authorbors <bors@rust-lang.org> 2026-02-17 02:03:25 UTC
committerbors <bors@rust-lang.org> 2026-02-17 02:03:25 UTC
logd1a11b670b617f1370f7b1cdf86e225a4e070f15
tree2d9a0550ec3dd99619266c5d77b1939a1efcbf8a
parent3c9faa0d037b9eecda4a440cc482ff7f960fb8a5
parentf7699054f750cf3815147e5a3b8a82bee18c537b

Auto merge of #152739 - Zalathar:rollup-8qaJ8F2, r=Zalathar

Rollup of 11 pull requests Successful merges: - rust-lang/rust#152700 (miri subtree update) - rust-lang/rust#152715 (`rust-analyzer` subtree update) - rust-lang/rust#151783 (Implement RFC 3678: Final trait methods) - rust-lang/rust#152512 (core: Implement feature `float_exact_integer_constants`) - rust-lang/rust#152661 (Avoid ICE in From/TryFrom diagnostic under -Znext-solver) - rust-lang/rust#152703 (Remove `rustc_query_system`) - rust-lang/rust#152206 (misc doc improvements) - rust-lang/rust#152664 (Fix mis-constructed `file_span` when generating scraped examples) - rust-lang/rust#152698 (Suppress unstable-trait notes under `-Zforce-unstable-if-unmarked`) - rust-lang/rust#152727 (`probe_op` silence ambiguity errors if tainted) - rust-lang/rust#152728 (Port #![default_lib_allocator] to the new attribute parser)

268 files changed, 3922 insertions(+), 1934 deletions(-)

Cargo.lock-19
......@@ -3640,7 +3640,6 @@ dependencies = [
36403640 "rustc_macros",
36413641 "rustc_metadata",
36423642 "rustc_middle",
3643 "rustc_query_system",
36443643 "rustc_sanitizers",
36453644 "rustc_session",
36463645 "rustc_span",
......@@ -4243,7 +4242,6 @@ dependencies = [
42434242 "rustc_index",
42444243 "rustc_lint_defs",
42454244 "rustc_macros",
4246 "rustc_query_system",
42474245 "rustc_serialize",
42484246 "rustc_session",
42494247 "rustc_span",
......@@ -4507,23 +4505,6 @@ dependencies = [
45074505 "tracing",
45084506]
45094507
4510[[package]]
4511name = "rustc_query_system"
4512version = "0.0.0"
4513dependencies = [
4514 "rustc_abi",
4515 "rustc_ast",
4516 "rustc_data_structures",
4517 "rustc_errors",
4518 "rustc_feature",
4519 "rustc_hir",
4520 "rustc_macros",
4521 "rustc_serialize",
4522 "rustc_session",
4523 "rustc_span",
4524 "smallvec",
4525]
4526
45274508[[package]]
45284509name = "rustc_resolve"
45294510version = "0.0.0"
compiler/rustc_ast/src/ast.rs+10-2
......@@ -3131,8 +3131,16 @@ pub enum Const {
31313131/// For details see the [RFC #2532](https://github.com/rust-lang/rfcs/pull/2532).
31323132#[derive(Copy, Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic, Walkable)]
31333133pub enum Defaultness {
3134 /// Item is unmarked. Implicitly determined based off of position.
3135 /// For impls, this is `final`; for traits, this is `default`.
3136 ///
3137 /// If you're expanding an item in a built-in macro or parsing an item
3138 /// by hand, you probably want to use this.
3139 Implicit,
3140 /// `default`
31343141 Default(Span),
3135 Final,
3142 /// `final`; per RFC 3678, only trait items may be *explicitly* marked final.
3143 Final(Span),
31363144}
31373145
31383146#[derive(Copy, Clone, PartialEq, Encodable, Decodable, HashStable_Generic, Walkable)]
......@@ -4140,7 +4148,7 @@ impl AssocItemKind {
41404148 | Self::Fn(box Fn { defaultness, .. })
41414149 | Self::Type(box TyAlias { defaultness, .. }) => defaultness,
41424150 Self::MacCall(..) | Self::Delegation(..) | Self::DelegationMac(..) => {
4143 Defaultness::Final
4151 Defaultness::Implicit
41444152 }
41454153 }
41464154 }
compiler/rustc_ast_lowering/src/item.rs+13-8
......@@ -939,7 +939,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
939939 );
940940 let trait_item_def_id = hir_id.expect_owner();
941941
942 let (ident, generics, kind, has_default) = match &i.kind {
942 let (ident, generics, kind, has_value) = match &i.kind {
943943 AssocItemKind::Const(box ConstItem {
944944 ident,
945945 generics,
......@@ -1088,13 +1088,17 @@ impl<'hir> LoweringContext<'_, 'hir> {
10881088 }
10891089 };
10901090
1091 let (defaultness, _) = self.lower_defaultness(i.kind.defaultness(), has_value, || {
1092 hir::Defaultness::Default { has_value }
1093 });
1094
10911095 let item = hir::TraitItem {
10921096 owner_id: trait_item_def_id,
10931097 ident: self.lower_ident(ident),
10941098 generics,
10951099 kind,
10961100 span: self.lower_span(i.span),
1097 defaultness: hir::Defaultness::Default { has_value: has_default },
1101 defaultness,
10981102 has_delayed_lints: !self.delayed_lints.is_empty(),
10991103 };
11001104 self.arena.alloc(item)
......@@ -1122,7 +1126,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
11221126 // `defaultness.has_value()` is never called for an `impl`, always `true` in order
11231127 // to not cause an assertion failure inside the `lower_defaultness` function.
11241128 let has_val = true;
1125 let (defaultness, defaultness_span) = self.lower_defaultness(defaultness, has_val);
1129 let (defaultness, defaultness_span) =
1130 self.lower_defaultness(defaultness, has_val, || hir::Defaultness::Final);
11261131 let modifiers = TraitBoundModifiers {
11271132 constness: BoundConstness::Never,
11281133 asyncness: BoundAsyncness::Normal,
......@@ -1151,7 +1156,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
11511156 ) -> &'hir hir::ImplItem<'hir> {
11521157 // Since `default impl` is not yet implemented, this is always true in impls.
11531158 let has_value = true;
1154 let (defaultness, _) = self.lower_defaultness(i.kind.defaultness(), has_value);
1159 let (defaultness, _) =
1160 self.lower_defaultness(i.kind.defaultness(), has_value, || hir::Defaultness::Final);
11551161 let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id);
11561162 let attrs = self.lower_attrs(
11571163 hir_id,
......@@ -1304,15 +1310,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
13041310 &self,
13051311 d: Defaultness,
13061312 has_value: bool,
1313 implicit: impl FnOnce() -> hir::Defaultness,
13071314 ) -> (hir::Defaultness, Option<Span>) {
13081315 match d {
1316 Defaultness::Implicit => (implicit(), None),
13091317 Defaultness::Default(sp) => {
13101318 (hir::Defaultness::Default { has_value }, Some(self.lower_span(sp)))
13111319 }
1312 Defaultness::Final => {
1313 assert!(has_value);
1314 (hir::Defaultness::Final, None)
1315 }
1320 Defaultness::Final(sp) => (hir::Defaultness::Final, Some(self.lower_span(sp))),
13161321 }
13171322 }
13181323
compiler/rustc_ast_passes/src/ast_validation.rs+66-12
......@@ -65,6 +65,28 @@ impl TraitOrImpl {
6565 }
6666}
6767
68enum AllowDefault {
69 Yes,
70 No,
71}
72
73impl AllowDefault {
74 fn when(b: bool) -> Self {
75 if b { Self::Yes } else { Self::No }
76 }
77}
78
79enum AllowFinal {
80 Yes,
81 No,
82}
83
84impl AllowFinal {
85 fn when(b: bool) -> Self {
86 if b { Self::Yes } else { Self::No }
87 }
88}
89
6890struct AstValidator<'a> {
6991 sess: &'a Session,
7092 features: &'a Features,
......@@ -563,10 +585,32 @@ impl<'a> AstValidator<'a> {
563585 }
564586 }
565587
566 fn check_defaultness(&self, span: Span, defaultness: Defaultness) {
567 if let Defaultness::Default(def_span) = defaultness {
568 let span = self.sess.source_map().guess_head_span(span);
569 self.dcx().emit_err(errors::ForbiddenDefault { span, def_span });
588 fn check_defaultness(
589 &self,
590 span: Span,
591 defaultness: Defaultness,
592 allow_default: AllowDefault,
593 allow_final: AllowFinal,
594 ) {
595 match defaultness {
596 Defaultness::Default(def_span) if matches!(allow_default, AllowDefault::No) => {
597 let span = self.sess.source_map().guess_head_span(span);
598 self.dcx().emit_err(errors::ForbiddenDefault { span, def_span });
599 }
600 Defaultness::Final(def_span) if matches!(allow_final, AllowFinal::No) => {
601 let span = self.sess.source_map().guess_head_span(span);
602 self.dcx().emit_err(errors::ForbiddenFinal { span, def_span });
603 }
604 _ => (),
605 }
606 }
607
608 fn check_final_has_body(&self, item: &Item<AssocItemKind>, defaultness: Defaultness) {
609 if let AssocItemKind::Fn(box Fn { body: None, .. }) = &item.kind
610 && let Defaultness::Final(def_span) = defaultness
611 {
612 let span = self.sess.source_map().guess_head_span(item.span);
613 self.dcx().emit_err(errors::ForbiddenFinalWithoutBody { span, def_span });
570614 }
571615 }
572616
......@@ -1190,7 +1234,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
11901234 },
11911235 ) => {
11921236 self.visit_attrs_vis_ident(&item.attrs, &item.vis, ident);
1193 self.check_defaultness(item.span, *defaultness);
1237 self.check_defaultness(item.span, *defaultness, AllowDefault::No, AllowFinal::No);
11941238
11951239 for EiiImpl { eii_macro_path, .. } in eii_impls {
11961240 self.visit_path(eii_macro_path);
......@@ -1360,7 +1404,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
13601404 });
13611405 }
13621406 ItemKind::Const(box ConstItem { defaultness, ident, rhs_kind, .. }) => {
1363 self.check_defaultness(item.span, *defaultness);
1407 self.check_defaultness(item.span, *defaultness, AllowDefault::No, AllowFinal::No);
13641408 if !rhs_kind.has_expr() {
13651409 self.dcx().emit_err(errors::ConstWithoutBody {
13661410 span: item.span,
......@@ -1398,7 +1442,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
13981442 ItemKind::TyAlias(
13991443 ty_alias @ box TyAlias { defaultness, bounds, after_where_clause, ty, .. },
14001444 ) => {
1401 self.check_defaultness(item.span, *defaultness);
1445 self.check_defaultness(item.span, *defaultness, AllowDefault::No, AllowFinal::No);
14021446 if ty.is_none() {
14031447 self.dcx().emit_err(errors::TyAliasWithoutBody {
14041448 span: item.span,
......@@ -1428,7 +1472,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
14281472 fn visit_foreign_item(&mut self, fi: &'a ForeignItem) {
14291473 match &fi.kind {
14301474 ForeignItemKind::Fn(box Fn { defaultness, ident, sig, body, .. }) => {
1431 self.check_defaultness(fi.span, *defaultness);
1475 self.check_defaultness(fi.span, *defaultness, AllowDefault::No, AllowFinal::No);
14321476 self.check_foreign_fn_bodyless(*ident, body.as_deref());
14331477 self.check_foreign_fn_headerless(sig.header);
14341478 self.check_foreign_item_ascii_only(*ident);
......@@ -1448,7 +1492,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
14481492 ty,
14491493 ..
14501494 }) => {
1451 self.check_defaultness(fi.span, *defaultness);
1495 self.check_defaultness(fi.span, *defaultness, AllowDefault::No, AllowFinal::No);
14521496 self.check_foreign_kind_bodyless(*ident, "type", ty.as_ref().map(|b| b.span));
14531497 self.check_type_no_bounds(bounds, "`extern` blocks");
14541498 self.check_foreign_ty_genericless(generics, after_where_clause);
......@@ -1707,9 +1751,19 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
17071751 self.check_nomangle_item_asciionly(ident, item.span);
17081752 }
17091753
1710 if ctxt == AssocCtxt::Trait || self.outer_trait_or_trait_impl.is_none() {
1711 self.check_defaultness(item.span, item.kind.defaultness());
1712 }
1754 let defaultness = item.kind.defaultness();
1755 self.check_defaultness(
1756 item.span,
1757 defaultness,
1758 // `default` is allowed on all associated items in impls.
1759 AllowDefault::when(matches!(ctxt, AssocCtxt::Impl { .. })),
1760 // `final` is allowed on all associated *functions* in traits.
1761 AllowFinal::when(
1762 ctxt == AssocCtxt::Trait && matches!(item.kind, AssocItemKind::Fn(..)),
1763 ),
1764 );
1765
1766 self.check_final_has_body(item, defaultness);
17131767
17141768 if let AssocCtxt::Impl { .. } = ctxt {
17151769 match &item.kind {
compiler/rustc_ast_passes/src/errors.rs+18
......@@ -159,6 +159,24 @@ pub(crate) struct ForbiddenDefault {
159159 pub def_span: Span,
160160}
161161
162#[derive(Diagnostic)]
163#[diag("`final` is only allowed on associated functions in traits")]
164pub(crate) struct ForbiddenFinal {
165 #[primary_span]
166 pub span: Span,
167 #[label("`final` because of this")]
168 pub def_span: Span,
169}
170
171#[derive(Diagnostic)]
172#[diag("`final` is only allowed on associated functions if they have a body")]
173pub(crate) struct ForbiddenFinalWithoutBody {
174 #[primary_span]
175 pub span: Span,
176 #[label("`final` because of this")]
177 pub def_span: Span,
178}
179
162180#[derive(Diagnostic)]
163181#[diag("associated constant in `impl` without body")]
164182pub(crate) struct AssocConstWithoutBody {
compiler/rustc_ast_passes/src/feature_gate.rs+1
......@@ -580,6 +580,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
580580 gate_all!(frontmatter, "frontmatters are experimental");
581581 gate_all!(coroutines, "coroutine syntax is experimental");
582582 gate_all!(const_block_items, "const block items are experimental");
583 gate_all!(final_associated_functions, "`final` on trait functions is experimental");
583584
584585 if !visitor.features.never_patterns() {
585586 if let Some(spans) = spans.get(&sym::never_patterns) {
compiler/rustc_ast_pretty/src/pprust/state/item.rs+2-2
......@@ -51,7 +51,7 @@ impl<'a> State<'a> {
5151 expr.as_deref(),
5252 vis,
5353 *safety,
54 ast::Defaultness::Final,
54 ast::Defaultness::Implicit,
5555 define_opaque.as_deref(),
5656 ),
5757 ast::ForeignItemKind::TyAlias(box ast::TyAlias {
......@@ -201,7 +201,7 @@ impl<'a> State<'a> {
201201 body.as_deref(),
202202 &item.vis,
203203 ast::Safety::Default,
204 ast::Defaultness::Final,
204 ast::Defaultness::Implicit,
205205 define_opaque.as_deref(),
206206 );
207207 }
compiler/rustc_attr_parsing/src/attributes/crate_level.rs+9
......@@ -292,3 +292,12 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcNoImplicitBoundsParser {
292292 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
293293 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcNoImplicitBounds;
294294}
295
296pub(crate) struct DefaultLibAllocatorParser;
297
298impl<S: Stage> NoArgsAttributeParser<S> for DefaultLibAllocatorParser {
299 const PATH: &[Symbol] = &[sym::default_lib_allocator];
300 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
301 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
302 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::DefaultLibAllocator;
303}
compiler/rustc_attr_parsing/src/context.rs+1
......@@ -235,6 +235,7 @@ attribute_parsers!(
235235 Single<WithoutArgs<ConstContinueParser>>,
236236 Single<WithoutArgs<ConstStabilityIndirectParser>>,
237237 Single<WithoutArgs<CoroutineParser>>,
238 Single<WithoutArgs<DefaultLibAllocatorParser>>,
238239 Single<WithoutArgs<DenyExplicitImplParser>>,
239240 Single<WithoutArgs<DynIncompatibleTraitParser>>,
240241 Single<WithoutArgs<EiiForeignItemParser>>,
compiler/rustc_builtin_macros/src/alloc_error_handler.rs+1-1
......@@ -83,7 +83,7 @@ fn generate_handler(cx: &ExtCtxt<'_>, handler: Ident, span: Span, sig_span: Span
8383
8484 let body = Some(cx.block_expr(call));
8585 let kind = ItemKind::Fn(Box::new(Fn {
86 defaultness: ast::Defaultness::Final,
86 defaultness: ast::Defaultness::Implicit,
8787 sig,
8888 ident: Ident::from_str_and_span(&global_fn_name(ALLOC_ERROR_HANDLER), span),
8989 generics: Generics::default(),
compiler/rustc_builtin_macros/src/autodiff.rs+1-1
......@@ -334,7 +334,7 @@ mod llvm_enzyme {
334334
335335 // The first element of it is the name of the function to be generated
336336 let d_fn = Box::new(ast::Fn {
337 defaultness: ast::Defaultness::Final,
337 defaultness: ast::Defaultness::Implicit,
338338 sig: d_sig,
339339 ident: first_ident(&meta_item_vec[0]),
340340 generics,
compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs+2-2
......@@ -136,7 +136,7 @@ pub(crate) fn expand_deriving_coerce_pointee(
136136 of_trait: Some(Box::new(ast::TraitImplHeader {
137137 safety: ast::Safety::Default,
138138 polarity: ast::ImplPolarity::Positive,
139 defaultness: ast::Defaultness::Final,
139 defaultness: ast::Defaultness::Implicit,
140140 trait_ref,
141141 })),
142142 constness: ast::Const::No,
......@@ -159,7 +159,7 @@ pub(crate) fn expand_deriving_coerce_pointee(
159159 of_trait: Some(Box::new(ast::TraitImplHeader {
160160 safety: ast::Safety::Default,
161161 polarity: ast::ImplPolarity::Positive,
162 defaultness: ast::Defaultness::Final,
162 defaultness: ast::Defaultness::Implicit,
163163 trait_ref,
164164 })),
165165 constness: ast::Const::No,
compiler/rustc_builtin_macros/src/deriving/generic/mod.rs+3-3
......@@ -614,7 +614,7 @@ impl<'a> TraitDef<'a> {
614614 },
615615 attrs: ast::AttrVec::new(),
616616 kind: ast::AssocItemKind::Type(Box::new(ast::TyAlias {
617 defaultness: ast::Defaultness::Final,
617 defaultness: ast::Defaultness::Implicit,
618618 ident,
619619 generics: Generics::default(),
620620 after_where_clause: ast::WhereClause::default(),
......@@ -851,7 +851,7 @@ impl<'a> TraitDef<'a> {
851851 of_trait: Some(Box::new(ast::TraitImplHeader {
852852 safety: self.safety,
853853 polarity: ast::ImplPolarity::Positive,
854 defaultness: ast::Defaultness::Final,
854 defaultness: ast::Defaultness::Implicit,
855855 trait_ref,
856856 })),
857857 constness: if self.is_const { ast::Const::Yes(DUMMY_SP) } else { ast::Const::No },
......@@ -1073,7 +1073,7 @@ impl<'a> MethodDef<'a> {
10731073 let trait_lo_sp = span.shrink_to_lo();
10741074
10751075 let sig = ast::FnSig { header: ast::FnHeader::default(), decl: fn_decl, span };
1076 let defaultness = ast::Defaultness::Final;
1076 let defaultness = ast::Defaultness::Implicit;
10771077
10781078 // Create the method.
10791079 Box::new(ast::AssocItem {
compiler/rustc_builtin_macros/src/global_allocator.rs+1-1
......@@ -77,7 +77,7 @@ impl AllocFnFactory<'_, '_> {
7777 let sig = FnSig { decl, header, span: self.span };
7878 let body = Some(self.cx.block_expr(result));
7979 let kind = ItemKind::Fn(Box::new(Fn {
80 defaultness: ast::Defaultness::Final,
80 defaultness: ast::Defaultness::Implicit,
8181 sig,
8282 ident: Ident::from_str_and_span(&global_fn_name(method.name), self.span),
8383 generics: Generics::default(),
compiler/rustc_builtin_macros/src/test.rs+1-1
......@@ -283,7 +283,7 @@ pub(crate) fn expand_test_or_bench(
283283 // const $ident: test::TestDescAndFn =
284284 ast::ItemKind::Const(
285285 ast::ConstItem {
286 defaultness: ast::Defaultness::Final,
286 defaultness: ast::Defaultness::Implicit,
287287 ident: Ident::new(fn_.ident.name, sp),
288288 generics: ast::Generics::default(),
289289 ty: cx.ty(sp, ast::TyKind::Path(None, test_path("TestDescAndFn"))),
compiler/rustc_builtin_macros/src/test_harness.rs+1-1
......@@ -330,7 +330,7 @@ fn mk_main(cx: &mut TestCtxt<'_>) -> Box<ast::Item> {
330330
331331 let decl = ecx.fn_decl(ThinVec::new(), ast::FnRetTy::Ty(main_ret_ty));
332332 let sig = ast::FnSig { decl, header: ast::FnHeader::default(), span: sp };
333 let defaultness = ast::Defaultness::Final;
333 let defaultness = ast::Defaultness::Implicit;
334334
335335 // Honor the reexport_test_harness_main attribute
336336 let main_ident = match cx.reexport_test_harness_main {
compiler/rustc_codegen_cranelift/src/codegen_f16_f128.rs+1-1
......@@ -208,7 +208,7 @@ pub(crate) fn codegen_cast(
208208 let ret_ty = if to_ty.bits() < 32 { types::I32 } else { to_ty };
209209 let name = format!(
210210 "__fix{sign}tf{size}i",
211 sign = if from_signed { "" } else { "un" },
211 sign = if to_signed { "" } else { "uns" },
212212 size = match ret_ty {
213213 types::I32 => 's',
214214 types::I64 => 'd',
compiler/rustc_codegen_llvm/Cargo.toml-1
......@@ -31,7 +31,6 @@ rustc_llvm = { path = "../rustc_llvm" }
3131rustc_macros = { path = "../rustc_macros" }
3232rustc_metadata = { path = "../rustc_metadata" }
3333rustc_middle = { path = "../rustc_middle" }
34rustc_query_system = { path = "../rustc_query_system" }
3534rustc_sanitizers = { path = "../rustc_sanitizers" }
3635rustc_session = { path = "../rustc_session" }
3736rustc_span = { path = "../rustc_span" }
compiler/rustc_error_codes/src/error_codes/E0570.md+2-2
......@@ -1,7 +1,7 @@
11The requested ABI is unsupported by the current target.
22
3The rust compiler maintains for each target a list of unsupported ABIs on
4that target. If an ABI is present in such a list this usually means that the
3The Rust compiler maintains a list of unsupported ABIs for each target.
4If an ABI is present in such a list, this usually means that the
55target / ABI combination is currently unsupported by llvm.
66
77If necessary, you can circumvent this check using custom target specifications.
compiler/rustc_expand/src/build.rs+1-1
......@@ -729,7 +729,7 @@ impl<'a> ExtCtxt<'a> {
729729 ty: Box<ast::Ty>,
730730 rhs_kind: ast::ConstItemRhsKind,
731731 ) -> Box<ast::Item> {
732 let defaultness = ast::Defaultness::Final;
732 let defaultness = ast::Defaultness::Implicit;
733733 self.item(
734734 span,
735735 AttrVec::new(),
compiler/rustc_expand/src/config.rs+2-3
......@@ -86,8 +86,7 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute], crate_name: Symbol) -
8686 if let Some(f) = REMOVED_LANG_FEATURES.iter().find(|f| name == f.feature.name) {
8787 let pull_note = if let Some(pull) = f.pull {
8888 format!(
89 "; see <https://github.com/rust-lang/rust/pull/{}> for more information",
90 pull
89 "; see <https://github.com/rust-lang/rust/pull/{pull}> for more information",
9190 )
9291 } else {
9392 "".to_owned()
......@@ -123,7 +122,7 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute], crate_name: Symbol) -
123122
124123 // If the enabled feature is unstable, record it.
125124 if UNSTABLE_LANG_FEATURES.iter().find(|f| name == f.name).is_some() {
126 // When the ICE comes a standard library crate, there's a chance that the person
125 // When the ICE comes from a standard library crate, there's a chance that the person
127126 // hitting the ICE may be using -Zbuild-std or similar with an untested target.
128127 // The bug is probably in the standard library and not the compiler in that case,
129128 // but that doesn't really matter - we want a bug report.
compiler/rustc_feature/src/unstable.rs+5-4
......@@ -64,8 +64,6 @@ pub struct EnabledLibFeature {
6464}
6565
6666impl Features {
67 /// `since` should be set for stable features that are nevertheless enabled with a `#[feature]`
68 /// attribute, indicating since when they are stable.
6967 pub fn set_enabled_lang_feature(&mut self, lang_feat: EnabledLangFeature) {
7068 self.enabled_lang_features.push(lang_feat);
7169 self.enabled_features.insert(lang_feat.gate_name);
......@@ -494,6 +492,8 @@ declare_features! (
494492 (unstable, ffi_const, "1.45.0", Some(58328)),
495493 /// Allows the use of `#[ffi_pure]` on foreign functions.
496494 (unstable, ffi_pure, "1.45.0", Some(58329)),
495 /// Allows marking trait functions as `final` to prevent overriding impls
496 (unstable, final_associated_functions, "CURRENT_RUSTC_VERSION", Some(1)),
497497 /// Controlling the behavior of fmt::Debug
498498 (unstable, fmt_debug, "1.82.0", Some(129709)),
499499 /// Allows using `#[align(...)]` on function items
......@@ -779,8 +779,9 @@ impl Features {
779779 }
780780}
781781
782/// Some features are not allowed to be used together at the same time, if
783/// the two are present, produce an error.
782/// Some features are not allowed to be used together at the same time.
783///
784/// If the two are present, produce an error.
784785pub const INCOMPATIBLE_FEATURES: &[(Symbol, Symbol)] = &[
785786 // Experimental match ergonomics rulesets are incompatible with each other, to simplify the
786787 // boolean logic required to tell which typing rules to use.
compiler/rustc_hir/src/attrs/data_structures.rs+3
......@@ -897,6 +897,9 @@ pub enum AttributeKind {
897897 /// Represents `#[debugger_visualizer]`.
898898 DebuggerVisualizer(ThinVec<DebugVisualizer>),
899899
900 /// Represents `#![default_lib_allocator]`
901 DefaultLibAllocator,
902
900903 /// Represents [`#[deprecated]`](https://doc.rust-lang.org/stable/reference/attributes/diagnostics.html#the-deprecated-attribute).
901904 Deprecation { deprecation: Deprecation, span: Span },
902905
compiler/rustc_hir/src/attrs/encode_cross_crate.rs+1
......@@ -35,6 +35,7 @@ impl AttributeKind {
3535 CrateType(_) => No,
3636 CustomMir(_, _, _) => Yes,
3737 DebuggerVisualizer(..) => No,
38 DefaultLibAllocator => No,
3839 Deprecation { .. } => Yes,
3940 DoNotRecommend { .. } => Yes,
4041 Doc(_) => Yes,
compiler/rustc_hir_analysis/src/check/check.rs+25-1
......@@ -1175,13 +1175,35 @@ pub(super) fn check_specialization_validity<'tcx>(
11751175
11761176 if let Err(parent_impl) = result {
11771177 if !tcx.is_impl_trait_in_trait(impl_item) {
1178 report_forbidden_specialization(tcx, impl_item, parent_impl);
1178 let span = tcx.def_span(impl_item);
1179 let ident = tcx.item_ident(impl_item);
1180
1181 let err = match tcx.span_of_impl(parent_impl) {
1182 Ok(sp) => errors::ImplNotMarkedDefault::Ok { span, ident, ok_label: sp },
1183 Err(cname) => errors::ImplNotMarkedDefault::Err { span, ident, cname },
1184 };
1185
1186 tcx.dcx().emit_err(err);
11791187 } else {
11801188 tcx.dcx().delayed_bug(format!("parent item: {parent_impl:?} not marked as default"));
11811189 }
11821190 }
11831191}
11841192
1193fn check_overriding_final_trait_item<'tcx>(
1194 tcx: TyCtxt<'tcx>,
1195 trait_item: ty::AssocItem,
1196 impl_item: ty::AssocItem,
1197) {
1198 if trait_item.defaultness(tcx).is_final() {
1199 tcx.dcx().emit_err(errors::OverridingFinalTraitFunction {
1200 impl_span: tcx.def_span(impl_item.def_id),
1201 trait_span: tcx.def_span(trait_item.def_id),
1202 ident: tcx.item_ident(impl_item.def_id),
1203 });
1204 }
1205}
1206
11851207fn check_impl_items_against_trait<'tcx>(
11861208 tcx: TyCtxt<'tcx>,
11871209 impl_id: LocalDefId,
......@@ -1259,6 +1281,8 @@ fn check_impl_items_against_trait<'tcx>(
12591281 impl_id.to_def_id(),
12601282 impl_item,
12611283 );
1284
1285 check_overriding_final_trait_item(tcx, ty_trait_item, ty_impl_item);
12621286 }
12631287
12641288 if let Ok(ancestors) = trait_def.ancestors(tcx, impl_id.to_def_id()) {
compiler/rustc_hir_analysis/src/check/mod.rs-12
......@@ -197,18 +197,6 @@ pub(super) fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: LocalDef
197197 }
198198}
199199
200fn report_forbidden_specialization(tcx: TyCtxt<'_>, impl_item: DefId, parent_impl: DefId) {
201 let span = tcx.def_span(impl_item);
202 let ident = tcx.item_ident(impl_item);
203
204 let err = match tcx.span_of_impl(parent_impl) {
205 Ok(sp) => errors::ImplNotMarkedDefault::Ok { span, ident, ok_label: sp },
206 Err(cname) => errors::ImplNotMarkedDefault::Err { span, ident, cname },
207 };
208
209 tcx.dcx().emit_err(err);
210}
211
212200fn missing_items_err(
213201 tcx: TyCtxt<'_>,
214202 impl_def_id: LocalDefId,
compiler/rustc_hir_analysis/src/errors.rs+10
......@@ -892,6 +892,16 @@ pub(crate) enum ImplNotMarkedDefault {
892892#[diag("this item cannot be used as its where bounds are not satisfied for the `Self` type")]
893893pub(crate) struct UselessImplItem;
894894
895#[derive(Diagnostic)]
896#[diag("cannot override `{$ident}` because it already has a `final` definition in the trait")]
897pub(crate) struct OverridingFinalTraitFunction {
898 #[primary_span]
899 pub impl_span: Span,
900 #[note("`{$ident}` is marked final here")]
901 pub trait_span: Span,
902 pub ident: Ident,
903}
904
895905#[derive(Diagnostic)]
896906#[diag("not all trait items implemented, missing: `{$missing_items_msg}`", code = E0046)]
897907pub(crate) struct MissingTraitItem {
compiler/rustc_hir_typeck/src/method/probe.rs+1
......@@ -490,6 +490,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
490490 .unwrap_or_else(|_| span_bug!(span, "instantiating {:?} failed?", ty));
491491 let ty = self.resolve_vars_if_possible(ty.value);
492492 let guar = match *ty.kind() {
493 _ if let Some(guar) = self.tainted_by_errors() => guar,
493494 ty::Infer(ty::TyVar(_)) => {
494495 // We want to get the variable name that the method
495496 // is being called on. If it is a method call.
compiler/rustc_interface/src/callbacks.rs+3-43
......@@ -11,9 +11,8 @@
1111
1212use std::fmt;
1313
14use rustc_errors::{DiagInner, TRACK_DIAGNOSTIC};
15use rustc_middle::dep_graph::dep_node::default_dep_kind_debug;
16use rustc_middle::dep_graph::{DepKind, DepNode, TaskDepsRef};
14use rustc_errors::DiagInner;
15use rustc_middle::dep_graph::TaskDepsRef;
1716use rustc_middle::ty::tls;
1817
1918fn track_span_parent(def_id: rustc_span::def_id::LocalDefId) {
......@@ -65,49 +64,10 @@ fn def_id_debug(def_id: rustc_hir::def_id::DefId, f: &mut fmt::Formatter<'_>) ->
6564 write!(f, ")")
6665}
6766
68/// This is a callback from `rustc_query_system` as it cannot access the implicit state
69/// in `rustc_middle` otherwise.
70pub fn dep_kind_debug(kind: DepKind, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
71 tls::with_opt(|opt_tcx| {
72 if let Some(tcx) = opt_tcx {
73 write!(f, "{}", tcx.dep_kind_vtable(kind).name)
74 } else {
75 default_dep_kind_debug(kind, f)
76 }
77 })
78}
79
80/// This is a callback from `rustc_query_system` as it cannot access the implicit state
81/// in `rustc_middle` otherwise.
82pub fn dep_node_debug(node: DepNode, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
83 write!(f, "{:?}(", node.kind)?;
84
85 tls::with_opt(|opt_tcx| {
86 if let Some(tcx) = opt_tcx {
87 if let Some(def_id) = node.extract_def_id(tcx) {
88 write!(f, "{}", tcx.def_path_debug_str(def_id))?;
89 } else if let Some(ref s) = tcx.dep_graph.dep_node_debug_str(node) {
90 write!(f, "{s}")?;
91 } else {
92 write!(f, "{}", node.hash)?;
93 }
94 } else {
95 write!(f, "{}", node.hash)?;
96 }
97 Ok(())
98 })?;
99
100 write!(f, ")")
101}
102
10367/// Sets up the callbacks in prior crates which we want to refer to the
10468/// TyCtxt in.
10569pub fn setup_callbacks() {
10670 rustc_span::SPAN_TRACK.swap(&(track_span_parent as fn(_)));
10771 rustc_hir::def_id::DEF_ID_DEBUG.swap(&(def_id_debug as fn(_, &mut fmt::Formatter<'_>) -> _));
108 rustc_middle::dep_graph::dep_node::DEP_KIND_DEBUG
109 .swap(&(dep_kind_debug as fn(_, &mut fmt::Formatter<'_>) -> _));
110 rustc_middle::dep_graph::dep_node::DEP_NODE_DEBUG
111 .swap(&(dep_node_debug as fn(_, &mut fmt::Formatter<'_>) -> _));
112 TRACK_DIAGNOSTIC.swap(&(track_diagnostic as _));
72 rustc_errors::TRACK_DIAGNOSTIC.swap(&(track_diagnostic as _));
11373}
compiler/rustc_lint_defs/src/builtin.rs+3-3
......@@ -3659,10 +3659,10 @@ declare_lint! {
36593659 /// `stdcall`, `fastcall`, and `cdecl` calling conventions (or their unwind
36603660 /// variants) on targets that cannot meaningfully be supported for the requested target.
36613661 ///
3662 /// For example `stdcall` does not make much sense for a x86_64 or, more apparently, powerpc
3662 /// For example, `stdcall` does not make much sense for a x86_64 or, more apparently, powerpc
36633663 /// code, because this calling convention was never specified for those targets.
36643664 ///
3665 /// Historically MSVC toolchains have fallen back to the regular C calling convention for
3665 /// Historically, MSVC toolchains have fallen back to the regular C calling convention for
36663666 /// targets other than x86, but Rust doesn't really see a similar need to introduce a similar
36673667 /// hack across many more targets.
36683668 ///
......@@ -3689,7 +3689,7 @@ declare_lint! {
36893689 ///
36903690 /// ### Explanation
36913691 ///
3692 /// On most of the targets the behaviour of `stdcall` and similar calling conventions is not
3692 /// On most of the targets, the behaviour of `stdcall` and similar calling conventions is not
36933693 /// defined at all, but was previously accepted due to a bug in the implementation of the
36943694 /// compiler.
36953695 pub UNSUPPORTED_CALLING_CONVENTIONS,
compiler/rustc_macros/src/hash_stable.rs+1-1
......@@ -96,7 +96,7 @@ fn hash_stable_derive_with_mode(
9696
9797 let context: syn::Type = match mode {
9898 HashStableMode::Normal => {
99 parse_quote!(::rustc_query_system::ich::StableHashingContext<'__ctx>)
99 parse_quote!(::rustc_middle::ich::StableHashingContext<'__ctx>)
100100 }
101101 HashStableMode::Generic | HashStableMode::NoContext => parse_quote!(__CTX),
102102 };
compiler/rustc_metadata/src/rmeta/encoder.rs+1-4
......@@ -734,10 +734,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
734734 has_global_allocator: tcx.has_global_allocator(LOCAL_CRATE),
735735 has_alloc_error_handler: tcx.has_alloc_error_handler(LOCAL_CRATE),
736736 has_panic_handler: tcx.has_panic_handler(LOCAL_CRATE),
737 has_default_lib_allocator: ast::attr::contains_name(
738 attrs,
739 sym::default_lib_allocator,
740 ),
737 has_default_lib_allocator: find_attr!(attrs, AttributeKind::DefaultLibAllocator),
741738 externally_implementable_items,
742739 proc_macro_data,
743740 debugger_visualizers,
compiler/rustc_middle/Cargo.toml-1
......@@ -26,7 +26,6 @@ rustc_hir_pretty = { path = "../rustc_hir_pretty" }
2626rustc_index = { path = "../rustc_index" }
2727rustc_lint_defs = { path = "../rustc_lint_defs" }
2828rustc_macros = { path = "../rustc_macros" }
29rustc_query_system = { path = "../rustc_query_system" }
3029rustc_serialize = { path = "../rustc_serialize" }
3130rustc_session = { path = "../rustc_session" }
3231rustc_span = { path = "../rustc_span" }
compiler/rustc_middle/src/dep_graph/dep_node.rs+27-19
......@@ -58,18 +58,17 @@
5858use std::fmt;
5959use std::hash::Hash;
6060
61use rustc_data_structures::AtomicRef;
6261use rustc_data_structures::fingerprint::{Fingerprint, PackedFingerprint};
6362use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableOrd, ToStableHashKey};
6463use rustc_hir::def_id::DefId;
6564use rustc_hir::definitions::DefPathHash;
6665use rustc_macros::{Decodable, Encodable};
67use rustc_query_system::ich::StableHashingContext;
6866use rustc_span::Symbol;
6967
7068use super::{FingerprintStyle, SerializedDepNodeIndex};
69use crate::ich::StableHashingContext;
7170use crate::mir::mono::MonoItem;
72use crate::ty::TyCtxt;
71use crate::ty::{TyCtxt, tls};
7372
7473/// This serves as an index into arrays built by `make_dep_kind_array`.
7574#[derive(Clone, Copy, PartialEq, Eq, Hash)]
......@@ -114,16 +113,15 @@ impl DepKind {
114113 pub(crate) const MAX: u16 = DEP_KIND_VARIANTS - 1;
115114}
116115
117pub fn default_dep_kind_debug(kind: DepKind, f: &mut fmt::Formatter<'_>) -> fmt::Result {
118 f.debug_struct("DepKind").field("variant", &kind.variant).finish()
119}
120
121pub static DEP_KIND_DEBUG: AtomicRef<fn(DepKind, &mut fmt::Formatter<'_>) -> fmt::Result> =
122 AtomicRef::new(&(default_dep_kind_debug as fn(_, &mut fmt::Formatter<'_>) -> _));
123
124116impl fmt::Debug for DepKind {
125117 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
126 (*DEP_KIND_DEBUG)(*self, f)
118 tls::with_opt(|opt_tcx| {
119 if let Some(tcx) = opt_tcx {
120 write!(f, "{}", tcx.dep_kind_vtable(*self).name)
121 } else {
122 f.debug_struct("DepKind").field("variant", &self.variant).finish()
123 }
124 })
127125 }
128126}
129127
......@@ -175,16 +173,26 @@ impl DepNode {
175173 }
176174}
177175
178pub fn default_dep_node_debug(node: DepNode, f: &mut fmt::Formatter<'_>) -> fmt::Result {
179 f.debug_struct("DepNode").field("kind", &node.kind).field("hash", &node.hash).finish()
180}
181
182pub static DEP_NODE_DEBUG: AtomicRef<fn(DepNode, &mut fmt::Formatter<'_>) -> fmt::Result> =
183 AtomicRef::new(&(default_dep_node_debug as fn(_, &mut fmt::Formatter<'_>) -> _));
184
185176impl fmt::Debug for DepNode {
186177 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
187 (*DEP_NODE_DEBUG)(*self, f)
178 write!(f, "{:?}(", self.kind)?;
179
180 tls::with_opt(|opt_tcx| {
181 if let Some(tcx) = opt_tcx {
182 if let Some(def_id) = self.extract_def_id(tcx) {
183 write!(f, "{}", tcx.def_path_debug_str(def_id))?;
184 } else if let Some(ref s) = tcx.dep_graph.dep_node_debug_str(*self) {
185 write!(f, "{s}")?;
186 } else {
187 write!(f, "{}", self.hash)?;
188 }
189 } else {
190 write!(f, "{}", self.hash)?;
191 }
192 Ok(())
193 })?;
194
195 write!(f, ")")
188196 }
189197}
190198
compiler/rustc_middle/src/dep_graph/graph.rs+18-2
......@@ -15,8 +15,6 @@ use rustc_data_structures::{assert_matches, outline};
1515use rustc_errors::DiagInner;
1616use rustc_index::IndexVec;
1717use rustc_macros::{Decodable, Encodable};
18use rustc_query_system::ich::StableHashingContext;
19use rustc_query_system::query::QuerySideEffect;
2018use rustc_serialize::opaque::{FileEncodeResult, FileEncoder};
2119use rustc_session::Session;
2220use tracing::{debug, instrument};
......@@ -27,9 +25,27 @@ use super::query::DepGraphQuery;
2725use super::serialized::{GraphEncoder, SerializedDepGraph, SerializedDepNodeIndex};
2826use super::{DepKind, DepNode, HasDepContext, WorkProductId, read_deps, with_deps};
2927use crate::dep_graph::edges::EdgesVec;
28use crate::ich::StableHashingContext;
3029use crate::ty::TyCtxt;
3130use crate::verify_ich::incremental_verify_ich;
3231
32/// Tracks 'side effects' for a particular query.
33/// This struct is saved to disk along with the query result,
34/// and loaded from disk if we mark the query as green.
35/// This allows us to 'replay' changes to global state
36/// that would otherwise only occur if we actually
37/// executed the query method.
38///
39/// Each side effect gets an unique dep node index which is added
40/// as a dependency of the query which had the effect.
41#[derive(Debug, Encodable, Decodable)]
42pub enum QuerySideEffect {
43 /// Stores a diagnostic emitted during query execution.
44 /// This diagnostic will be re-emitted if we mark
45 /// the query as green, as that query will have the side
46 /// effect dep node as a dependency.
47 Diagnostic(DiagInner),
48}
3349#[derive(Clone)]
3450pub struct DepGraph {
3551 data: Option<Arc<DepGraphData>>,
compiler/rustc_middle/src/dep_graph/mod.rs+2-1
......@@ -7,7 +7,8 @@ pub use self::dep_node::{
77 label_strs,
88};
99pub use self::graph::{
10 DepGraph, DepGraphData, DepNodeIndex, TaskDepsRef, WorkProduct, WorkProductMap, hash_result,
10 DepGraph, DepGraphData, DepNodeIndex, QuerySideEffect, TaskDepsRef, WorkProduct,
11 WorkProductMap, hash_result,
1112};
1213use self::graph::{MarkFrame, print_markframe_trace};
1314pub use self::query::DepGraphQuery;
compiler/rustc_middle/src/ich/hcx.rs created+196
......@@ -0,0 +1,196 @@
1use std::hash::Hash;
2
3use rustc_data_structures::stable_hasher::{HashStable, HashingControls, StableHasher};
4use rustc_hir::def_id::{DefId, LocalDefId};
5use rustc_hir::definitions::DefPathHash;
6use rustc_session::Session;
7use rustc_session::cstore::Untracked;
8use rustc_span::source_map::SourceMap;
9use rustc_span::{CachingSourceMapView, DUMMY_SP, Pos, Span};
10
11// Very often, we are hashing something that does not need the `CachingSourceMapView`, so we
12// initialize it lazily.
13#[derive(Clone)]
14enum CachingSourceMap<'a> {
15 Unused(&'a SourceMap),
16 InUse(CachingSourceMapView<'a>),
17}
18
19/// This is the context state available during incr. comp. hashing. It contains
20/// enough information to transform `DefId`s and `HirId`s into stable `DefPath`s (i.e.,
21/// a reference to the `TyCtxt`) and it holds a few caches for speeding up various
22/// things (e.g., each `DefId`/`DefPath` is only hashed once).
23#[derive(Clone)]
24pub struct StableHashingContext<'a> {
25 untracked: &'a Untracked,
26 // The value of `-Z incremental-ignore-spans`.
27 // This field should only be used by `unstable_opts_incremental_ignore_span`
28 incremental_ignore_spans: bool,
29 caching_source_map: CachingSourceMap<'a>,
30 hashing_controls: HashingControls,
31}
32
33impl<'a> StableHashingContext<'a> {
34 #[inline]
35 pub fn new(sess: &'a Session, untracked: &'a Untracked) -> Self {
36 let hash_spans_initial = !sess.opts.unstable_opts.incremental_ignore_spans;
37
38 StableHashingContext {
39 untracked,
40 incremental_ignore_spans: sess.opts.unstable_opts.incremental_ignore_spans,
41 caching_source_map: CachingSourceMap::Unused(sess.source_map()),
42 hashing_controls: HashingControls { hash_spans: hash_spans_initial },
43 }
44 }
45
46 #[inline]
47 pub fn while_hashing_spans<F: FnOnce(&mut Self)>(&mut self, hash_spans: bool, f: F) {
48 let prev_hash_spans = self.hashing_controls.hash_spans;
49 self.hashing_controls.hash_spans = hash_spans;
50 f(self);
51 self.hashing_controls.hash_spans = prev_hash_spans;
52 }
53
54 #[inline]
55 fn source_map(&mut self) -> &mut CachingSourceMapView<'a> {
56 match self.caching_source_map {
57 CachingSourceMap::InUse(ref mut sm) => sm,
58 CachingSourceMap::Unused(sm) => {
59 self.caching_source_map = CachingSourceMap::InUse(CachingSourceMapView::new(sm));
60 self.source_map() // this recursive call will hit the `InUse` case
61 }
62 }
63 }
64
65 #[inline]
66 fn def_span(&self, def_id: LocalDefId) -> Span {
67 self.untracked.source_span.get(def_id).unwrap_or(DUMMY_SP)
68 }
69
70 #[inline]
71 pub fn hashing_controls(&self) -> HashingControls {
72 self.hashing_controls
73 }
74}
75
76impl<'a> rustc_span::HashStableContext for StableHashingContext<'a> {
77 /// Hashes a span in a stable way. We can't directly hash the span's `BytePos` fields (that
78 /// would be similar to hashing pointers, since those are just offsets into the `SourceMap`).
79 /// Instead, we hash the (file name, line, column) triple, which stays the same even if the
80 /// containing `SourceFile` has moved within the `SourceMap`.
81 ///
82 /// Also note that we are hashing byte offsets for the column, not unicode codepoint offsets.
83 /// For the purpose of the hash that's sufficient. Also, hashing filenames is expensive so we
84 /// avoid doing it twice when the span starts and ends in the same file, which is almost always
85 /// the case.
86 ///
87 /// IMPORTANT: changes to this method should be reflected in implementations of `SpanEncoder`.
88 #[inline]
89 fn span_hash_stable(&mut self, span: Span, hasher: &mut StableHasher) {
90 const TAG_VALID_SPAN: u8 = 0;
91 const TAG_INVALID_SPAN: u8 = 1;
92 const TAG_RELATIVE_SPAN: u8 = 2;
93
94 if !self.hashing_controls().hash_spans {
95 return;
96 }
97
98 let span = span.data_untracked();
99 span.ctxt.hash_stable(self, hasher);
100 span.parent.hash_stable(self, hasher);
101
102 if span.is_dummy() {
103 Hash::hash(&TAG_INVALID_SPAN, hasher);
104 return;
105 }
106
107 let parent = span.parent.map(|parent| self.def_span(parent).data_untracked());
108 if let Some(parent) = parent
109 && parent.contains(span)
110 {
111 // This span is enclosed in a definition: only hash the relative position. This catches
112 // a subset of the cases from the `file.contains(parent.lo)`. But we can do this check
113 // cheaply without the expensive `span_data_to_lines_and_cols` query.
114 Hash::hash(&TAG_RELATIVE_SPAN, hasher);
115 (span.lo - parent.lo).to_u32().hash_stable(self, hasher);
116 (span.hi - parent.lo).to_u32().hash_stable(self, hasher);
117 return;
118 }
119
120 // If this is not an empty or invalid span, we want to hash the last position that belongs
121 // to it, as opposed to hashing the first position past it.
122 let Some((file, line_lo, col_lo, line_hi, col_hi)) =
123 self.source_map().span_data_to_lines_and_cols(&span)
124 else {
125 Hash::hash(&TAG_INVALID_SPAN, hasher);
126 return;
127 };
128
129 if let Some(parent) = parent
130 && file.contains(parent.lo)
131 {
132 // This span is relative to another span in the same file,
133 // only hash the relative position.
134 Hash::hash(&TAG_RELATIVE_SPAN, hasher);
135 Hash::hash(&(span.lo.0.wrapping_sub(parent.lo.0)), hasher);
136 Hash::hash(&(span.hi.0.wrapping_sub(parent.lo.0)), hasher);
137 return;
138 }
139
140 Hash::hash(&TAG_VALID_SPAN, hasher);
141 Hash::hash(&file.stable_id, hasher);
142
143 // Hash both the length and the end location (line/column) of a span. If we hash only the
144 // length, for example, then two otherwise equal spans with different end locations will
145 // have the same hash. This can cause a problem during incremental compilation wherein a
146 // previous result for a query that depends on the end location of a span will be
147 // incorrectly reused when the end location of the span it depends on has changed (see
148 // issue #74890). A similar analysis applies if some query depends specifically on the
149 // length of the span, but we only hash the end location. So hash both.
150
151 let col_lo_trunc = (col_lo.0 as u64) & 0xFF;
152 let line_lo_trunc = ((line_lo as u64) & 0xFF_FF_FF) << 8;
153 let col_hi_trunc = (col_hi.0 as u64) & 0xFF << 32;
154 let line_hi_trunc = ((line_hi as u64) & 0xFF_FF_FF) << 40;
155 let col_line = col_lo_trunc | line_lo_trunc | col_hi_trunc | line_hi_trunc;
156 let len = (span.hi - span.lo).0;
157 Hash::hash(&col_line, hasher);
158 Hash::hash(&len, hasher);
159 }
160
161 #[inline]
162 fn def_path_hash(&self, def_id: DefId) -> DefPathHash {
163 if let Some(def_id) = def_id.as_local() {
164 self.untracked.definitions.read().def_path_hash(def_id)
165 } else {
166 self.untracked.cstore.read().def_path_hash(def_id)
167 }
168 }
169
170 /// Assert that the provided `HashStableContext` is configured with the default
171 /// `HashingControls`. We should always have bailed out before getting to here with a
172 /// non-default mode. With this check in place, we can avoid the need to maintain separate
173 /// versions of `ExpnData` hashes for each permutation of `HashingControls` settings.
174 #[inline]
175 fn assert_default_hashing_controls(&self, msg: &str) {
176 let hashing_controls = self.hashing_controls;
177 let HashingControls { hash_spans } = hashing_controls;
178
179 // Note that we require that `hash_spans` be the inverse of the global `-Z
180 // incremental-ignore-spans` option. Normally, this option is disabled, in which case
181 // `hash_spans` must be true.
182 //
183 // Span hashing can also be disabled without `-Z incremental-ignore-spans`. This is the
184 // case for instance when building a hash for name mangling. Such configuration must not be
185 // used for metadata.
186 assert_eq!(
187 hash_spans, !self.incremental_ignore_spans,
188 "Attempted hashing of {msg} with non-default HashingControls: {hashing_controls:?}"
189 );
190 }
191}
192
193impl<'a> rustc_abi::HashStableContext for StableHashingContext<'a> {}
194impl<'a> rustc_ast::HashStableContext for StableHashingContext<'a> {}
195impl<'a> rustc_hir::HashStableContext for StableHashingContext<'a> {}
196impl<'a> rustc_session::HashStableContext for StableHashingContext<'a> {}
compiler/rustc_middle/src/ich/impls_syntax.rs created+130
......@@ -0,0 +1,130 @@
1//! This module contains `HashStable` implementations for various data types
2//! from various crates in no particular order.
3
4use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
5use rustc_span::{SourceFile, Symbol, sym};
6use smallvec::SmallVec;
7use {rustc_ast as ast, rustc_hir as hir};
8
9use super::StableHashingContext;
10
11impl<'a> HashStable<StableHashingContext<'a>> for ast::NodeId {
12 #[inline]
13 fn hash_stable(&self, _: &mut StableHashingContext<'a>, _: &mut StableHasher) {
14 panic!("Node IDs should not appear in incremental state");
15 }
16}
17
18impl<'a> HashStable<StableHashingContext<'a>> for [hir::Attribute] {
19 fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
20 if self.is_empty() {
21 self.len().hash_stable(hcx, hasher);
22 return;
23 }
24
25 // Some attributes are always ignored during hashing.
26 let filtered: SmallVec<[&hir::Attribute; 8]> = self
27 .iter()
28 .filter(|attr| {
29 attr.is_doc_comment().is_none()
30 // FIXME(jdonszelmann) have a better way to handle ignored attrs
31 && !attr.name().is_some_and(|ident| is_ignored_attr(ident))
32 })
33 .collect();
34
35 filtered.len().hash_stable(hcx, hasher);
36 for attr in filtered {
37 attr.hash_stable(hcx, hasher);
38 }
39 }
40}
41
42#[inline]
43fn is_ignored_attr(name: Symbol) -> bool {
44 const IGNORED_ATTRIBUTES: &[Symbol] = &[
45 sym::cfg_trace, // FIXME(#138844) should this really be ignored?
46 sym::rustc_if_this_changed,
47 sym::rustc_then_this_would_need,
48 sym::rustc_clean,
49 sym::rustc_partition_reused,
50 sym::rustc_partition_codegened,
51 sym::rustc_expected_cgu_reuse,
52 ];
53 IGNORED_ATTRIBUTES.contains(&name)
54}
55
56impl<'a> HashStable<StableHashingContext<'a>> for SourceFile {
57 fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
58 let SourceFile {
59 name: _, // We hash the smaller stable_id instead of this
60 stable_id,
61 cnum,
62 // Do not hash the source as it is not encoded
63 src: _,
64 ref src_hash,
65 // Already includes src_hash, this is redundant
66 checksum_hash: _,
67 external_src: _,
68 start_pos: _,
69 normalized_source_len: _,
70 unnormalized_source_len: _,
71 lines: _,
72 ref multibyte_chars,
73 ref normalized_pos,
74 } = *self;
75
76 stable_id.hash_stable(hcx, hasher);
77
78 src_hash.hash_stable(hcx, hasher);
79
80 {
81 // We are always in `Lines` form by the time we reach here.
82 assert!(self.lines.read().is_lines());
83 let lines = self.lines();
84 // We only hash the relative position within this source_file
85 lines.len().hash_stable(hcx, hasher);
86 for &line in lines.iter() {
87 line.hash_stable(hcx, hasher);
88 }
89 }
90
91 // We only hash the relative position within this source_file
92 multibyte_chars.len().hash_stable(hcx, hasher);
93 for &char_pos in multibyte_chars.iter() {
94 char_pos.hash_stable(hcx, hasher);
95 }
96
97 normalized_pos.len().hash_stable(hcx, hasher);
98 for &char_pos in normalized_pos.iter() {
99 char_pos.hash_stable(hcx, hasher);
100 }
101
102 cnum.hash_stable(hcx, hasher);
103 }
104}
105
106impl<'tcx> HashStable<StableHashingContext<'tcx>> for rustc_feature::Features {
107 fn hash_stable(&self, hcx: &mut StableHashingContext<'tcx>, hasher: &mut StableHasher) {
108 // Unfortunately we cannot exhaustively list fields here, since the
109 // struct has private fields (to ensure its invariant is maintained)
110 self.enabled_lang_features().hash_stable(hcx, hasher);
111 self.enabled_lib_features().hash_stable(hcx, hasher);
112 }
113}
114
115impl<'tcx> HashStable<StableHashingContext<'tcx>> for rustc_feature::EnabledLangFeature {
116 fn hash_stable(&self, hcx: &mut StableHashingContext<'tcx>, hasher: &mut StableHasher) {
117 let rustc_feature::EnabledLangFeature { gate_name, attr_sp, stable_since } = self;
118 gate_name.hash_stable(hcx, hasher);
119 attr_sp.hash_stable(hcx, hasher);
120 stable_since.hash_stable(hcx, hasher);
121 }
122}
123
124impl<'tcx> HashStable<StableHashingContext<'tcx>> for rustc_feature::EnabledLibFeature {
125 fn hash_stable(&self, hcx: &mut StableHashingContext<'tcx>, hasher: &mut StableHasher) {
126 let rustc_feature::EnabledLibFeature { gate_name, attr_sp } = self;
127 gate_name.hash_stable(hcx, hasher);
128 attr_sp.hash_stable(hcx, hasher);
129 }
130}
compiler/rustc_middle/src/ich/mod.rs created+6
......@@ -0,0 +1,6 @@
1//! ICH - Incremental Compilation Hash
2
3pub use self::hcx::StableHashingContext;
4
5mod hcx;
6mod impls_syntax;
compiler/rustc_middle/src/lib.rs+1
......@@ -72,6 +72,7 @@ pub mod arena;
7272pub mod error;
7373pub mod hir;
7474pub mod hooks;
75pub mod ich;
7576pub mod infer;
7677pub mod lint;
7778pub mod metadata;
compiler/rustc_middle/src/middle/privacy.rs+1-1
......@@ -8,9 +8,9 @@ use rustc_data_structures::fx::{FxIndexMap, IndexEntry};
88use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
99use rustc_hir::def::DefKind;
1010use rustc_macros::HashStable;
11use rustc_query_system::ich::StableHashingContext;
1211use rustc_span::def_id::{CRATE_DEF_ID, LocalDefId};
1312
13use crate::ich::StableHashingContext;
1414use crate::ty::{TyCtxt, Visibility};
1515
1616/// Represents the levels of effective visibility an item can have.
compiler/rustc_middle/src/mir/mod.rs+2-1
......@@ -911,7 +911,8 @@ pub struct VarBindingIntroduction {
911911
912912mod binding_form_impl {
913913 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
914 use rustc_query_system::ich::StableHashingContext;
914
915 use crate::ich::StableHashingContext;
915916
916917 impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for super::BindingForm<'tcx> {
917918 fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
compiler/rustc_middle/src/mir/mono.rs+1-1
......@@ -12,7 +12,6 @@ use rustc_hir::ItemId;
1212use rustc_hir::attrs::{InlineAttr, Linkage};
1313use rustc_hir::def_id::{CrateNum, DefId, DefIdSet, LOCAL_CRATE};
1414use rustc_macros::{HashStable, TyDecodable, TyEncodable};
15use rustc_query_system::ich::StableHashingContext;
1615use rustc_session::config::OptLevel;
1716use rustc_span::{Span, Symbol};
1817use rustc_target::spec::SymbolVisibility;
......@@ -20,6 +19,7 @@ use tracing::debug;
2019
2120use crate::dep_graph::dep_node::{make_compile_codegen_unit, make_compile_mono_item};
2221use crate::dep_graph::{DepNode, WorkProduct, WorkProductId};
22use crate::ich::StableHashingContext;
2323use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
2424use crate::ty::{self, GenericArgs, Instance, InstanceKind, SymbolName, Ty, TyCtxt};
2525
compiler/rustc_middle/src/query/caches.rs+1-1
......@@ -7,10 +7,10 @@ use rustc_data_structures::stable_hasher::HashStable;
77pub use rustc_data_structures::vec_cache::VecCache;
88use rustc_hir::def_id::LOCAL_CRATE;
99use rustc_index::Idx;
10use rustc_query_system::ich::StableHashingContext;
1110use rustc_span::def_id::{DefId, DefIndex};
1211
1312use crate::dep_graph::DepNodeIndex;
13use crate::ich::StableHashingContext;
1414
1515/// Traits that all query keys must satisfy.
1616pub trait QueryCacheKey = Hash + Eq + Copy + Debug + for<'a> HashStable<StableHashingContext<'a>>;
compiler/rustc_middle/src/query/on_disk_cache.rs+1-2
......@@ -11,7 +11,6 @@ use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LOCAL_CRATE, LocalDefId, Stab
1111use rustc_hir::definitions::DefPathHash;
1212use rustc_index::{Idx, IndexVec};
1313use rustc_macros::{Decodable, Encodable};
14use rustc_query_system::query::QuerySideEffect;
1514use rustc_serialize::opaque::{FileEncodeResult, FileEncoder, IntEncodedWithFixedSize, MemDecoder};
1615use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
1716use rustc_session::Session;
......@@ -24,7 +23,7 @@ use rustc_span::{
2423 SourceFile, Span, SpanDecoder, SpanEncoder, StableSourceFileId, Symbol,
2524};
2625
27use crate::dep_graph::{DepNodeIndex, SerializedDepNodeIndex};
26use crate::dep_graph::{DepNodeIndex, QuerySideEffect, SerializedDepNodeIndex};
2827use crate::mir::interpret::{AllocDecodingSession, AllocDecodingState};
2928use crate::mir::mono::MonoItem;
3029use crate::mir::{self, interpret};
compiler/rustc_middle/src/query/plumbing.rs+1-4
......@@ -8,12 +8,12 @@ use rustc_data_structures::sync::{AtomicU64, WorkerLocal};
88use rustc_hir::def_id::{DefId, LocalDefId};
99use rustc_hir::hir_id::OwnerId;
1010use rustc_macros::HashStable;
11use rustc_query_system::ich::StableHashingContext;
1211use rustc_span::{ErrorGuaranteed, Span};
1312pub use sealed::IntoQueryParam;
1413
1514use crate::dep_graph;
1615use crate::dep_graph::{DepKind, DepNodeIndex, SerializedDepNodeIndex};
16use crate::ich::StableHashingContext;
1717use crate::queries::{
1818 ExternProviders, PerQueryVTables, Providers, QueryArenas, QueryCaches, QueryEngine, QueryStates,
1919};
......@@ -102,9 +102,6 @@ pub enum QueryMode {
102102}
103103
104104/// Stores function pointers and other metadata for a particular query.
105///
106/// Used indirectly by query plumbing in `rustc_query_system` via a trait,
107/// and also used directly by query plumbing in `rustc_query_impl`.
108105pub struct QueryVTable<'tcx, C: QueryCache> {
109106 pub name: &'static str,
110107 pub eval_always: bool,
compiler/rustc_middle/src/ty/adt.rs+1-1
......@@ -15,7 +15,6 @@ use rustc_hir::def_id::DefId;
1515use rustc_hir::{self as hir, LangItem, find_attr};
1616use rustc_index::{IndexSlice, IndexVec};
1717use rustc_macros::{HashStable, TyDecodable, TyEncodable};
18use rustc_query_system::ich::StableHashingContext;
1918use rustc_session::DataTypeKind;
2019use rustc_type_ir::solve::AdtDestructorKind;
2120use tracing::{debug, info, trace};
......@@ -23,6 +22,7 @@ use tracing::{debug, info, trace};
2322use super::{
2423 AsyncDestructor, Destructor, FieldDef, GenericPredicates, Ty, TyCtxt, VariantDef, VariantDiscr,
2524};
25use crate::ich::StableHashingContext;
2626use crate::mir::interpret::ErrorHandled;
2727use crate::ty;
2828use crate::ty::util::{Discr, IntTypeExt};
compiler/rustc_middle/src/ty/context.rs+2-2
......@@ -39,7 +39,6 @@ use rustc_hir::lang_items::LangItem;
3939use rustc_hir::limit::Limit;
4040use rustc_hir::{self as hir, HirId, Node, TraitCandidate, find_attr};
4141use rustc_index::IndexVec;
42use rustc_query_system::ich::StableHashingContext;
4342use rustc_serialize::opaque::{FileEncodeResult, FileEncoder};
4443use rustc_session::Session;
4544use rustc_session::config::CrateType;
......@@ -55,6 +54,7 @@ use tracing::{debug, instrument};
5554use crate::arena::Arena;
5655use crate::dep_graph::dep_node::make_metadata;
5756use crate::dep_graph::{DepGraph, DepKindVTable, DepNodeIndex};
57use crate::ich::StableHashingContext;
5858use crate::infer::canonical::{CanonicalParamEnvCache, CanonicalVarKind};
5959use crate::lint::lint_level;
6060use crate::metadata::ModChild;
......@@ -1220,7 +1220,7 @@ impl<'tcx> TyCtxt<'tcx> {
12201220 pub fn needs_crate_hash(self) -> bool {
12211221 // Why is the crate hash needed for these configurations?
12221222 // - debug_assertions: for the "fingerprint the result" check in
1223 // `rustc_query_system::query::plumbing::execute_job`.
1223 // `rustc_query_impl::execution::execute_job`.
12241224 // - incremental: for query lookups.
12251225 // - needs_metadata: for putting into crate metadata.
12261226 // - instrument_coverage: for putting into coverage data (see
compiler/rustc_middle/src/ty/impls_ty.rs+1-1
......@@ -9,9 +9,9 @@ use rustc_data_structures::fx::FxHashMap;
99use rustc_data_structures::stable_hasher::{
1010 HashStable, HashingControls, StableHasher, ToStableHashKey,
1111};
12use rustc_query_system::ich::StableHashingContext;
1312use tracing::trace;
1413
14use crate::ich::StableHashingContext;
1515use crate::middle::region;
1616use crate::{mir, ty};
1717
compiler/rustc_middle/src/ty/mod.rs+1-1
......@@ -47,7 +47,6 @@ use rustc_macros::{
4747 BlobDecodable, Decodable, Encodable, HashStable, TyDecodable, TyEncodable, TypeFoldable,
4848 TypeVisitable, extension,
4949};
50use rustc_query_system::ich::StableHashingContext;
5150use rustc_serialize::{Decodable, Encodable};
5251pub use rustc_session::lint::RegisteredTools;
5352use rustc_span::hygiene::MacroKind;
......@@ -112,6 +111,7 @@ pub use self::typeck_results::{
112111 Rust2024IncompatiblePatInfo, TypeckResults, UserType, UserTypeAnnotationIndex, UserTypeKind,
113112};
114113use crate::error::{OpaqueHiddenTypeMismatch, TypeMismatchReason};
114use crate::ich::StableHashingContext;
115115use crate::metadata::{AmbigModChild, ModChild};
116116use crate::middle::privacy::EffectiveVisibilities;
117117use crate::mir::{Body, CoroutineLayout, CoroutineSavedLocal, SourceInfo};
compiler/rustc_middle/src/verify_ich.rs+1-1
......@@ -1,10 +1,10 @@
11use std::cell::Cell;
22
33use rustc_data_structures::fingerprint::Fingerprint;
4use rustc_query_system::ich::StableHashingContext;
54use tracing::instrument;
65
76use crate::dep_graph::{DepGraphData, SerializedDepNodeIndex};
7use crate::ich::StableHashingContext;
88use crate::ty::TyCtxt;
99
1010#[inline]
compiler/rustc_parse/src/errors.rs+11
......@@ -3787,6 +3787,17 @@ pub(crate) struct RecoverImportAsUse {
37873787 pub token_name: String,
37883788}
37893789
3790#[derive(Diagnostic)]
3791#[diag("{$article} {$descr} cannot be `final`")]
3792#[note("only associated functions in traits can be `final`")]
3793pub(crate) struct InappropriateFinal {
3794 #[primary_span]
3795 #[label("`final` because of this")]
3796 pub span: Span,
3797 pub article: &'static str,
3798 pub descr: &'static str,
3799}
3800
37903801#[derive(Diagnostic)]
37913802#[diag("expected `::`, found `:`")]
37923803#[note("import paths are delimited using `::`")]
compiler/rustc_parse/src/parser/item.rs+24-11
......@@ -206,14 +206,24 @@ impl<'a> Parser<'a> {
206206 })
207207 }
208208
209 /// Error in-case `default` was parsed in an in-appropriate context.
209 /// Error in-case `default`/`final` was parsed in an in-appropriate context.
210210 fn error_on_unconsumed_default(&self, def: Defaultness, kind: &ItemKind) {
211 if let Defaultness::Default(span) = def {
212 self.dcx().emit_err(errors::InappropriateDefault {
213 span,
214 article: kind.article(),
215 descr: kind.descr(),
216 });
211 match def {
212 Defaultness::Default(span) => {
213 self.dcx().emit_err(errors::InappropriateDefault {
214 span,
215 article: kind.article(),
216 descr: kind.descr(),
217 });
218 }
219 Defaultness::Final(span) => {
220 self.dcx().emit_err(errors::InappropriateFinal {
221 span,
222 article: kind.article(),
223 descr: kind.descr(),
224 });
225 }
226 Defaultness::Implicit => (),
217227 }
218228 }
219229
......@@ -229,8 +239,8 @@ impl<'a> Parser<'a> {
229239 fn_parse_mode: FnParseMode,
230240 case: Case,
231241 ) -> PResult<'a, Option<ItemKind>> {
232 let check_pub = def == &Defaultness::Final;
233 let mut def_ = || mem::replace(def, Defaultness::Final);
242 let check_pub = def == &Defaultness::Implicit;
243 let mut def_ = || mem::replace(def, Defaultness::Implicit);
234244
235245 let info = if !self.is_use_closure() && self.eat_keyword_case(exp!(Use), case) {
236246 self.parse_use_item()?
......@@ -1005,8 +1015,11 @@ impl<'a> Parser<'a> {
10051015 {
10061016 self.bump(); // `default`
10071017 Defaultness::Default(self.prev_token_uninterpolated_span())
1018 } else if self.eat_keyword(exp!(Final)) {
1019 self.psess.gated_spans.gate(sym::final_associated_functions, self.prev_token.span);
1020 Defaultness::Final(self.prev_token_uninterpolated_span())
10081021 } else {
1009 Defaultness::Final
1022 Defaultness::Implicit
10101023 }
10111024 }
10121025
......@@ -1130,7 +1143,7 @@ impl<'a> Parser<'a> {
11301143 }) => {
11311144 self.dcx().emit_err(errors::AssociatedStaticItemNotAllowed { span });
11321145 AssocItemKind::Const(Box::new(ConstItem {
1133 defaultness: Defaultness::Final,
1146 defaultness: Defaultness::Implicit,
11341147 ident,
11351148 generics: Generics::default(),
11361149 ty,
compiler/rustc_parse/src/parser/token_type.rs+4
......@@ -91,6 +91,7 @@ pub enum TokenType {
9191 KwElse,
9292 KwEnum,
9393 KwExtern,
94 KwFinal,
9495 KwFn,
9596 KwFor,
9697 KwGen,
......@@ -233,6 +234,7 @@ impl TokenType {
233234 KwExtern,
234235 KwFn,
235236 KwFor,
237 KwFinal,
236238 KwGen,
237239 KwIf,
238240 KwImpl,
......@@ -309,6 +311,7 @@ impl TokenType {
309311 TokenType::KwExtern => Some(kw::Extern),
310312 TokenType::KwFn => Some(kw::Fn),
311313 TokenType::KwFor => Some(kw::For),
314 TokenType::KwFinal => Some(kw::Final),
312315 TokenType::KwGen => Some(kw::Gen),
313316 TokenType::KwIf => Some(kw::If),
314317 TokenType::KwImpl => Some(kw::Impl),
......@@ -524,6 +527,7 @@ macro_rules! exp {
524527 (Extern) => { exp!(@kw, Extern, KwExtern) };
525528 (Fn) => { exp!(@kw, Fn, KwFn) };
526529 (For) => { exp!(@kw, For, KwFor) };
530 (Final) => { exp!(@kw, Final, KwFinal) };
527531 (Gen) => { exp!(@kw, Gen, KwGen) };
528532 (If) => { exp!(@kw, If, KwIf) };
529533 (Impl) => { exp!(@kw, Impl, KwImpl) };
compiler/rustc_passes/src/check_attr.rs+1-1
......@@ -246,6 +246,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
246246 | AttributeKind::CrateName { .. }
247247 | AttributeKind::CrateType(..)
248248 | AttributeKind::DebuggerVisualizer(..)
249 | AttributeKind::DefaultLibAllocator
249250 // `#[doc]` is actually a lot more than just doc comments, so is checked below
250251 | AttributeKind::DocComment {..}
251252 | AttributeKind::EiiDeclaration { .. }
......@@ -399,7 +400,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
399400 | sym::deny
400401 | sym::forbid
401402 // internal
402 | sym::default_lib_allocator
403403 | sym::rustc_inherit_overflow_checks
404404 | sym::rustc_on_unimplemented
405405 | sym::rustc_doc_primitive
compiler/rustc_query_system/Cargo.toml deleted-19
......@@ -1,19 +0,0 @@
1[package]
2name = "rustc_query_system"
3version = "0.0.0"
4edition = "2024"
5
6[dependencies]
7# tidy-alphabetical-start
8rustc_abi = { path = "../rustc_abi" }
9rustc_ast = { path = "../rustc_ast" }
10rustc_data_structures = { path = "../rustc_data_structures" }
11rustc_errors = { path = "../rustc_errors" }
12rustc_feature = { path = "../rustc_feature" }
13rustc_hir = { path = "../rustc_hir" }
14rustc_macros = { path = "../rustc_macros" }
15rustc_serialize = { path = "../rustc_serialize" }
16rustc_session = { path = "../rustc_session" }
17rustc_span = { path = "../rustc_span" }
18smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
19# tidy-alphabetical-end
compiler/rustc_query_system/src/ich/hcx.rs deleted-196
......@@ -1,196 +0,0 @@
1use std::hash::Hash;
2
3use rustc_data_structures::stable_hasher::{HashStable, HashingControls, StableHasher};
4use rustc_hir::def_id::{DefId, LocalDefId};
5use rustc_hir::definitions::DefPathHash;
6use rustc_session::Session;
7use rustc_session::cstore::Untracked;
8use rustc_span::source_map::SourceMap;
9use rustc_span::{CachingSourceMapView, DUMMY_SP, Pos, Span};
10
11// Very often, we are hashing something that does not need the `CachingSourceMapView`, so we
12// initialize it lazily.
13#[derive(Clone)]
14enum CachingSourceMap<'a> {
15 Unused(&'a SourceMap),
16 InUse(CachingSourceMapView<'a>),
17}
18
19/// This is the context state available during incr. comp. hashing. It contains
20/// enough information to transform `DefId`s and `HirId`s into stable `DefPath`s (i.e.,
21/// a reference to the `TyCtxt`) and it holds a few caches for speeding up various
22/// things (e.g., each `DefId`/`DefPath` is only hashed once).
23#[derive(Clone)]
24pub struct StableHashingContext<'a> {
25 untracked: &'a Untracked,
26 // The value of `-Z incremental-ignore-spans`.
27 // This field should only be used by `unstable_opts_incremental_ignore_span`
28 incremental_ignore_spans: bool,
29 caching_source_map: CachingSourceMap<'a>,
30 hashing_controls: HashingControls,
31}
32
33impl<'a> StableHashingContext<'a> {
34 #[inline]
35 pub fn new(sess: &'a Session, untracked: &'a Untracked) -> Self {
36 let hash_spans_initial = !sess.opts.unstable_opts.incremental_ignore_spans;
37
38 StableHashingContext {
39 untracked,
40 incremental_ignore_spans: sess.opts.unstable_opts.incremental_ignore_spans,
41 caching_source_map: CachingSourceMap::Unused(sess.source_map()),
42 hashing_controls: HashingControls { hash_spans: hash_spans_initial },
43 }
44 }
45
46 #[inline]
47 pub fn while_hashing_spans<F: FnOnce(&mut Self)>(&mut self, hash_spans: bool, f: F) {
48 let prev_hash_spans = self.hashing_controls.hash_spans;
49 self.hashing_controls.hash_spans = hash_spans;
50 f(self);
51 self.hashing_controls.hash_spans = prev_hash_spans;
52 }
53
54 #[inline]
55 fn source_map(&mut self) -> &mut CachingSourceMapView<'a> {
56 match self.caching_source_map {
57 CachingSourceMap::InUse(ref mut sm) => sm,
58 CachingSourceMap::Unused(sm) => {
59 self.caching_source_map = CachingSourceMap::InUse(CachingSourceMapView::new(sm));
60 self.source_map() // this recursive call will hit the `InUse` case
61 }
62 }
63 }
64
65 #[inline]
66 fn def_span(&self, def_id: LocalDefId) -> Span {
67 self.untracked.source_span.get(def_id).unwrap_or(DUMMY_SP)
68 }
69
70 #[inline]
71 pub fn hashing_controls(&self) -> HashingControls {
72 self.hashing_controls
73 }
74}
75
76impl<'a> rustc_span::HashStableContext for StableHashingContext<'a> {
77 /// Hashes a span in a stable way. We can't directly hash the span's `BytePos` fields (that
78 /// would be similar to hashing pointers, since those are just offsets into the `SourceMap`).
79 /// Instead, we hash the (file name, line, column) triple, which stays the same even if the
80 /// containing `SourceFile` has moved within the `SourceMap`.
81 ///
82 /// Also note that we are hashing byte offsets for the column, not unicode codepoint offsets.
83 /// For the purpose of the hash that's sufficient. Also, hashing filenames is expensive so we
84 /// avoid doing it twice when the span starts and ends in the same file, which is almost always
85 /// the case.
86 ///
87 /// IMPORTANT: changes to this method should be reflected in implementations of `SpanEncoder`.
88 #[inline]
89 fn span_hash_stable(&mut self, span: Span, hasher: &mut StableHasher) {
90 const TAG_VALID_SPAN: u8 = 0;
91 const TAG_INVALID_SPAN: u8 = 1;
92 const TAG_RELATIVE_SPAN: u8 = 2;
93
94 if !self.hashing_controls().hash_spans {
95 return;
96 }
97
98 let span = span.data_untracked();
99 span.ctxt.hash_stable(self, hasher);
100 span.parent.hash_stable(self, hasher);
101
102 if span.is_dummy() {
103 Hash::hash(&TAG_INVALID_SPAN, hasher);
104 return;
105 }
106
107 let parent = span.parent.map(|parent| self.def_span(parent).data_untracked());
108 if let Some(parent) = parent
109 && parent.contains(span)
110 {
111 // This span is enclosed in a definition: only hash the relative position. This catches
112 // a subset of the cases from the `file.contains(parent.lo)`. But we can do this check
113 // cheaply without the expensive `span_data_to_lines_and_cols` query.
114 Hash::hash(&TAG_RELATIVE_SPAN, hasher);
115 (span.lo - parent.lo).to_u32().hash_stable(self, hasher);
116 (span.hi - parent.lo).to_u32().hash_stable(self, hasher);
117 return;
118 }
119
120 // If this is not an empty or invalid span, we want to hash the last position that belongs
121 // to it, as opposed to hashing the first position past it.
122 let Some((file, line_lo, col_lo, line_hi, col_hi)) =
123 self.source_map().span_data_to_lines_and_cols(&span)
124 else {
125 Hash::hash(&TAG_INVALID_SPAN, hasher);
126 return;
127 };
128
129 if let Some(parent) = parent
130 && file.contains(parent.lo)
131 {
132 // This span is relative to another span in the same file,
133 // only hash the relative position.
134 Hash::hash(&TAG_RELATIVE_SPAN, hasher);
135 Hash::hash(&(span.lo.0.wrapping_sub(parent.lo.0)), hasher);
136 Hash::hash(&(span.hi.0.wrapping_sub(parent.lo.0)), hasher);
137 return;
138 }
139
140 Hash::hash(&TAG_VALID_SPAN, hasher);
141 Hash::hash(&file.stable_id, hasher);
142
143 // Hash both the length and the end location (line/column) of a span. If we hash only the
144 // length, for example, then two otherwise equal spans with different end locations will
145 // have the same hash. This can cause a problem during incremental compilation wherein a
146 // previous result for a query that depends on the end location of a span will be
147 // incorrectly reused when the end location of the span it depends on has changed (see
148 // issue #74890). A similar analysis applies if some query depends specifically on the
149 // length of the span, but we only hash the end location. So hash both.
150
151 let col_lo_trunc = (col_lo.0 as u64) & 0xFF;
152 let line_lo_trunc = ((line_lo as u64) & 0xFF_FF_FF) << 8;
153 let col_hi_trunc = (col_hi.0 as u64) & 0xFF << 32;
154 let line_hi_trunc = ((line_hi as u64) & 0xFF_FF_FF) << 40;
155 let col_line = col_lo_trunc | line_lo_trunc | col_hi_trunc | line_hi_trunc;
156 let len = (span.hi - span.lo).0;
157 Hash::hash(&col_line, hasher);
158 Hash::hash(&len, hasher);
159 }
160
161 #[inline]
162 fn def_path_hash(&self, def_id: DefId) -> DefPathHash {
163 if let Some(def_id) = def_id.as_local() {
164 self.untracked.definitions.read().def_path_hash(def_id)
165 } else {
166 self.untracked.cstore.read().def_path_hash(def_id)
167 }
168 }
169
170 /// Assert that the provided `HashStableContext` is configured with the default
171 /// `HashingControls`. We should always have bailed out before getting to here with a
172 /// non-default mode. With this check in place, we can avoid the need to maintain separate
173 /// versions of `ExpnData` hashes for each permutation of `HashingControls` settings.
174 #[inline]
175 fn assert_default_hashing_controls(&self, msg: &str) {
176 let hashing_controls = self.hashing_controls;
177 let HashingControls { hash_spans } = hashing_controls;
178
179 // Note that we require that `hash_spans` be the inverse of the global `-Z
180 // incremental-ignore-spans` option. Normally, this option is disabled, in which case
181 // `hash_spans` must be true.
182 //
183 // Span hashing can also be disabled without `-Z incremental-ignore-spans`. This is the
184 // case for instance when building a hash for name mangling. Such configuration must not be
185 // used for metadata.
186 assert_eq!(
187 hash_spans, !self.incremental_ignore_spans,
188 "Attempted hashing of {msg} with non-default HashingControls: {hashing_controls:?}"
189 );
190 }
191}
192
193impl<'a> rustc_abi::HashStableContext for StableHashingContext<'a> {}
194impl<'a> rustc_ast::HashStableContext for StableHashingContext<'a> {}
195impl<'a> rustc_hir::HashStableContext for StableHashingContext<'a> {}
196impl<'a> rustc_session::HashStableContext for StableHashingContext<'a> {}
compiler/rustc_query_system/src/ich/impls_syntax.rs deleted-130
......@@ -1,130 +0,0 @@
1//! This module contains `HashStable` implementations for various data types
2//! from various crates in no particular order.
3
4use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
5use rustc_span::{SourceFile, Symbol, sym};
6use smallvec::SmallVec;
7use {rustc_ast as ast, rustc_hir as hir};
8
9use crate::ich::StableHashingContext;
10
11impl<'a> HashStable<StableHashingContext<'a>> for ast::NodeId {
12 #[inline]
13 fn hash_stable(&self, _: &mut StableHashingContext<'a>, _: &mut StableHasher) {
14 panic!("Node IDs should not appear in incremental state");
15 }
16}
17
18impl<'a> HashStable<StableHashingContext<'a>> for [hir::Attribute] {
19 fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
20 if self.is_empty() {
21 self.len().hash_stable(hcx, hasher);
22 return;
23 }
24
25 // Some attributes are always ignored during hashing.
26 let filtered: SmallVec<[&hir::Attribute; 8]> = self
27 .iter()
28 .filter(|attr| {
29 attr.is_doc_comment().is_none()
30 // FIXME(jdonszelmann) have a better way to handle ignored attrs
31 && !attr.name().is_some_and(|ident| is_ignored_attr(ident))
32 })
33 .collect();
34
35 filtered.len().hash_stable(hcx, hasher);
36 for attr in filtered {
37 attr.hash_stable(hcx, hasher);
38 }
39 }
40}
41
42#[inline]
43fn is_ignored_attr(name: Symbol) -> bool {
44 const IGNORED_ATTRIBUTES: &[Symbol] = &[
45 sym::cfg_trace, // FIXME(#138844) should this really be ignored?
46 sym::rustc_if_this_changed,
47 sym::rustc_then_this_would_need,
48 sym::rustc_clean,
49 sym::rustc_partition_reused,
50 sym::rustc_partition_codegened,
51 sym::rustc_expected_cgu_reuse,
52 ];
53 IGNORED_ATTRIBUTES.contains(&name)
54}
55
56impl<'a> HashStable<StableHashingContext<'a>> for SourceFile {
57 fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
58 let SourceFile {
59 name: _, // We hash the smaller stable_id instead of this
60 stable_id,
61 cnum,
62 // Do not hash the source as it is not encoded
63 src: _,
64 ref src_hash,
65 // Already includes src_hash, this is redundant
66 checksum_hash: _,
67 external_src: _,
68 start_pos: _,
69 normalized_source_len: _,
70 unnormalized_source_len: _,
71 lines: _,
72 ref multibyte_chars,
73 ref normalized_pos,
74 } = *self;
75
76 stable_id.hash_stable(hcx, hasher);
77
78 src_hash.hash_stable(hcx, hasher);
79
80 {
81 // We are always in `Lines` form by the time we reach here.
82 assert!(self.lines.read().is_lines());
83 let lines = self.lines();
84 // We only hash the relative position within this source_file
85 lines.len().hash_stable(hcx, hasher);
86 for &line in lines.iter() {
87 line.hash_stable(hcx, hasher);
88 }
89 }
90
91 // We only hash the relative position within this source_file
92 multibyte_chars.len().hash_stable(hcx, hasher);
93 for &char_pos in multibyte_chars.iter() {
94 char_pos.hash_stable(hcx, hasher);
95 }
96
97 normalized_pos.len().hash_stable(hcx, hasher);
98 for &char_pos in normalized_pos.iter() {
99 char_pos.hash_stable(hcx, hasher);
100 }
101
102 cnum.hash_stable(hcx, hasher);
103 }
104}
105
106impl<'tcx> HashStable<StableHashingContext<'tcx>> for rustc_feature::Features {
107 fn hash_stable(&self, hcx: &mut StableHashingContext<'tcx>, hasher: &mut StableHasher) {
108 // Unfortunately we cannot exhaustively list fields here, since the
109 // struct has private fields (to ensure its invariant is maintained)
110 self.enabled_lang_features().hash_stable(hcx, hasher);
111 self.enabled_lib_features().hash_stable(hcx, hasher);
112 }
113}
114
115impl<'tcx> HashStable<StableHashingContext<'tcx>> for rustc_feature::EnabledLangFeature {
116 fn hash_stable(&self, hcx: &mut StableHashingContext<'tcx>, hasher: &mut StableHasher) {
117 let rustc_feature::EnabledLangFeature { gate_name, attr_sp, stable_since } = self;
118 gate_name.hash_stable(hcx, hasher);
119 attr_sp.hash_stable(hcx, hasher);
120 stable_since.hash_stable(hcx, hasher);
121 }
122}
123
124impl<'tcx> HashStable<StableHashingContext<'tcx>> for rustc_feature::EnabledLibFeature {
125 fn hash_stable(&self, hcx: &mut StableHashingContext<'tcx>, hasher: &mut StableHasher) {
126 let rustc_feature::EnabledLibFeature { gate_name, attr_sp } = self;
127 gate_name.hash_stable(hcx, hasher);
128 attr_sp.hash_stable(hcx, hasher);
129 }
130}
compiler/rustc_query_system/src/ich/mod.rs deleted-6
......@@ -1,6 +0,0 @@
1//! ICH - Incremental Compilation Hash
2
3pub use self::hcx::StableHashingContext;
4
5mod hcx;
6mod impls_syntax;
compiler/rustc_query_system/src/lib.rs deleted-8
......@@ -1,8 +0,0 @@
1// tidy-alphabetical-start
2#![allow(internal_features)]
3#![cfg_attr(bootstrap, feature(assert_matches))]
4#![feature(min_specialization)]
5// tidy-alphabetical-end
6
7pub mod ich;
8pub mod query;
compiler/rustc_query_system/src/query/README.md deleted-3
......@@ -1,3 +0,0 @@
1For more information about how the query system works, see the [rustc dev guide].
2
3[rustc dev guide]: https://rustc-dev-guide.rust-lang.org/query.html
compiler/rustc_query_system/src/query/mod.rs deleted-22
......@@ -1,22 +0,0 @@
1use std::fmt::Debug;
2
3use rustc_errors::DiagInner;
4use rustc_macros::{Decodable, Encodable};
5
6/// Tracks 'side effects' for a particular query.
7/// This struct is saved to disk along with the query result,
8/// and loaded from disk if we mark the query as green.
9/// This allows us to 'replay' changes to global state
10/// that would otherwise only occur if we actually
11/// executed the query method.
12///
13/// Each side effect gets an unique dep node index which is added
14/// as a dependency of the query which had the effect.
15#[derive(Debug, Encodable, Decodable)]
16pub enum QuerySideEffect {
17 /// Stores a diagnostic emitted during query execution.
18 /// This diagnostic will be re-emitted if we mark
19 /// the query as green, as that query will have the side
20 /// effect dep node as a dependency.
21 Diagnostic(DiagInner),
22}
compiler/rustc_span/src/symbol.rs+1
......@@ -1096,6 +1096,7 @@ symbols! {
10961096 fields,
10971097 file,
10981098 file_options,
1099 final_associated_functions,
10991100 flags,
11001101 float,
11011102 float_to_int_unchecked,
compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs+21-13
......@@ -282,23 +282,31 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
282282 if self.tcx.is_diagnostic_item(sym::From, trait_def_id)
283283 || self.tcx.is_diagnostic_item(sym::TryFrom, trait_def_id)
284284 {
285 let found_ty = leaf_trait_predicate.skip_binder().trait_ref.args.type_at(1);
286 let ty = main_trait_predicate.skip_binder().self_ty();
287 if let Some(cast_ty) = self.find_explicit_cast_type(
288 obligation.param_env,
289 found_ty,
290 ty,
291 ) {
292 let found_ty_str = self.tcx.short_string(found_ty, &mut long_ty_file);
293 let cast_ty_str = self.tcx.short_string(cast_ty, &mut long_ty_file);
294 err.help(
295 format!(
285 let trait_ref = leaf_trait_predicate.skip_binder().trait_ref;
286
287 // Defensive: next-solver may produce fewer args than expected.
288 if trait_ref.args.len() > 1 {
289 let found_ty = trait_ref.args.type_at(1);
290 let ty = main_trait_predicate.skip_binder().self_ty();
291
292 if let Some(cast_ty) = self.find_explicit_cast_type(
293 obligation.param_env,
294 found_ty,
295 ty,
296 ) {
297 let found_ty_str =
298 self.tcx.short_string(found_ty, &mut long_ty_file);
299 let cast_ty_str =
300 self.tcx.short_string(cast_ty, &mut long_ty_file);
301
302 err.help(format!(
296303 "consider casting the `{found_ty_str}` value to `{cast_ty_str}`",
297 ),
298 );
304 ));
305 }
299306 }
300307 }
301308
309
302310 *err.long_ty_path() = long_ty_file;
303311
304312 let mut suggested = false;
compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs+10-8
......@@ -5608,15 +5608,17 @@ pub(super) fn get_explanation_based_on_obligation<'tcx>(
56085608 None => String::new(),
56095609 };
56105610 if let ty::PredicatePolarity::Positive = trait_predicate.polarity() {
5611 // If the trait in question is unstable, mention that fact in the diagnostic.
5612 // But if we're building with `-Zforce-unstable-if-unmarked` then _any_ trait
5613 // not explicitly marked stable is considered unstable, so the extra text is
5614 // unhelpful noise. See <https://github.com/rust-lang/rust/issues/152692>.
5615 let mention_unstable = !tcx.sess.opts.unstable_opts.force_unstable_if_unmarked
5616 && try { tcx.lookup_stability(trait_predicate.def_id())?.level.is_stable() }
5617 == Some(false);
5618 let unstable = if mention_unstable { "nightly-only, unstable " } else { "" };
5619
56115620 format!(
5612 "{pre_message}the {}trait `{}` is not implemented for{desc} `{}`",
5613 if tcx.lookup_stability(trait_predicate.def_id()).map(|s| s.level.is_stable())
5614 == Some(false)
5615 {
5616 "nightly-only, unstable "
5617 } else {
5618 ""
5619 },
5621 "{pre_message}the {unstable}trait `{}` is not implemented for{desc} `{}`",
56205622 trait_predicate.print_modifiers_and_trait_path(),
56215623 tcx.short_string(trait_predicate.self_ty().skip_binder(), long_ty_path),
56225624 )
compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs+5
......@@ -314,6 +314,11 @@ pub fn dyn_compatibility_violations_for_assoc_item(
314314 trait_def_id: DefId,
315315 item: ty::AssocItem,
316316) -> Vec<DynCompatibilityViolation> {
317 // `final` assoc functions don't prevent a trait from being dyn-compatible
318 if tcx.defaultness(item.def_id).is_final() {
319 return Vec::new();
320 }
321
317322 // Any item that has a `Self: Sized` requisite is otherwise exempt from the regulations.
318323 if tcx.generics_require_sized_self(item.def_id) {
319324 return Vec::new();
compiler/rustc_trait_selection/src/traits/vtable.rs+5
......@@ -210,6 +210,11 @@ fn own_existential_vtable_entries_iter(
210210 debug!("own_existential_vtable_entry: trait_method={:?}", trait_method);
211211 let def_id = trait_method.def_id;
212212
213 // Final methods should not be included in the vtable.
214 if trait_method.defaultness(tcx).is_final() {
215 return None;
216 }
217
213218 // Some methods cannot be called on an object; skip those.
214219 if !is_vtable_safe_method(tcx, trait_def_id, trait_method) {
215220 debug!("own_existential_vtable_entry: not vtable safe");
compiler/rustc_ty_utils/src/instance.rs+6
......@@ -237,6 +237,12 @@ fn resolve_associated_item<'tcx>(
237237 }
238238 traits::ImplSource::Builtin(BuiltinImplSource::Object(_), _) => {
239239 let trait_ref = ty::TraitRef::from_assoc(tcx, trait_id, rcvr_args);
240
241 // `final` methods should be called directly.
242 if tcx.defaultness(trait_item_id).is_final() {
243 return Ok(Some(ty::Instance::new_raw(trait_item_id, rcvr_args)));
244 }
245
240246 if trait_ref.has_non_region_infer() || trait_ref.has_non_region_param() {
241247 // We only resolve totally substituted vtable entries.
242248 None
compiler/rustc_type_ir/src/predicate.rs+11-2
......@@ -42,7 +42,9 @@ where
4242 }
4343}
4444
45/// A complete reference to a trait. These take numerous guises in syntax,
45/// A complete reference to a trait.
46///
47/// These take numerous guises in syntax,
4648/// but perhaps the most recognizable form is in a where-clause:
4749/// ```ignore (illustrative)
4850/// T: Foo<U>
......@@ -241,7 +243,9 @@ impl ImplPolarity {
241243 }
242244}
243245
244/// Polarity for a trait predicate. May either be negative or positive.
246/// Polarity for a trait predicate.
247///
248/// May either be negative or positive.
245249/// Distinguished from [`ImplPolarity`] since we never compute goals with
246250/// "reservation" level.
247251#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
......@@ -327,6 +331,7 @@ impl<I: Interner> ty::Binder<I, ExistentialPredicate<I>> {
327331}
328332
329333/// An existential reference to a trait, where `Self` is erased.
334///
330335/// For example, the trait object `Trait<'a, 'b, X, Y>` is:
331336/// ```ignore (illustrative)
332337/// exists T. T: Trait<'a, 'b, X, Y>
......@@ -442,6 +447,7 @@ impl<I: Interner> ExistentialProjection<I> {
442447 }
443448
444449 /// Extracts the underlying existential trait reference from this projection.
450 ///
445451 /// For example, if this is a projection of `exists T. <T as Iterator>::Item == X`,
446452 /// then this function would return an `exists T. T: Iterator` existential trait
447453 /// reference.
......@@ -493,14 +499,17 @@ impl<I: Interner> ty::Binder<I, ExistentialProjection<I>> {
493499#[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_NoContext))]
494500pub enum AliasTermKind {
495501 /// A projection `<Type as Trait>::AssocType`.
502 ///
496503 /// Can get normalized away if monomorphic enough.
497504 ProjectionTy,
498505 /// An associated type in an inherent `impl`
499506 InherentTy,
500507 /// An opaque type (usually from `impl Trait` in type aliases or function return types)
508 ///
501509 /// Can only be normalized away in PostAnalysis mode or its defining scope.
502510 OpaqueTy,
503511 /// A free type alias that actually checks its trait bounds.
512 ///
504513 /// Currently only used if the type alias references opaque types.
505514 /// Can always be normalized away.
506515 FreeTy,
compiler/rustc_type_ir/src/ty_kind.rs+25-9
......@@ -29,14 +29,17 @@ mod closure;
2929)]
3030pub enum AliasTyKind {
3131 /// A projection `<Type as Trait>::AssocType`.
32 ///
3233 /// Can get normalized away if monomorphic enough.
3334 Projection,
3435 /// An associated type in an inherent `impl`
3536 Inherent,
3637 /// An opaque type (usually from `impl Trait` in type aliases or function return types)
38 ///
3739 /// Can only be normalized away in PostAnalysis mode or its defining scope.
3840 Opaque,
3941 /// A type alias that actually checks its trait bounds.
42 ///
4043 /// Currently only used if the type alias references opaque types.
4144 /// Can always be normalized away.
4245 Free,
......@@ -99,7 +102,9 @@ pub enum TyKind<I: Interner> {
99102 /// An array with the given length. Written as `[T; N]`.
100103 Array(I::Ty, I::Const),
101104
102 /// A pattern newtype. Takes any type and restricts its valid values to its pattern.
105 /// A pattern newtype.
106 ///
107 /// Takes any type and restricts its valid values to its pattern.
103108 /// This will also change the layout to take advantage of this restriction.
104109 /// Only `Copy` and `Clone` will automatically get implemented for pattern types.
105110 /// Auto-traits treat this as if it were an aggregate with a single nested type.
......@@ -116,8 +121,9 @@ pub enum TyKind<I: Interner> {
116121 /// `&'a mut T` or `&'a T`.
117122 Ref(I::Region, I::Ty, Mutability),
118123
119 /// The anonymous type of a function declaration/definition. Each
120 /// function has a unique type.
124 /// The anonymous type of a function declaration/definition.
125 ///
126 /// Each function has a unique type.
121127 ///
122128 /// For the function `fn foo() -> i32 { 3 }` this type would be
123129 /// shown to the user as `fn() -> i32 {foo}`.
......@@ -129,7 +135,9 @@ pub enum TyKind<I: Interner> {
129135 /// ```
130136 FnDef(I::FunctionId, I::GenericArgs),
131137
132 /// A pointer to a function. Written as `fn() -> i32`.
138 /// A pointer to a function.
139 ///
140 /// Written as `fn() -> i32`.
133141 ///
134142 /// Note that both functions and closures start out as either
135143 /// [FnDef] or [Closure] which can be then be coerced to this variant.
......@@ -179,6 +187,7 @@ pub enum TyKind<I: Interner> {
179187 Coroutine(I::CoroutineId, I::GenericArgs),
180188
181189 /// A type representing the types stored inside a coroutine.
190 ///
182191 /// This should only appear as part of the `CoroutineArgs`.
183192 ///
184193 /// Unlike upvars, the witness can reference lifetimes from
......@@ -210,6 +219,7 @@ pub enum TyKind<I: Interner> {
210219 Tuple(I::Tys),
211220
212221 /// A projection, opaque type, free type alias, or inherent associated type.
222 ///
213223 /// All of these types are represented as pairs of def-id and args, and can
214224 /// be normalized, so they are grouped conceptually.
215225 Alias(AliasTyKind, AliasTy<I>),
......@@ -253,8 +263,9 @@ pub enum TyKind<I: Interner> {
253263 /// inside of the type.
254264 Infer(InferTy),
255265
256 /// A placeholder for a type which could not be computed; this is
257 /// propagated to avoid useless error messages.
266 /// A placeholder for a type which could not be computed.
267 ///
268 /// This is propagated to avoid useless error messages.
258269 Error(I::ErrorGuaranteed),
259270}
260271
......@@ -282,7 +293,9 @@ impl<I: Interner> TyKind<I> {
282293 }
283294
284295 /// Returns `true` when the outermost type cannot be further normalized,
285 /// resolved, or instantiated. This includes all primitive types, but also
296 /// resolved, or instantiated.
297 ///
298 /// This includes all primitive types, but also
286299 /// things like ADTs and trait objects, since even if their arguments or
287300 /// nested types may be further simplified, the outermost [`ty::TyKind`] or
288301 /// type constructor remains the same.
......@@ -481,6 +494,7 @@ impl<I: Interner> AliasTy<I> {
481494 }
482495
483496 /// Extracts the underlying trait reference and own args from this projection.
497 ///
484498 /// For example, if this is a projection of `<T as StreamingIterator>::Item<'a>`,
485499 /// then this function would return a `T: StreamingIterator` trait reference and
486500 /// `['a]` as the own args.
......@@ -490,6 +504,7 @@ impl<I: Interner> AliasTy<I> {
490504 }
491505
492506 /// Extracts the underlying trait reference from this projection.
507 ///
493508 /// For example, if this is a projection of `<T as Iterator>::Item`,
494509 /// then this function would return a `T: Iterator` trait reference.
495510 ///
......@@ -593,8 +608,9 @@ pub enum InferTy {
593608 FloatVar(FloatVid),
594609
595610 /// A [`FreshTy`][Self::FreshTy] is one that is generated as a replacement
596 /// for an unbound type variable. This is convenient for caching etc. See
597 /// `TypeFreshener` for more details.
611 /// for an unbound type variable.
612 ///
613 /// This is convenient for caching etc. See `TypeFreshener` for more details.
598614 ///
599615 /// Compare with [`TyVar`][Self::TyVar].
600616 FreshTy(u32),
library/core/src/num/f128.rs+64
......@@ -275,6 +275,70 @@ impl f128 {
275275 #[unstable(feature = "f128", issue = "116909")]
276276 pub const NEG_INFINITY: f128 = -1.0_f128 / 0.0_f128;
277277
278 /// Maximum integer that can be represented exactly in an [`f128`] value,
279 /// with no other integer converting to the same floating point value.
280 ///
281 /// For an integer `x` which satisfies `MIN_EXACT_INTEGER <= x <= MAX_EXACT_INTEGER`,
282 /// there is a "one-to-one" mapping between [`i128`] and [`f128`] values.
283 /// `MAX_EXACT_INTEGER + 1` also converts losslessly to [`f128`] and back to
284 /// [`i128`], but `MAX_EXACT_INTEGER + 2` converts to the same [`f128`] value
285 /// (and back to `MAX_EXACT_INTEGER + 1` as an integer) so there is not a
286 /// "one-to-one" mapping.
287 ///
288 /// [`MAX_EXACT_INTEGER`]: f128::MAX_EXACT_INTEGER
289 /// [`MIN_EXACT_INTEGER`]: f128::MIN_EXACT_INTEGER
290 /// ```
291 /// #![feature(f128)]
292 /// #![feature(float_exact_integer_constants)]
293 /// # // FIXME(#152635): Float rounding on `i586` does not adhere to IEEE 754
294 /// # #[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))] {
295 /// # #[cfg(target_has_reliable_f128)] {
296 /// let max_exact_int = f128::MAX_EXACT_INTEGER;
297 /// assert_eq!(max_exact_int, max_exact_int as f128 as i128);
298 /// assert_eq!(max_exact_int + 1, (max_exact_int + 1) as f128 as i128);
299 /// assert_ne!(max_exact_int + 2, (max_exact_int + 2) as f128 as i128);
300 ///
301 /// // Beyond `f128::MAX_EXACT_INTEGER`, multiple integers can map to one float value
302 /// assert_eq!((max_exact_int + 1) as f128, (max_exact_int + 2) as f128);
303 /// # }}
304 /// ```
305 // #[unstable(feature = "f128", issue = "116909")]
306 #[unstable(feature = "float_exact_integer_constants", issue = "152466")]
307 pub const MAX_EXACT_INTEGER: i128 = (1 << Self::MANTISSA_DIGITS) - 1;
308
309 /// Minimum integer that can be represented exactly in an [`f128`] value,
310 /// with no other integer converting to the same floating point value.
311 ///
312 /// For an integer `x` which satisfies `MIN_EXACT_INTEGER <= x <= MAX_EXACT_INTEGER`,
313 /// there is a "one-to-one" mapping between [`i128`] and [`f128`] values.
314 /// `MAX_EXACT_INTEGER + 1` also converts losslessly to [`f128`] and back to
315 /// [`i128`], but `MAX_EXACT_INTEGER + 2` converts to the same [`f128`] value
316 /// (and back to `MAX_EXACT_INTEGER + 1` as an integer) so there is not a
317 /// "one-to-one" mapping.
318 ///
319 /// This constant is equivalent to `-MAX_EXACT_INTEGER`.
320 ///
321 /// [`MAX_EXACT_INTEGER`]: f128::MAX_EXACT_INTEGER
322 /// [`MIN_EXACT_INTEGER`]: f128::MIN_EXACT_INTEGER
323 /// ```
324 /// #![feature(f128)]
325 /// #![feature(float_exact_integer_constants)]
326 /// # // FIXME(#152635): Float rounding on `i586` does not adhere to IEEE 754
327 /// # #[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))] {
328 /// # #[cfg(target_has_reliable_f128)] {
329 /// let min_exact_int = f128::MIN_EXACT_INTEGER;
330 /// assert_eq!(min_exact_int, min_exact_int as f128 as i128);
331 /// assert_eq!(min_exact_int - 1, (min_exact_int - 1) as f128 as i128);
332 /// assert_ne!(min_exact_int - 2, (min_exact_int - 2) as f128 as i128);
333 ///
334 /// // Below `f128::MIN_EXACT_INTEGER`, multiple integers can map to one float value
335 /// assert_eq!((min_exact_int - 1) as f128, (min_exact_int - 2) as f128);
336 /// # }}
337 /// ```
338 // #[unstable(feature = "f128", issue = "116909")]
339 #[unstable(feature = "float_exact_integer_constants", issue = "152466")]
340 pub const MIN_EXACT_INTEGER: i128 = -Self::MAX_EXACT_INTEGER;
341
278342 /// Sign bit
279343 pub(crate) const SIGN_MASK: u128 = 0x8000_0000_0000_0000_0000_0000_0000_0000;
280344
library/core/src/num/f16.rs+64
......@@ -269,6 +269,70 @@ impl f16 {
269269 #[unstable(feature = "f16", issue = "116909")]
270270 pub const NEG_INFINITY: f16 = -1.0_f16 / 0.0_f16;
271271
272 /// Maximum integer that can be represented exactly in an [`f16`] value,
273 /// with no other integer converting to the same floating point value.
274 ///
275 /// For an integer `x` which satisfies `MIN_EXACT_INTEGER <= x <= MAX_EXACT_INTEGER`,
276 /// there is a "one-to-one" mapping between [`i16`] and [`f16`] values.
277 /// `MAX_EXACT_INTEGER + 1` also converts losslessly to [`f16`] and back to
278 /// [`i16`], but `MAX_EXACT_INTEGER + 2` converts to the same [`f16`] value
279 /// (and back to `MAX_EXACT_INTEGER + 1` as an integer) so there is not a
280 /// "one-to-one" mapping.
281 ///
282 /// [`MAX_EXACT_INTEGER`]: f16::MAX_EXACT_INTEGER
283 /// [`MIN_EXACT_INTEGER`]: f16::MIN_EXACT_INTEGER
284 /// ```
285 /// #![feature(f16)]
286 /// #![feature(float_exact_integer_constants)]
287 /// # // FIXME(#152635): Float rounding on `i586` does not adhere to IEEE 754
288 /// # #[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))] {
289 /// # #[cfg(target_has_reliable_f16)] {
290 /// let max_exact_int = f16::MAX_EXACT_INTEGER;
291 /// assert_eq!(max_exact_int, max_exact_int as f16 as i16);
292 /// assert_eq!(max_exact_int + 1, (max_exact_int + 1) as f16 as i16);
293 /// assert_ne!(max_exact_int + 2, (max_exact_int + 2) as f16 as i16);
294 ///
295 /// // Beyond `f16::MAX_EXACT_INTEGER`, multiple integers can map to one float value
296 /// assert_eq!((max_exact_int + 1) as f16, (max_exact_int + 2) as f16);
297 /// # }}
298 /// ```
299 // #[unstable(feature = "f16", issue = "116909")]
300 #[unstable(feature = "float_exact_integer_constants", issue = "152466")]
301 pub const MAX_EXACT_INTEGER: i16 = (1 << Self::MANTISSA_DIGITS) - 1;
302
303 /// Minimum integer that can be represented exactly in an [`f16`] value,
304 /// with no other integer converting to the same floating point value.
305 ///
306 /// For an integer `x` which satisfies `MIN_EXACT_INTEGER <= x <= MAX_EXACT_INTEGER`,
307 /// there is a "one-to-one" mapping between [`i16`] and [`f16`] values.
308 /// `MAX_EXACT_INTEGER + 1` also converts losslessly to [`f16`] and back to
309 /// [`i16`], but `MAX_EXACT_INTEGER + 2` converts to the same [`f16`] value
310 /// (and back to `MAX_EXACT_INTEGER + 1` as an integer) so there is not a
311 /// "one-to-one" mapping.
312 ///
313 /// This constant is equivalent to `-MAX_EXACT_INTEGER`.
314 ///
315 /// [`MAX_EXACT_INTEGER`]: f16::MAX_EXACT_INTEGER
316 /// [`MIN_EXACT_INTEGER`]: f16::MIN_EXACT_INTEGER
317 /// ```
318 /// #![feature(f16)]
319 /// #![feature(float_exact_integer_constants)]
320 /// # // FIXME(#152635): Float rounding on `i586` does not adhere to IEEE 754
321 /// # #[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))] {
322 /// # #[cfg(target_has_reliable_f16)] {
323 /// let min_exact_int = f16::MIN_EXACT_INTEGER;
324 /// assert_eq!(min_exact_int, min_exact_int as f16 as i16);
325 /// assert_eq!(min_exact_int - 1, (min_exact_int - 1) as f16 as i16);
326 /// assert_ne!(min_exact_int - 2, (min_exact_int - 2) as f16 as i16);
327 ///
328 /// // Below `f16::MIN_EXACT_INTEGER`, multiple integers can map to one float value
329 /// assert_eq!((min_exact_int - 1) as f16, (min_exact_int - 2) as f16);
330 /// # }}
331 /// ```
332 // #[unstable(feature = "f16", issue = "116909")]
333 #[unstable(feature = "float_exact_integer_constants", issue = "152466")]
334 pub const MIN_EXACT_INTEGER: i16 = -Self::MAX_EXACT_INTEGER;
335
272336 /// Sign bit
273337 pub(crate) const SIGN_MASK: u16 = 0x8000;
274338
library/core/src/num/f32.rs+58
......@@ -513,6 +513,64 @@ impl f32 {
513513 #[stable(feature = "assoc_int_consts", since = "1.43.0")]
514514 pub const NEG_INFINITY: f32 = -1.0_f32 / 0.0_f32;
515515
516 /// Maximum integer that can be represented exactly in an [`f32`] value,
517 /// with no other integer converting to the same floating point value.
518 ///
519 /// For an integer `x` which satisfies `MIN_EXACT_INTEGER <= x <= MAX_EXACT_INTEGER`,
520 /// there is a "one-to-one" mapping between [`i32`] and [`f32`] values.
521 /// `MAX_EXACT_INTEGER + 1` also converts losslessly to [`f32`] and back to
522 /// [`i32`], but `MAX_EXACT_INTEGER + 2` converts to the same [`f32`] value
523 /// (and back to `MAX_EXACT_INTEGER + 1` as an integer) so there is not a
524 /// "one-to-one" mapping.
525 ///
526 /// [`MAX_EXACT_INTEGER`]: f32::MAX_EXACT_INTEGER
527 /// [`MIN_EXACT_INTEGER`]: f32::MIN_EXACT_INTEGER
528 /// ```
529 /// #![feature(float_exact_integer_constants)]
530 /// # // FIXME(#152635): Float rounding on `i586` does not adhere to IEEE 754
531 /// # #[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))] {
532 /// let max_exact_int = f32::MAX_EXACT_INTEGER;
533 /// assert_eq!(max_exact_int, max_exact_int as f32 as i32);
534 /// assert_eq!(max_exact_int + 1, (max_exact_int + 1) as f32 as i32);
535 /// assert_ne!(max_exact_int + 2, (max_exact_int + 2) as f32 as i32);
536 ///
537 /// // Beyond `f32::MAX_EXACT_INTEGER`, multiple integers can map to one float value
538 /// assert_eq!((max_exact_int + 1) as f32, (max_exact_int + 2) as f32);
539 /// # }
540 /// ```
541 #[unstable(feature = "float_exact_integer_constants", issue = "152466")]
542 pub const MAX_EXACT_INTEGER: i32 = (1 << Self::MANTISSA_DIGITS) - 1;
543
544 /// Minimum integer that can be represented exactly in an [`f32`] value,
545 /// with no other integer converting to the same floating point value.
546 ///
547 /// For an integer `x` which satisfies `MIN_EXACT_INTEGER <= x <= MAX_EXACT_INTEGER`,
548 /// there is a "one-to-one" mapping between [`i32`] and [`f32`] values.
549 /// `MAX_EXACT_INTEGER + 1` also converts losslessly to [`f32`] and back to
550 /// [`i32`], but `MAX_EXACT_INTEGER + 2` converts to the same [`f32`] value
551 /// (and back to `MAX_EXACT_INTEGER + 1` as an integer) so there is not a
552 /// "one-to-one" mapping.
553 ///
554 /// This constant is equivalent to `-MAX_EXACT_INTEGER`.
555 ///
556 /// [`MAX_EXACT_INTEGER`]: f32::MAX_EXACT_INTEGER
557 /// [`MIN_EXACT_INTEGER`]: f32::MIN_EXACT_INTEGER
558 /// ```
559 /// #![feature(float_exact_integer_constants)]
560 /// # // FIXME(#152635): Float rounding on `i586` does not adhere to IEEE 754
561 /// # #[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))] {
562 /// let min_exact_int = f32::MIN_EXACT_INTEGER;
563 /// assert_eq!(min_exact_int, min_exact_int as f32 as i32);
564 /// assert_eq!(min_exact_int - 1, (min_exact_int - 1) as f32 as i32);
565 /// assert_ne!(min_exact_int - 2, (min_exact_int - 2) as f32 as i32);
566 ///
567 /// // Below `f32::MIN_EXACT_INTEGER`, multiple integers can map to one float value
568 /// assert_eq!((min_exact_int - 1) as f32, (min_exact_int - 2) as f32);
569 /// # }
570 /// ```
571 #[unstable(feature = "float_exact_integer_constants", issue = "152466")]
572 pub const MIN_EXACT_INTEGER: i32 = -Self::MAX_EXACT_INTEGER;
573
516574 /// Sign bit
517575 pub(crate) const SIGN_MASK: u32 = 0x8000_0000;
518576
library/core/src/num/f64.rs+58
......@@ -512,6 +512,64 @@ impl f64 {
512512 #[stable(feature = "assoc_int_consts", since = "1.43.0")]
513513 pub const NEG_INFINITY: f64 = -1.0_f64 / 0.0_f64;
514514
515 /// Maximum integer that can be represented exactly in an [`f64`] value,
516 /// with no other integer converting to the same floating point value.
517 ///
518 /// For an integer `x` which satisfies `MIN_EXACT_INTEGER <= x <= MAX_EXACT_INTEGER`,
519 /// there is a "one-to-one" mapping between [`i64`] and [`f64`] values.
520 /// `MAX_EXACT_INTEGER + 1` also converts losslessly to [`f64`] and back to
521 /// [`i64`], but `MAX_EXACT_INTEGER + 2` converts to the same [`f64`] value
522 /// (and back to `MAX_EXACT_INTEGER + 1` as an integer) so there is not a
523 /// "one-to-one" mapping.
524 ///
525 /// [`MAX_EXACT_INTEGER`]: f64::MAX_EXACT_INTEGER
526 /// [`MIN_EXACT_INTEGER`]: f64::MIN_EXACT_INTEGER
527 /// ```
528 /// #![feature(float_exact_integer_constants)]
529 /// # // FIXME(#152635): Float rounding on `i586` does not adhere to IEEE 754
530 /// # #[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))] {
531 /// let max_exact_int = f64::MAX_EXACT_INTEGER;
532 /// assert_eq!(max_exact_int, max_exact_int as f64 as i64);
533 /// assert_eq!(max_exact_int + 1, (max_exact_int + 1) as f64 as i64);
534 /// assert_ne!(max_exact_int + 2, (max_exact_int + 2) as f64 as i64);
535 ///
536 /// // Beyond `f64::MAX_EXACT_INTEGER`, multiple integers can map to one float value
537 /// assert_eq!((max_exact_int + 1) as f64, (max_exact_int + 2) as f64);
538 /// # }
539 /// ```
540 #[unstable(feature = "float_exact_integer_constants", issue = "152466")]
541 pub const MAX_EXACT_INTEGER: i64 = (1 << Self::MANTISSA_DIGITS) - 1;
542
543 /// Minimum integer that can be represented exactly in an [`f64`] value,
544 /// with no other integer converting to the same floating point value.
545 ///
546 /// For an integer `x` which satisfies `MIN_EXACT_INTEGER <= x <= MAX_EXACT_INTEGER`,
547 /// there is a "one-to-one" mapping between [`i64`] and [`f64`] values.
548 /// `MAX_EXACT_INTEGER + 1` also converts losslessly to [`f64`] and back to
549 /// [`i64`], but `MAX_EXACT_INTEGER + 2` converts to the same [`f64`] value
550 /// (and back to `MAX_EXACT_INTEGER + 1` as an integer) so there is not a
551 /// "one-to-one" mapping.
552 ///
553 /// This constant is equivalent to `-MAX_EXACT_INTEGER`.
554 ///
555 /// [`MAX_EXACT_INTEGER`]: f64::MAX_EXACT_INTEGER
556 /// [`MIN_EXACT_INTEGER`]: f64::MIN_EXACT_INTEGER
557 /// ```
558 /// #![feature(float_exact_integer_constants)]
559 /// # // FIXME(#152635): Float rounding on `i586` does not adhere to IEEE 754
560 /// # #[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))] {
561 /// let min_exact_int = f64::MIN_EXACT_INTEGER;
562 /// assert_eq!(min_exact_int, min_exact_int as f64 as i64);
563 /// assert_eq!(min_exact_int - 1, (min_exact_int - 1) as f64 as i64);
564 /// assert_ne!(min_exact_int - 2, (min_exact_int - 2) as f64 as i64);
565 ///
566 /// // Below `f64::MIN_EXACT_INTEGER`, multiple integers can map to one float value
567 /// assert_eq!((min_exact_int - 1) as f64, (min_exact_int - 2) as f64);
568 /// # }
569 /// ```
570 #[unstable(feature = "float_exact_integer_constants", issue = "152466")]
571 pub const MIN_EXACT_INTEGER: i64 = -Self::MAX_EXACT_INTEGER;
572
515573 /// Sign bit
516574 pub(crate) const SIGN_MASK: u64 = 0x8000_0000_0000_0000;
517575
library/coretests/tests/floats/mod.rs+93
......@@ -5,6 +5,8 @@ trait TestableFloat: Sized {
55 const BITS: u32;
66 /// Unsigned int with the same size, for converting to/from bits.
77 type Int;
8 /// Signed int with the same size.
9 type SInt;
810 /// Set the default tolerance for float comparison based on the type.
911 const APPROX: Self;
1012 /// Allow looser tolerance for f32 on miri
......@@ -61,6 +63,7 @@ trait TestableFloat: Sized {
6163impl TestableFloat for f16 {
6264 const BITS: u32 = 16;
6365 type Int = u16;
66 type SInt = i16;
6467 const APPROX: Self = 1e-3;
6568 const POWF_APPROX: Self = 5e-1;
6669 const _180_TO_RADIANS_APPROX: Self = 1e-2;
......@@ -101,6 +104,7 @@ impl TestableFloat for f16 {
101104impl TestableFloat for f32 {
102105 const BITS: u32 = 32;
103106 type Int = u32;
107 type SInt = i32;
104108 const APPROX: Self = 1e-6;
105109 /// Miri adds some extra errors to float functions; make sure the tests still pass.
106110 /// These values are purely used as a canary to test against and are thus not a stable guarantee Rust provides.
......@@ -143,6 +147,7 @@ impl TestableFloat for f32 {
143147impl TestableFloat for f64 {
144148 const BITS: u32 = 64;
145149 type Int = u64;
150 type SInt = i64;
146151 const APPROX: Self = 1e-6;
147152 const GAMMA_APPROX_LOOSE: Self = 1e-4;
148153 const LNGAMMA_APPROX_LOOSE: Self = 1e-4;
......@@ -170,6 +175,7 @@ impl TestableFloat for f64 {
170175impl TestableFloat for f128 {
171176 const BITS: u32 = 128;
172177 type Int = u128;
178 type SInt = i128;
173179 const APPROX: Self = 1e-9;
174180 const EXP_APPROX: Self = 1e-12;
175181 const LN_APPROX: Self = 1e-12;
......@@ -2003,6 +2009,93 @@ float_test! {
20032009 }
20042010}
20052011
2012// Test the `float_exact_integer_constants` feature
2013float_test! {
2014 name: max_exact_integer_constant,
2015 attrs: {
2016 f16: #[cfg(any(miri, target_has_reliable_f16))],
2017 f128: #[cfg(any(miri, target_has_reliable_f128))],
2018 },
2019 test<Float> {
2020 // The maximum integer that converts to a unique floating point
2021 // value.
2022 const MAX_EXACT_INTEGER: <Float as TestableFloat>::SInt = Float::MAX_EXACT_INTEGER;
2023
2024 let max_minus_one = (MAX_EXACT_INTEGER - 1) as Float as <Float as TestableFloat>::SInt;
2025 let max_plus_one = (MAX_EXACT_INTEGER + 1) as Float as <Float as TestableFloat>::SInt;
2026 let max_plus_two = (MAX_EXACT_INTEGER + 2) as Float as <Float as TestableFloat>::SInt;
2027
2028 // This does an extra round trip back to float for the second operand in
2029 // order to print the results if there is a mismatch
2030 assert_biteq!((MAX_EXACT_INTEGER - 1) as Float, max_minus_one as Float);
2031 assert_biteq!(MAX_EXACT_INTEGER as Float, MAX_EXACT_INTEGER as Float as <Float as TestableFloat>::SInt as Float);
2032 assert_biteq!((MAX_EXACT_INTEGER + 1) as Float, max_plus_one as Float);
2033 // The first non-unique conversion, where `max_plus_two` roundtrips to
2034 // `max_plus_one`
2035 assert_biteq!((MAX_EXACT_INTEGER + 1) as Float, (MAX_EXACT_INTEGER + 2) as Float);
2036 assert_biteq!((MAX_EXACT_INTEGER + 2) as Float, max_plus_one as Float);
2037 assert_biteq!((MAX_EXACT_INTEGER + 2) as Float, max_plus_two as Float);
2038
2039 // Lossless roundtrips, for integers
2040 assert!(MAX_EXACT_INTEGER - 1 == max_minus_one);
2041 assert!(MAX_EXACT_INTEGER == MAX_EXACT_INTEGER as Float as <Float as TestableFloat>::SInt);
2042 assert!(MAX_EXACT_INTEGER + 1 == max_plus_one);
2043 // The first non-unique conversion, where `max_plus_two` roundtrips to
2044 // one less than the starting value
2045 assert!(MAX_EXACT_INTEGER + 2 != max_plus_two);
2046
2047 // max-1 | max+0 | max+1 | max+2
2048 // After roundtripping, +1 and +2 will equal each other
2049 assert!(max_minus_one != MAX_EXACT_INTEGER);
2050 assert!(MAX_EXACT_INTEGER != max_plus_one);
2051 assert!(max_plus_one == max_plus_two);
2052 }
2053}
2054
2055float_test! {
2056 name: min_exact_integer_constant,
2057 attrs: {
2058 f16: #[cfg(any(miri, target_has_reliable_f16))],
2059 f128: #[cfg(any(miri, target_has_reliable_f128))],
2060 },
2061 test<Float> {
2062 // The minimum integer that converts to a unique floating point
2063 // value.
2064 const MIN_EXACT_INTEGER: <Float as TestableFloat>::SInt = Float::MIN_EXACT_INTEGER;
2065
2066 // Same logic as the `max` test, but we work our way leftward
2067 // across the number line from (min_exact + 1) to (min_exact - 2).
2068 let min_plus_one = (MIN_EXACT_INTEGER + 1) as Float as <Float as TestableFloat>::SInt;
2069 let min_minus_one = (MIN_EXACT_INTEGER - 1) as Float as <Float as TestableFloat>::SInt;
2070 let min_minus_two = (MIN_EXACT_INTEGER - 2) as Float as <Float as TestableFloat>::SInt;
2071
2072 // This does an extra round trip back to float for the second operand in
2073 // order to print the results if there is a mismatch
2074 assert_biteq!((MIN_EXACT_INTEGER + 1) as Float, min_plus_one as Float);
2075 assert_biteq!(MIN_EXACT_INTEGER as Float, MIN_EXACT_INTEGER as Float as <Float as TestableFloat>::SInt as Float);
2076 assert_biteq!((MIN_EXACT_INTEGER - 1) as Float, min_minus_one as Float);
2077 // The first non-unique conversion, which roundtrips to one
2078 // greater than the starting value.
2079 assert_biteq!((MIN_EXACT_INTEGER - 1) as Float, (MIN_EXACT_INTEGER - 2) as Float);
2080 assert_biteq!((MIN_EXACT_INTEGER - 2) as Float, min_minus_one as Float);
2081 assert_biteq!((MIN_EXACT_INTEGER - 2) as Float, min_minus_two as Float);
2082
2083 // Lossless roundtrips, for integers
2084 assert!(MIN_EXACT_INTEGER + 1 == min_plus_one);
2085 assert!(MIN_EXACT_INTEGER == MIN_EXACT_INTEGER as Float as <Float as TestableFloat>::SInt);
2086 assert!(MIN_EXACT_INTEGER - 1 == min_minus_one);
2087 // The first non-unique conversion, which roundtrips to one
2088 // greater than the starting value.
2089 assert!(MIN_EXACT_INTEGER - 2 != min_minus_two);
2090
2091 // min-2 | min-1 | min | min+1
2092 // After roundtripping, -2 and -1 will equal each other.
2093 assert!(min_plus_one != MIN_EXACT_INTEGER);
2094 assert!(MIN_EXACT_INTEGER != min_minus_one);
2095 assert!(min_minus_one == min_minus_two);
2096 }
2097}
2098
20062099// FIXME(f128): Uncomment and adapt these tests once the From<{u64,i64}> impls are added.
20072100// float_test! {
20082101// name: from_u64_i64,
library/coretests/tests/lib.rs+1
......@@ -53,6 +53,7 @@
5353#![feature(f128)]
5454#![feature(float_algebraic)]
5555#![feature(float_bits_const)]
56#![feature(float_exact_integer_constants)]
5657#![feature(float_gamma)]
5758#![feature(float_minimum_maximum)]
5859#![feature(flt2dec)]
rust-bors.toml+6-6
......@@ -25,7 +25,7 @@ labels_blocking_approval = [
2525 "S-waiting-on-t-rustdoc-frontend",
2626 "S-waiting-on-t-clippy",
2727 # PR manually set to blocked
28 "S-blocked"
28 "S-blocked",
2929]
3030
3131# If CI runs quicker than this duration, consider it to be a failure
......@@ -41,7 +41,7 @@ approved = [
4141 "-S-waiting-on-author",
4242 "-S-waiting-on-crater",
4343 "-S-waiting-on-review",
44 "-S-waiting-on-team"
44 "-S-waiting-on-team",
4545]
4646unapproved = [
4747 "+S-waiting-on-author",
......@@ -49,16 +49,16 @@ unapproved = [
4949 "-S-waiting-on-bors",
5050 "-S-waiting-on-crater",
5151 "-S-waiting-on-review",
52 "-S-waiting-on-team"
52 "-S-waiting-on-team",
5353]
5454try_failed = [
5555 "+S-waiting-on-author",
5656 "-S-waiting-on-review",
57 "-S-waiting-on-crater"
57 "-S-waiting-on-crater",
5858]
5959auto_build_succeeded = [
6060 "+merged-by-bors",
61 "-S-waiting-on-bors"
61 "-S-waiting-on-bors",
6262]
6363auto_build_failed = [
6464 "+S-waiting-on-review",
......@@ -66,5 +66,5 @@ auto_build_failed = [
6666 "-S-waiting-on-bors",
6767 "-S-waiting-on-author",
6868 "-S-waiting-on-crater",
69 "-S-waiting-on-team"
69 "-S-waiting-on-team",
7070]
src/bootstrap/src/core/builder/cli_paths/snapshots/x_bench.snap-1
......@@ -79,7 +79,6 @@ expression: bench
7979 - Set({bench::compiler/rustc_public})
8080 - Set({bench::compiler/rustc_public_bridge})
8181 - Set({bench::compiler/rustc_query_impl})
82 - Set({bench::compiler/rustc_query_system})
8382 - Set({bench::compiler/rustc_resolve})
8483 - Set({bench::compiler/rustc_sanitizers})
8584 - Set({bench::compiler/rustc_serialize})
src/bootstrap/src/core/builder/cli_paths/snapshots/x_build_compiler.snap-1
......@@ -61,7 +61,6 @@ expression: build compiler
6161 - Set({build::compiler/rustc_public})
6262 - Set({build::compiler/rustc_public_bridge})
6363 - Set({build::compiler/rustc_query_impl})
64 - Set({build::compiler/rustc_query_system})
6564 - Set({build::compiler/rustc_resolve})
6665 - Set({build::compiler/rustc_sanitizers})
6766 - Set({build::compiler/rustc_serialize})
src/bootstrap/src/core/builder/cli_paths/snapshots/x_check.snap-1
......@@ -63,7 +63,6 @@ expression: check
6363 - Set({check::compiler/rustc_public})
6464 - Set({check::compiler/rustc_public_bridge})
6565 - Set({check::compiler/rustc_query_impl})
66 - Set({check::compiler/rustc_query_system})
6766 - Set({check::compiler/rustc_resolve})
6867 - Set({check::compiler/rustc_sanitizers})
6968 - Set({check::compiler/rustc_serialize})
src/bootstrap/src/core/builder/cli_paths/snapshots/x_check_compiler.snap-1
......@@ -63,7 +63,6 @@ expression: check compiler
6363 - Set({check::compiler/rustc_public})
6464 - Set({check::compiler/rustc_public_bridge})
6565 - Set({check::compiler/rustc_query_impl})
66 - Set({check::compiler/rustc_query_system})
6766 - Set({check::compiler/rustc_resolve})
6867 - Set({check::compiler/rustc_sanitizers})
6968 - Set({check::compiler/rustc_serialize})
src/bootstrap/src/core/builder/cli_paths/snapshots/x_check_compiletest_include_default_paths.snap-1
......@@ -63,7 +63,6 @@ expression: check compiletest --include-default-paths
6363 - Set({check::compiler/rustc_public})
6464 - Set({check::compiler/rustc_public_bridge})
6565 - Set({check::compiler/rustc_query_impl})
66 - Set({check::compiler/rustc_query_system})
6766 - Set({check::compiler/rustc_resolve})
6867 - Set({check::compiler/rustc_sanitizers})
6968 - Set({check::compiler/rustc_serialize})
src/bootstrap/src/core/builder/cli_paths/snapshots/x_clippy.snap-1
......@@ -78,7 +78,6 @@ expression: clippy
7878 - Set({clippy::compiler/rustc_public})
7979 - Set({clippy::compiler/rustc_public_bridge})
8080 - Set({clippy::compiler/rustc_query_impl})
81 - Set({clippy::compiler/rustc_query_system})
8281 - Set({clippy::compiler/rustc_resolve})
8382 - Set({clippy::compiler/rustc_sanitizers})
8483 - Set({clippy::compiler/rustc_serialize})
src/bootstrap/src/core/builder/cli_paths/snapshots/x_fix.snap-1
......@@ -63,7 +63,6 @@ expression: fix
6363 - Set({fix::compiler/rustc_public})
6464 - Set({fix::compiler/rustc_public_bridge})
6565 - Set({fix::compiler/rustc_query_impl})
66 - Set({fix::compiler/rustc_query_system})
6766 - Set({fix::compiler/rustc_resolve})
6867 - Set({fix::compiler/rustc_sanitizers})
6968 - Set({fix::compiler/rustc_serialize})
src/bootstrap/src/core/builder/cli_paths/snapshots/x_test.snap-1
......@@ -129,7 +129,6 @@ expression: test
129129 - Set({test::compiler/rustc_public})
130130 - Set({test::compiler/rustc_public_bridge})
131131 - Set({test::compiler/rustc_query_impl})
132 - Set({test::compiler/rustc_query_system})
133132 - Set({test::compiler/rustc_resolve})
134133 - Set({test::compiler/rustc_sanitizers})
135134 - Set({test::compiler/rustc_serialize})
src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_coverage.snap-1
......@@ -128,7 +128,6 @@ expression: test --skip=coverage
128128 - Set({test::compiler/rustc_public})
129129 - Set({test::compiler/rustc_public_bridge})
130130 - Set({test::compiler/rustc_query_impl})
131 - Set({test::compiler/rustc_query_system})
132131 - Set({test::compiler/rustc_resolve})
133132 - Set({test::compiler/rustc_sanitizers})
134133 - Set({test::compiler/rustc_serialize})
src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_tests.snap-1
......@@ -92,7 +92,6 @@ expression: test --skip=tests
9292 - Set({test::compiler/rustc_public})
9393 - Set({test::compiler/rustc_public_bridge})
9494 - Set({test::compiler/rustc_query_impl})
95 - Set({test::compiler/rustc_query_system})
9695 - Set({test::compiler/rustc_resolve})
9796 - Set({test::compiler/rustc_sanitizers})
9897 - Set({test::compiler/rustc_serialize})
src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_tests_etc.snap-1
......@@ -72,7 +72,6 @@ expression: test --skip=tests --skip=coverage-map --skip=coverage-run --skip=lib
7272 - Set({test::compiler/rustc_public})
7373 - Set({test::compiler/rustc_public_bridge})
7474 - Set({test::compiler/rustc_query_impl})
75 - Set({test::compiler/rustc_query_system})
7675 - Set({test::compiler/rustc_resolve})
7776 - Set({test::compiler/rustc_sanitizers})
7877 - Set({test::compiler/rustc_serialize})
src/bootstrap/src/core/builder/tests.rs+7-7
......@@ -1815,7 +1815,7 @@ mod snapshot {
18151815 insta::assert_snapshot!(
18161816 ctx.config("check")
18171817 .path("compiler")
1818 .render_steps(), @"[check] rustc 0 <host> -> rustc 1 <host> (74 crates)");
1818 .render_steps(), @"[check] rustc 0 <host> -> rustc 1 <host> (73 crates)");
18191819 }
18201820
18211821 #[test]
......@@ -1841,7 +1841,7 @@ mod snapshot {
18411841 ctx.config("check")
18421842 .path("compiler")
18431843 .stage(1)
1844 .render_steps(), @"[check] rustc 0 <host> -> rustc 1 <host> (74 crates)");
1844 .render_steps(), @"[check] rustc 0 <host> -> rustc 1 <host> (73 crates)");
18451845 }
18461846
18471847 #[test]
......@@ -1851,11 +1851,11 @@ mod snapshot {
18511851 ctx.config("check")
18521852 .path("compiler")
18531853 .stage(2)
1854 .render_steps(), @r"
1854 .render_steps(), @"
18551855 [build] llvm <host>
18561856 [build] rustc 0 <host> -> rustc 1 <host>
18571857 [build] rustc 1 <host> -> std 1 <host>
1858 [check] rustc 1 <host> -> rustc 2 <host> (74 crates)
1858 [check] rustc 1 <host> -> rustc 2 <host> (73 crates)
18591859 ");
18601860 }
18611861
......@@ -1866,12 +1866,12 @@ mod snapshot {
18661866 ctx.config("check")
18671867 .targets(&[TEST_TRIPLE_1])
18681868 .hosts(&[TEST_TRIPLE_1])
1869 .render_steps(), @r"
1869 .render_steps(), @"
18701870 [build] llvm <host>
18711871 [build] rustc 0 <host> -> rustc 1 <host>
18721872 [build] rustc 1 <host> -> std 1 <host>
18731873 [check] rustc 1 <host> -> std 1 <target1>
1874 [check] rustc 1 <host> -> rustc 2 <target1> (74 crates)
1874 [check] rustc 1 <host> -> rustc 2 <target1> (73 crates)
18751875 [check] rustc 1 <host> -> rustc 2 <target1>
18761876 [check] rustc 1 <host> -> Rustdoc 2 <target1>
18771877 [check] rustc 1 <host> -> rustc_codegen_cranelift 2 <target1>
......@@ -1967,7 +1967,7 @@ mod snapshot {
19671967 ctx.config("check")
19681968 .paths(&["library", "compiler"])
19691969 .args(&args)
1970 .render_steps(), @"[check] rustc 0 <host> -> rustc 1 <host> (74 crates)");
1970 .render_steps(), @"[check] rustc 0 <host> -> rustc 1 <host> (73 crates)");
19711971 }
19721972
19731973 #[test]
src/doc/rustc-dev-guide/src/queries/incremental-compilation-in-detail.md+2-2
......@@ -178,7 +178,7 @@ fn try_mark_green(tcx, current_node) -> bool {
178178
179179> NOTE:
180180> The actual implementation can be found in
181> [`compiler/rustc_query_system/src/dep_graph/graph.rs`][try_mark_green]
181> [`compiler/rustc_middle/src/dep_graph/graph.rs`][try_mark_green]
182182
183183By using red-green marking we can avoid the devastating cumulative effect of
184184having false positives during change detection. Whenever a query is executed
......@@ -534,4 +534,4 @@ information.
534534
535535
536536[query-model]: ./query-evaluation-model-in-detail.html
537[try_mark_green]: https://doc.rust-lang.org/nightly/nightly-rustc/src/rustc_query_system/dep_graph/graph.rs.html
537[try_mark_green]: https://doc.rust-lang.org/nightly/nightly-rustc/src/rustc_middle/dep_graph/graph.rs.html
src/librustdoc/clean/mod.rs+13-11
......@@ -1222,11 +1222,11 @@ fn clean_trait_item<'tcx>(trait_item: &hir::TraitItem<'tcx>, cx: &mut DocContext
12221222 }
12231223 hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => {
12241224 let m = clean_function(cx, sig, trait_item.generics, ParamsSrc::Body(body));
1225 MethodItem(m, None)
1225 MethodItem(m, Defaultness::from_trait_item(trait_item.defaultness))
12261226 }
12271227 hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Required(idents)) => {
12281228 let m = clean_function(cx, sig, trait_item.generics, ParamsSrc::Idents(idents));
1229 RequiredMethodItem(m)
1229 RequiredMethodItem(m, Defaultness::from_trait_item(trait_item.defaultness))
12301230 }
12311231 hir::TraitItemKind::Type(bounds, Some(default)) => {
12321232 let generics = enter_impl_trait(cx, |cx| clean_generics(trait_item.generics, cx));
......@@ -1271,7 +1271,7 @@ pub(crate) fn clean_impl_item<'tcx>(
12711271 hir::ImplItemImplKind::Inherent { .. } => hir::Defaultness::Final,
12721272 hir::ImplItemImplKind::Trait { defaultness, .. } => defaultness,
12731273 };
1274 MethodItem(m, Some(defaultness))
1274 MethodItem(m, Defaultness::from_impl_item(defaultness))
12751275 }
12761276 hir::ImplItemKind::Type(hir_ty) => {
12771277 let type_ = clean_ty(hir_ty, cx);
......@@ -1353,18 +1353,20 @@ pub(crate) fn clean_middle_assoc_item(assoc_item: &ty::AssocItem, cx: &mut DocCo
13531353 }
13541354 }
13551355
1356 let provided = match assoc_item.container {
1357 ty::AssocContainer::InherentImpl | ty::AssocContainer::TraitImpl(_) => true,
1358 ty::AssocContainer::Trait => assoc_item.defaultness(tcx).has_value(),
1356 let defaultness = assoc_item.defaultness(tcx);
1357 let (provided, defaultness) = match assoc_item.container {
1358 ty::AssocContainer::Trait => {
1359 (defaultness.has_value(), Defaultness::from_trait_item(defaultness))
1360 }
1361 ty::AssocContainer::InherentImpl | ty::AssocContainer::TraitImpl(_) => {
1362 (true, Defaultness::from_impl_item(defaultness))
1363 }
13591364 };
1365
13601366 if provided {
1361 let defaultness = match assoc_item.container {
1362 ty::AssocContainer::TraitImpl(_) => Some(assoc_item.defaultness(tcx)),
1363 ty::AssocContainer::InherentImpl | ty::AssocContainer::Trait => None,
1364 };
13651367 MethodItem(item, defaultness)
13661368 } else {
1367 RequiredMethodItem(item)
1369 RequiredMethodItem(item, defaultness)
13681370 }
13691371 }
13701372 ty::AssocKind::Type { .. } => {
src/librustdoc/clean/types.rs+33-10
......@@ -61,6 +61,29 @@ pub(crate) enum ItemId {
6161 Blanket { impl_id: DefId, for_: DefId },
6262}
6363
64#[derive(Debug, Copy, Clone, PartialEq, Eq)]
65pub(crate) enum Defaultness {
66 Implicit,
67 Default,
68 Final,
69}
70
71impl Defaultness {
72 pub(crate) fn from_trait_item(defaultness: hir::Defaultness) -> Self {
73 match defaultness {
74 hir::Defaultness::Default { .. } => Self::Implicit,
75 hir::Defaultness::Final => Self::Final,
76 }
77 }
78
79 pub(crate) fn from_impl_item(defaultness: hir::Defaultness) -> Self {
80 match defaultness {
81 hir::Defaultness::Default { .. } => Self::Default,
82 hir::Defaultness::Final => Self::Implicit,
83 }
84 }
85}
86
6487impl ItemId {
6588 #[inline]
6689 pub(crate) fn is_local(self) -> bool {
......@@ -707,12 +730,12 @@ impl Item {
707730 ItemType::from(self)
708731 }
709732
710 pub(crate) fn is_default(&self) -> bool {
733 pub(crate) fn defaultness(&self) -> Option<Defaultness> {
711734 match self.kind {
712 ItemKind::MethodItem(_, Some(defaultness)) => {
713 defaultness.has_value() && !defaultness.is_final()
735 ItemKind::MethodItem(_, defaultness) | ItemKind::RequiredMethodItem(_, defaultness) => {
736 Some(defaultness)
714737 }
715 _ => false,
738 _ => None,
716739 }
717740 }
718741
......@@ -774,8 +797,8 @@ impl Item {
774797 }
775798 }
776799 ItemKind::FunctionItem(_)
777 | ItemKind::MethodItem(_, _)
778 | ItemKind::RequiredMethodItem(_) => {
800 | ItemKind::MethodItem(..)
801 | ItemKind::RequiredMethodItem(..) => {
779802 let def_id = self.def_id().unwrap();
780803 build_fn_header(def_id, tcx, tcx.asyncness(def_id))
781804 }
......@@ -859,11 +882,11 @@ pub(crate) enum ItemKind {
859882 TraitAliasItem(TraitAlias),
860883 ImplItem(Box<Impl>),
861884 /// A required method in a trait declaration meaning it's only a function signature.
862 RequiredMethodItem(Box<Function>),
885 RequiredMethodItem(Box<Function>, Defaultness),
863886 /// A method in a trait impl or a provided method in a trait declaration.
864887 ///
865888 /// Compared to [RequiredMethodItem], it also contains a method body.
866 MethodItem(Box<Function>, Option<hir::Defaultness>),
889 MethodItem(Box<Function>, Defaultness),
867890 StructFieldItem(Type),
868891 VariantItem(Variant),
869892 /// `fn`s from an extern block
......@@ -921,8 +944,8 @@ impl ItemKind {
921944 | StaticItem(_)
922945 | ConstantItem(_)
923946 | TraitAliasItem(_)
924 | RequiredMethodItem(_)
925 | MethodItem(_, _)
947 | RequiredMethodItem(..)
948 | MethodItem(..)
926949 | StructFieldItem(_)
927950 | ForeignFunctionItem(_, _)
928951 | ForeignStaticItem(_, _)
src/librustdoc/fold.rs+2-2
......@@ -82,8 +82,8 @@ pub(crate) trait DocFolder: Sized {
8282 | StaticItem(_)
8383 | ConstantItem(..)
8484 | TraitAliasItem(_)
85 | RequiredMethodItem(_)
86 | MethodItem(_, _)
85 | RequiredMethodItem(..)
86 | MethodItem(..)
8787 | StructFieldItem(_)
8888 | ForeignFunctionItem(..)
8989 | ForeignStaticItem(..)
src/librustdoc/html/format.rs-4
......@@ -1566,10 +1566,6 @@ pub(crate) fn print_abi_with_space(abi: ExternAbi) -> impl Display {
15661566 })
15671567}
15681568
1569pub(crate) fn print_default_space(v: bool) -> &'static str {
1570 if v { "default " } else { "" }
1571}
1572
15731569fn print_generic_arg(generic_arg: &clean::GenericArg, cx: &Context<'_>) -> impl Display {
15741570 fmt::from_fn(move |f| match generic_arg {
15751571 clean::GenericArg::Lifetime(lt) => f.write_str(print_lifetime(lt)),
src/librustdoc/html/render/mod.rs+21-49
......@@ -59,14 +59,14 @@ use rustc_hir::def_id::{DefId, DefIdSet};
5959use rustc_hir::{ConstStability, Mutability, RustcVersion, StabilityLevel, StableSince};
6060use rustc_middle::ty::print::PrintTraitRefExt;
6161use rustc_middle::ty::{self, TyCtxt};
62use rustc_span::DUMMY_SP;
6263use rustc_span::symbol::{Symbol, sym};
63use rustc_span::{BytePos, DUMMY_SP, FileName};
6464use tracing::{debug, info};
6565
6666pub(crate) use self::context::*;
6767pub(crate) use self::span_map::{LinkFromSrc, collect_spans_and_sources};
6868pub(crate) use self::write_shared::*;
69use crate::clean::{self, ItemId, RenderedLink};
69use crate::clean::{self, Defaultness, ItemId, RenderedLink};
7070use crate::display::{Joined as _, MaybeDisplay as _};
7171use crate::error::Error;
7272use crate::formats::Impl;
......@@ -75,8 +75,8 @@ use crate::formats::item_type::ItemType;
7575use crate::html::escape::Escape;
7676use crate::html::format::{
7777 Ending, HrefError, HrefInfo, PrintWithSpace, full_print_fn_decl, href, print_abi_with_space,
78 print_constness_with_space, print_default_space, print_generic_bounds, print_generics,
79 print_impl, print_path, print_type, print_where_clause, visibility_print_with_space,
78 print_constness_with_space, print_generic_bounds, print_generics, print_impl, print_path,
79 print_type, print_where_clause, visibility_print_with_space,
8080};
8181use crate::html::markdown::{
8282 HeadingOffset, IdMap, Markdown, MarkdownItemInfo, MarkdownSummaryLine,
......@@ -1110,7 +1110,11 @@ fn assoc_method(
11101110 let header = meth.fn_header(tcx).expect("Trying to get header from a non-function item");
11111111 let name = meth.name.as_ref().unwrap();
11121112 let vis = visibility_print_with_space(meth, cx).to_string();
1113 let defaultness = print_default_space(meth.is_default());
1113 let defaultness = match meth.defaultness().expect("Expected assoc method to have defaultness") {
1114 Defaultness::Implicit => "",
1115 Defaultness::Final => "final ",
1116 Defaultness::Default => "default ",
1117 };
11141118 // FIXME: Once https://github.com/rust-lang/rust/issues/143874 is implemented, we can remove
11151119 // this condition.
11161120 let constness = match render_mode {
......@@ -1261,7 +1265,7 @@ fn render_assoc_item(
12611265) -> impl fmt::Display {
12621266 fmt::from_fn(move |f| match &item.kind {
12631267 clean::StrippedItem(..) => Ok(()),
1264 clean::RequiredMethodItem(m) | clean::MethodItem(m, _) => {
1268 clean::RequiredMethodItem(m, _) | clean::MethodItem(m, _) => {
12651269 assoc_method(item, &m.generics, &m.decl, link, parent, cx, render_mode).fmt(f)
12661270 }
12671271 clean::RequiredAssocConstItem(generics, ty) => assoc_const(
......@@ -1586,7 +1590,7 @@ fn render_deref_methods(
15861590fn should_render_item(item: &clean::Item, deref_mut_: bool, tcx: TyCtxt<'_>) -> bool {
15871591 let self_type_opt = match item.kind {
15881592 clean::MethodItem(ref method, _) => method.decl.receiver_type(),
1589 clean::RequiredMethodItem(ref method) => method.decl.receiver_type(),
1593 clean::RequiredMethodItem(ref method, _) => method.decl.receiver_type(),
15901594 _ => None,
15911595 };
15921596
......@@ -1856,7 +1860,7 @@ fn render_impl(
18561860 deprecation_class = "";
18571861 }
18581862 match &item.kind {
1859 clean::MethodItem(..) | clean::RequiredMethodItem(_) => {
1863 clean::MethodItem(..) | clean::RequiredMethodItem(..) => {
18601864 // Only render when the method is not static or we allow static methods
18611865 if render_method_item {
18621866 let id = cx.derive_id(format!("{item_type}.{name}"));
......@@ -2034,7 +2038,9 @@ fn render_impl(
20342038 if !impl_.is_negative_trait_impl() {
20352039 for impl_item in &impl_.items {
20362040 match impl_item.kind {
2037 clean::MethodItem(..) | clean::RequiredMethodItem(_) => methods.push(impl_item),
2041 clean::MethodItem(..) | clean::RequiredMethodItem(..) => {
2042 methods.push(impl_item)
2043 }
20382044 clean::RequiredAssocTypeItem(..) | clean::AssocTypeItem(..) => {
20392045 assoc_types.push(impl_item)
20402046 }
......@@ -2779,46 +2785,12 @@ fn render_call_locations<W: fmt::Write>(
27792785 let needs_expansion = line_max - line_min > NUM_VISIBLE_LINES;
27802786 let locations_encoded = serde_json::to_string(&line_ranges).unwrap();
27812787
2782 let source_map = tcx.sess.source_map();
2783 let files = source_map.files();
2784 let local = tcx.sess.local_crate_source_file().unwrap();
2785
2786 let get_file_start_pos = || {
2787 let crate_src = local.clone().into_local_path()?;
2788 let abs_crate_src = crate_src.canonicalize().ok()?;
2789 let crate_root = abs_crate_src.parent()?.parent()?;
2790 let rel_path = path.strip_prefix(crate_root).ok()?;
2791 files
2792 .iter()
2793 .find(|file| match &file.name {
2794 FileName::Real(real) => real.local_path().map_or(false, |p| p == rel_path),
2795 _ => false,
2796 })
2797 .map(|file| file.start_pos)
2798 };
2799
2800 // Look for the example file in the source map if it exists, otherwise
2801 // return a span to the local crate's source file
2802 let Some(file_span) = get_file_start_pos()
2803 .or_else(|| {
2804 files
2805 .iter()
2806 .find(|file| match &file.name {
2807 FileName::Real(file_name) => file_name == &local,
2808 _ => false,
2809 })
2810 .map(|file| file.start_pos)
2811 })
2812 .map(|start_pos| {
2813 rustc_span::Span::with_root_ctxt(
2814 start_pos + BytePos(byte_min),
2815 start_pos + BytePos(byte_max),
2816 )
2817 })
2818 else {
2819 // if the fallback span can't be built, don't render the code for this example
2820 return false;
2821 };
2788 // For scraped examples, we don't need a real span from the SourceMap.
2789 // The URL is already provided in ScrapedInfo, and sources::print_src
2790 // will use that directly. We use DUMMY_SP as a placeholder.
2791 // Note: DUMMY_SP is safe here because href_from_span won't be called
2792 // for scraped examples.
2793 let file_span = rustc_span::DUMMY_SP;
28222794
28232795 let mut decoration_info = FxIndexMap::default();
28242796 decoration_info.insert("highlight focus", vec![byte_ranges.remove(0)]);
src/librustdoc/html/render/search_index.rs+1-1
......@@ -1977,7 +1977,7 @@ pub(crate) fn get_function_type_for_search(
19771977 clean::ForeignFunctionItem(ref f, _)
19781978 | clean::FunctionItem(ref f)
19791979 | clean::MethodItem(ref f, _)
1980 | clean::RequiredMethodItem(ref f) => {
1980 | clean::RequiredMethodItem(ref f, _) => {
19811981 get_fn_inputs_and_outputs(f, tcx, impl_or_trait_generics, cache)
19821982 }
19831983 clean::ConstantItem(ref c) => make_nullary_fn(&c.type_),
src/librustdoc/html/sources.rs+9-3
......@@ -344,9 +344,15 @@ pub(crate) fn print_src(
344344 lines += line_info.start_line as usize;
345345 }
346346 let code = fmt::from_fn(move |fmt| {
347 let current_href = context
348 .href_from_span(clean::Span::new(file_span), false)
349 .expect("only local crates should have sources emitted");
347 // For scraped examples, use the URL from ScrapedInfo directly.
348 // For regular sources, derive it from the span.
349 let current_href = if let SourceContext::Embedded(info) = source_context {
350 info.url.to_string()
351 } else {
352 context
353 .href_from_span(clean::Span::new(file_span), false)
354 .expect("only local crates should have sources emitted")
355 };
350356 highlight::write_code(
351357 fmt,
352358 s,
src/librustdoc/json/conversions.rs+1-1
......@@ -296,7 +296,7 @@ fn from_clean_item(item: &clean::Item, renderer: &JsonRenderer<'_>) -> ItemEnum
296296 MethodItem(m, _) => {
297297 ItemEnum::Function(from_clean_function(m, true, header.unwrap(), renderer))
298298 }
299 RequiredMethodItem(m) => {
299 RequiredMethodItem(m, _) => {
300300 ItemEnum::Function(from_clean_function(m, false, header.unwrap(), renderer))
301301 }
302302 ImplItem(i) => ItemEnum::Impl(i.into_json(renderer)),
src/librustdoc/visit.rs+2-2
......@@ -35,8 +35,8 @@ pub(crate) trait DocVisitor<'a>: Sized {
3535 | StaticItem(_)
3636 | ConstantItem(..)
3737 | TraitAliasItem(_)
38 | RequiredMethodItem(_)
39 | MethodItem(_, _)
38 | RequiredMethodItem(..)
39 | MethodItem(..)
4040 | StructFieldItem(_)
4141 | ForeignFunctionItem(..)
4242 | ForeignStaticItem(..)
src/tools/clippy/clippy_utils/src/ast_utils/mod.rs+3-1
......@@ -819,7 +819,9 @@ pub fn eq_use_tree_kind(l: &UseTreeKind, r: &UseTreeKind) -> bool {
819819pub fn eq_defaultness(l: Defaultness, r: Defaultness) -> bool {
820820 matches!(
821821 (l, r),
822 (Defaultness::Final, Defaultness::Final) | (Defaultness::Default(_), Defaultness::Default(_))
822 (Defaultness::Implicit, Defaultness::Implicit)
823 | (Defaultness::Default(_), Defaultness::Default(_))
824 | (Defaultness::Final(_), Defaultness::Final(_))
823825 )
824826}
825827
src/tools/miri/CONTRIBUTING.md+17
......@@ -66,6 +66,23 @@ process for such contributions:
6666This process is largely informal, and its primary goal is to more clearly communicate expectations.
6767Please get in touch with us if you have any questions!
6868
69## Scope of Miri shims
70
71Miri has "shims" to implement functionality that is usually implemented in C libraries which are
72invoked from Rust code, such as opening files or spawning threads, as well as for
73CPU-vendor-provided SIMD intrinsics. However, the set of C functions that Rust code invokes this way
74is enormous, and for obvious reasons we have no intention of implementing every C API ever written
75in Miri.
76
77At the moment, the general guideline for "could this function have a shim in Miri" is: we will
78generally only add shims for functions that can be implemented in a portable way using just what is
79provided by the Rust standard library. The function should also be reasonably widely-used in Rust
80code to justify the review and maintenance effort (i.e. the easier the function is to implement, the
81lower the barrier). Other than that, we might make exceptions for certain cases if (a) there is a
82good case for why Miri should support those APIs, and (b) robust and widely-used portable libraries
83exist in the Rust ecosystem. We will generally not add shims to Miri that would require Miri to
84directly interact with platform-specific APIs (such as `libc` or `windows-sys`).
85
6986## Preparing the build environment
7087
7188Miri heavily relies on internal and unstable rustc interfaces to execute MIR,
src/tools/miri/Cargo.lock+4-4
......@@ -562,9 +562,9 @@ checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7"
562562
563563[[package]]
564564name = "git2"
565version = "0.20.2"
565version = "0.20.4"
566566source = "registry+https://github.com/rust-lang/crates.io-index"
567checksum = "2deb07a133b1520dc1a5690e9bd08950108873d7ed5de38dcc74d3b5ebffa110"
567checksum = "7b88256088d75a56f8ecfa070513a775dd9107f6530ef14919dac831af9cfe2b"
568568dependencies = [
569569 "bitflags",
570570 "libc",
......@@ -804,9 +804,9 @@ dependencies = [
804804
805805[[package]]
806806name = "libgit2-sys"
807version = "0.18.2+1.9.1"
807version = "0.18.3+1.9.2"
808808source = "registry+https://github.com/rust-lang/crates.io-index"
809checksum = "1c42fe03df2bd3c53a3a9c7317ad91d80c81cd1fb0caec8d7cc4cd2bfa10c222"
809checksum = "c9b3acc4b91781bb0b3386669d325163746af5f6e4f73e6d2d630e09a35f3487"
810810dependencies = [
811811 "cc",
812812 "libc",
src/tools/miri/Cargo.toml+1-1
......@@ -39,7 +39,7 @@ serde = { version = "1.0.219", features = ["derive"], optional = true }
3939[target.'cfg(target_os = "linux")'.dependencies]
4040nix = { version = "0.30.1", features = ["mman", "ptrace", "signal"], optional = true }
4141ipc-channel = { version = "0.20.0", optional = true }
42capstone = { version = "0.14", optional = true }
42capstone = { version = "0.14", features = ["arch_x86", "full"], default-features = false, optional = true}
4343
4444[target.'cfg(all(target_os = "linux", target_pointer_width = "64", target_endian = "little"))'.dependencies]
4545genmc-sys = { path = "./genmc-sys/", version = "0.1.0", optional = true }
src/tools/miri/README.md+2
......@@ -626,6 +626,8 @@ Definite bugs found:
626626* [`ReentrantLock` not correctly dealing with reuse of addresses for TLS storage of different threads](https://github.com/rust-lang/rust/pull/141248)
627627* [Rare Deadlock in the thread (un)parking example code](https://github.com/rust-lang/rust/issues/145816)
628628* [`winit` registering a global constructor with the wrong ABI on Windows](https://github.com/rust-windowing/winit/issues/4435)
629* [`VecDeque::splice` confusing physical and logical indices](https://github.com/rust-lang/rust/issues/151758)
630* [Data race in `oneshot` channel](https://github.com/faern/oneshot/issues/69)
629631
630632Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows is currently just an experiment):
631633
src/tools/miri/cargo-miri/src/phases.rs+4
......@@ -63,6 +63,9 @@ pub fn phase_cargo_miri(mut args: impl Iterator<Item = String>) {
6363 "setup" => MiriCommand::Setup,
6464 "test" | "t" | "run" | "r" | "nextest" => MiriCommand::Forward(subcommand),
6565 "clean" => MiriCommand::Clean,
66 // For use by the `./miri test` dependency builder.
67 "build" if env::var_os("MIRI_BUILD_TEST_DEPS").is_some() =>
68 MiriCommand::Forward("build".into()),
6669 _ => {
6770 // Check for version and help flags.
6871 if has_arg_flag("--help") || has_arg_flag("-h") {
......@@ -309,6 +312,7 @@ pub fn phase_rustc(args: impl Iterator<Item = String>, phase: RustcPhase) {
309312 // Ask rustc for the filename (since that is target-dependent).
310313 let mut rustc = miri_for_host(); // sysroot doesn't matter for this so we just use the host
311314 rustc.arg("--print").arg("file-names");
315 rustc.arg("-Zunstable-options"); // needed for JSON targets
312316 for flag in ["--crate-name", "--crate-type", "--target"] {
313317 for val in get_arg_flag_values(flag) {
314318 rustc.arg(flag).arg(val);
src/tools/miri/cargo-miri/src/setup.rs+5
......@@ -88,6 +88,11 @@ pub fn setup(
8888 };
8989 let cargo_cmd = {
9090 let mut command = cargo();
91 // Allow JSON targets since users do not have a good way to set this flag otherwise.
92 if env::var("RUSTC_STAGE").is_err() {
93 // ^ is a HACK for bootstrap cargo. FIXME(cfg(bootstrap)) remove the hack.
94 command.arg("-Zjson-target-spec");
95 }
9196 // Use Miri as rustc to build a libstd compatible with us (and use the right flags).
9297 // We set ourselves (`cargo-miri`) instead of Miri directly to be able to patch the flags
9398 // for `libpanic_abort` (usually this is done by bootstrap but we have to do it ourselves).
src/tools/miri/ci/ci.sh+4-3
......@@ -129,7 +129,7 @@ function run_tests_minimal {
129129 time ./miri test $TARGET_FLAG "$@"
130130
131131 # Ensure that a small smoke test of cargo-miri works.
132 time cargo miri run --manifest-path test-cargo-miri/no-std-smoke/Cargo.toml $TARGET_FLAG
132 time cargo miri run --manifest-path test-cargo-miri/no-std-smoke/Cargo.toml -Zjson-target-spec $TARGET_FLAG
133133
134134 endgroup
135135}
......@@ -173,7 +173,9 @@ case $HOST_TARGET in
173173 # Host
174174 MIR_OPT=1 MANY_SEEDS=64 TEST_BENCH=1 CARGO_MIRI_ENV=1 run_tests
175175 # Custom target JSON file
176 TEST_TARGET=tests/x86_64-unknown-kernel.json MIRI_NO_STD=1 run_tests_minimal no_std
176 TEST_TARGET=tests/x86_64-unknown-kernel.json MIRI_NO_STD=1 MIRIFLAGS="-Zunstable-options" run_tests_minimal no_std
177 # Not officially supported tier 2
178 MANY_SEEDS=16 TEST_TARGET=x86_64-pc-solaris run_tests
177179 ;;
178180 aarch64-apple-darwin)
179181 # Host
......@@ -184,7 +186,6 @@ case $HOST_TARGET in
184186 # Not officially supported tier 2
185187 MANY_SEEDS=16 TEST_TARGET=mips-unknown-linux-gnu run_tests # a 32bit big-endian target, and also a target without 64bit atomics
186188 MANY_SEEDS=16 TEST_TARGET=x86_64-unknown-illumos run_tests
187 MANY_SEEDS=16 TEST_TARGET=x86_64-pc-solaris run_tests
188189 ;;
189190 i686-pc-windows-msvc)
190191 # Host
src/tools/miri/rust-version+1-1
......@@ -1 +1 @@
1d10ac47c20152feb5e99b1c35a2e6830f77c66dc
17bee525095c0872e87c038c412c781b9bbb3f5dc
src/tools/miri/src/alloc/isolated_alloc.rs+2-2
......@@ -66,10 +66,10 @@ impl IsolatedAlloc {
6666 // And make sure the align is at least one page
6767 let align = std::cmp::max(layout.align(), self.page_size);
6868 // pg_count gives us the # of pages needed to satisfy the size. For
69 // align > page_size where align = n * page_size, a sufficently-aligned
69 // align > page_size where align = n * page_size, a sufficiently-aligned
7070 // address must exist somewhere in the range of
7171 // some_page_aligned_address..some_page_aligned_address + (n-1) * page_size
72 // (since if some_page_aligned_address + n * page_size is sufficently aligned,
72 // (since if some_page_aligned_address + n * page_size is sufficiently aligned,
7373 // then so is some_page_aligned_address itself per the definition of n, so we
7474 // can avoid using that 1 extra page).
7575 // Thus we allocate n-1 extra pages
src/tools/miri/src/bin/log/tracing_chrome_instant.rs+2-2
......@@ -2,7 +2,7 @@
22//! <https://github.com/tikv/minstant/blob/27c9ec5ec90b5b67113a748a4defee0d2519518c/src/tsc_now.rs>.
33//! A useful resource is also
44//! <https://www.pingcap.com/blog/how-we-trace-a-kv-database-with-less-than-5-percent-performance-impact/>,
5//! although this file does not implement TSC synchronization but insteads pins threads to CPUs,
5//! although this file does not implement TSC synchronization but instead pins threads to CPUs,
66//! since the former is not reliable (i.e. it might lead to non-monotonic time measurements).
77//! Another useful resource for future improvements might be measureme's time measurement utils:
88//! <https://github.com/rust-lang/measureme/blob/master/measureme/src/counters.rs>.
......@@ -11,7 +11,7 @@
1111#![cfg(feature = "tracing")]
1212
1313/// This alternative `TracingChromeInstant` implementation was made entirely to suit the needs of
14/// [crate::log::tracing_chrome], and shouldn't be used for anything else. It featues two functions:
14/// [crate::log::tracing_chrome], and shouldn't be used for anything else. It features two functions:
1515/// - [TracingChromeInstant::setup_for_thread_and_start], which sets up the current thread to do
1616/// proper time tracking and returns a point in time to use as "t=0", and
1717/// - [TracingChromeInstant::with_elapsed_micros_subtracting_tracing], which allows
src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs+1-1
......@@ -578,7 +578,7 @@ pub mod diagnostics {
578578 // - created as Reserved { conflicted: false },
579579 // then Unique -> Disabled is forbidden
580580 // A potential `Reserved { conflicted: false }
581 // -> Reserved { conflicted: true }` is inexistant or irrelevant,
581 // -> Reserved { conflicted: true }` is inexistent or irrelevant,
582582 // and so is the `Reserved { conflicted: false } -> Unique`
583583 (Unique, Frozen) => false,
584584 (ReservedFrz { conflicted: true }, _) => false,
src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs+32-49
......@@ -26,7 +26,7 @@ use super::foreign_access_skipping::IdempotentForeignAccess;
2626use super::perms::{PermTransition, Permission};
2727use super::tree_visitor::{ChildrenVisitMode, ContinueTraversal, NodeAppArgs, TreeVisitor};
2828use super::unimap::{UniIndex, UniKeyMap, UniValMap};
29use super::wildcard::WildcardState;
29use super::wildcard::ExposedCache;
3030use crate::borrow_tracker::{AccessKind, GlobalState, ProtectorKind};
3131use crate::*;
3232
......@@ -89,7 +89,7 @@ impl LocationState {
8989 &mut self,
9090 idx: UniIndex,
9191 nodes: &mut UniValMap<Node>,
92 wildcard_accesses: &mut UniValMap<WildcardState>,
92 exposed_cache: &mut ExposedCache,
9393 access_kind: AccessKind,
9494 relatedness: AccessRelatedness,
9595 protected: bool,
......@@ -99,7 +99,7 @@ impl LocationState {
9999 // ensures it is only called when `skip_if_known_noop` returns
100100 // `Recurse`, due to the contract of `traverse_this_parents_children_other`.
101101 self.record_new_access(access_kind, relatedness);
102
102 let old_access_level = self.permission.strongest_allowed_local_access(protected);
103103 let transition = self.perform_access(access_kind, relatedness, protected)?;
104104 if !transition.is_noop() {
105105 let node = nodes.get_mut(idx).unwrap();
......@@ -111,8 +111,8 @@ impl LocationState {
111111 // We need to update the wildcard state, if the permission
112112 // of an exposed pointer changes.
113113 if node.is_exposed {
114 let access_type = self.permission.strongest_allowed_local_access(protected);
115 WildcardState::update_exposure(idx, access_type, nodes, wildcard_accesses);
114 let access_level = self.permission.strongest_allowed_local_access(protected);
115 exposed_cache.update_exposure(nodes, idx, old_access_level, access_level);
116116 }
117117 }
118118 Ok(())
......@@ -226,7 +226,7 @@ impl LocationState {
226226
227227 /// Records a new access, so that future access can potentially be skipped
228228 /// by `skip_if_known_noop`. This must be called on child accesses, and otherwise
229 /// shoud be called on foreign accesses for increased performance. It should not be called
229 /// should be called on foreign accesses for increased performance. It should not be called
230230 /// when `skip_if_known_noop` indicated skipping, since it then is a no-op.
231231 /// See `foreign_access_skipping.rs`
232232 fn record_new_access(&mut self, access_kind: AccessKind, rel_pos: AccessRelatedness) {
......@@ -261,14 +261,8 @@ pub struct LocationTree {
261261 ///
262262 /// We do uphold the fact that `keys(perms)` is a subset of `keys(nodes)`
263263 pub perms: UniValMap<LocationState>,
264 /// Maps a tag and a location to its wildcard access tracking information,
265 /// with possible lazy initialization.
266 ///
267 /// If this allocation doesn't have any exposed nodes, then this map doesn't get
268 /// initialized. This way we only need to allocate the map if we need it.
269 ///
270 /// NOTE: same guarantees on entry initialization as for `perms`.
271 pub wildcard_accesses: UniValMap<WildcardState>,
264 /// Caches information about the relatedness of nodes for a wildcard access.
265 pub exposed_cache: ExposedCache,
272266}
273267/// Tree structure with both parents and children since we want to be
274268/// able to traverse the tree efficiently in both directions.
......@@ -276,7 +270,7 @@ pub struct LocationTree {
276270pub struct Tree {
277271 /// Mapping from tags to keys. The key obtained can then be used in
278272 /// any of the `UniValMap` relative to this allocation, i.e.
279 /// `nodes`, `LocationTree::perms` and `LocationTree::wildcard_accesses`
273 /// `nodes`, `LocationTree::perms` and `LocationTree::exposed_cache`
280274 /// of the same `Tree`.
281275 /// The parent-child relationship in `Node` is encoded in terms of these same
282276 /// keys, so traversing the entire tree needs exactly one access to
......@@ -372,8 +366,8 @@ impl Tree {
372366 IdempotentForeignAccess::None,
373367 ),
374368 );
375 let wildcard_accesses = UniValMap::default();
376 DedupRangeMap::new(size, LocationTree { perms, wildcard_accesses })
369 let exposed_cache = ExposedCache::default();
370 DedupRangeMap::new(size, LocationTree { perms, exposed_cache })
377371 };
378372 Self { roots: SmallVec::from_slice(&[root_idx]), nodes, locations, tag_mapping }
379373 }
......@@ -451,19 +445,9 @@ impl<'tcx> Tree {
451445 }
452446 }
453447
454 // We need to ensure the consistency of the wildcard access tracking data structure.
455 // For this, we insert the correct entry for this tag based on its parent, if it exists.
456 // If we are inserting a new wildcard root (with Wildcard as parent_prov) then we insert
457 // the special wildcard root initial state instead.
458 for (_range, loc) in self.locations.iter_mut_all() {
459 if let Some(parent_idx) = parent_idx {
460 if let Some(parent_access) = loc.wildcard_accesses.get(parent_idx) {
461 loc.wildcard_accesses.insert(idx, parent_access.for_new_child());
462 }
463 } else {
464 loc.wildcard_accesses.insert(idx, WildcardState::for_wildcard_root());
465 }
466 }
448 // We don't have to update `exposed_cache` as the new node is not exposed and
449 // has no children so the default counts of 0 are correct.
450
467451 // If the parent is a wildcard pointer, then it doesn't track SIFA and doesn't need to be updated.
468452 if let Some(parent_idx) = parent_idx {
469453 // Inserting the new perms might have broken the SIFA invariant (see
......@@ -807,7 +791,7 @@ impl Tree {
807791 let node = self.nodes.remove(this).unwrap();
808792 for (_range, loc) in self.locations.iter_mut_all() {
809793 loc.perms.remove(this);
810 loc.wildcard_accesses.remove(this);
794 loc.exposed_cache.remove(this);
811795 }
812796 self.tag_mapping.remove(&node.tag);
813797 }
......@@ -943,7 +927,7 @@ impl<'tcx> LocationTree {
943927 };
944928
945929 let accessed_root_tag = accessed_root.map(|idx| nodes.get(idx).unwrap().tag);
946 for root in roots {
930 for (i, root) in roots.enumerate() {
947931 let tag = nodes.get(root).unwrap().tag;
948932 // On a protector release access we have to skip the children of the accessed tag.
949933 // However, if the tag has exposed children then some of the wildcard subtrees could
......@@ -981,6 +965,7 @@ impl<'tcx> LocationTree {
981965 access_kind,
982966 global,
983967 diagnostics,
968 /*is_wildcard_tree*/ i != 0,
984969 )?;
985970 }
986971 interp_ok(())
......@@ -1029,7 +1014,7 @@ impl<'tcx> LocationTree {
10291014 .perform_transition(
10301015 args.idx,
10311016 args.nodes,
1032 &mut args.data.wildcard_accesses,
1017 &mut args.data.exposed_cache,
10331018 access_kind,
10341019 args.rel_pos,
10351020 protected,
......@@ -1074,12 +1059,18 @@ impl<'tcx> LocationTree {
10741059 access_kind: AccessKind,
10751060 global: &GlobalState,
10761061 diagnostics: &DiagnosticInfo,
1062 is_wildcard_tree: bool,
10771063 ) -> InterpResult<'tcx> {
10781064 let get_relatedness = |idx: UniIndex, node: &Node, loc: &LocationTree| {
1079 let wildcard_state = loc.wildcard_accesses.get(idx).cloned().unwrap_or_default();
10801065 // If the tag is larger than `max_local_tag` then the access can only be foreign.
10811066 let only_foreign = max_local_tag.is_some_and(|max_local_tag| max_local_tag < node.tag);
1082 wildcard_state.access_relatedness(access_kind, only_foreign)
1067 loc.exposed_cache.access_relatedness(
1068 root,
1069 idx,
1070 access_kind,
1071 is_wildcard_tree,
1072 only_foreign,
1073 )
10831074 };
10841075
10851076 // Whether there is an exposed node in this tree that allows this access.
......@@ -1156,7 +1147,7 @@ impl<'tcx> LocationTree {
11561147 perm.perform_transition(
11571148 args.idx,
11581149 args.nodes,
1159 &mut args.data.wildcard_accesses,
1150 &mut args.data.exposed_cache,
11601151 access_kind,
11611152 relatedness,
11621153 protected,
......@@ -1175,19 +1166,11 @@ impl<'tcx> LocationTree {
11751166 })
11761167 },
11771168 )?;
1178 // If there is no exposed node in this tree that allows this access, then the
1179 // access *must* be foreign. So we check if the root of this tree would allow this
1180 // as a foreign access, and if not, then we can error.
1181 // In practice, all wildcard trees accept foreign accesses, but the main tree does
1182 // not, so this catches UB when none of the nodes in the main tree allows this access.
1183 if !has_valid_exposed
1184 && self
1185 .wildcard_accesses
1186 .get(root)
1187 .unwrap()
1188 .access_relatedness(access_kind, /* only_foreign */ true)
1189 .is_none()
1190 {
1169 // If there is no exposed node in this tree that allows this access, then the access *must*
1170 // be foreign to the entire subtree. Foreign accesses are only possible on wildcard subtrees
1171 // as there are no ancestors to the main root. So if we do not find a valid exposed node in
1172 // the main tree then this access is UB.
1173 if !has_valid_exposed && !is_wildcard_tree {
11911174 return Err(no_valid_exposed_references_error(diagnostics)).into();
11921175 }
11931176 interp_ok(())
src/tools/miri/src/borrow_tracker/tree_borrows/tree/tests.rs+1-1
......@@ -741,7 +741,7 @@ mod spurious_read {
741741 );
742742 eprintln!(" (arbitrary code instanciated with '{opaque}')");
743743 err += 1;
744 // We found an instanciation of the opaque code that makes this Pattern
744 // We found an instantiation of the opaque code that makes this Pattern
745745 // fail, we don't really need to check the rest.
746746 break;
747747 }
src/tools/miri/src/borrow_tracker/tree_borrows/tree_visitor.rs+1-1
......@@ -99,7 +99,7 @@ where
9999 assert!(self.stack.is_empty());
100100 // First, handle accessed node. A bunch of things need to
101101 // be handled differently here compared to the further parents
102 // of `accesssed_node`.
102 // of `accessesed_node`.
103103 {
104104 self.propagate_at(this, accessed_node, AccessRelatedness::LocalAccess)?;
105105 if matches!(visit_children, ChildrenVisitMode::VisitChildrenOfAccessed) {
src/tools/miri/src/borrow_tracker/tree_borrows/wildcard.rs+159-432
......@@ -1,4 +1,3 @@
1use std::cmp::max;
21use std::fmt::Debug;
32
43use super::Tree;
......@@ -51,374 +50,142 @@ impl WildcardAccessRelatedness {
5150 }
5251}
5352
53/// Caches information about where in the tree exposed nodes with permission to do reads/ rites are
54/// located. [`ExposedCache`] stores this information a single location (or rather, a range of
55/// homogeneous locations) for all nodes in an allocation.
56///
57/// Nodes not in this map have a default [`ExposedCacheNode`], i.e. they have no exposed children.
58/// In particular, this map remains empty (and thus consumes no memory) until the first
59/// node in the tree gets exposed.
60#[derive(Clone, Debug, Default, PartialEq, Eq)]
61pub struct ExposedCache(UniValMap<ExposedCacheNode>);
62
5463/// State per location per node keeping track of where relative to this
5564/// node exposed nodes are and what access permissions they have.
56///
57/// Designed to be completely determined by its parent, siblings and
58/// direct children's max_local_access/max_foreign_access.
59#[derive(Clone, Default, PartialEq, Eq)]
60pub struct WildcardState {
61 /// How many of this node's direct children have `max_local_access()==Write`.
62 child_writes: u16,
63 /// How many of this node's direct children have `max_local_access()>=Read`.
64 child_reads: u16,
65 /// The maximum access level that could happen from an exposed node
66 /// that is foreign to this node.
67 ///
68 /// This is calculated as the `max()` of the parent's `max_foreign_access`,
69 /// `exposed_as` and the siblings' `max_local_access()`.
70 max_foreign_access: WildcardAccessLevel,
71 /// At what access level this node itself is exposed.
72 exposed_as: WildcardAccessLevel,
73}
74impl Debug for WildcardState {
75 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
76 f.debug_struct("WildcardState")
77 .field("child_r/w", &(self.child_reads, self.child_writes))
78 .field("foreign", &self.max_foreign_access)
79 .field("exposed_as", &self.exposed_as)
80 .finish()
81 }
65#[derive(Clone, Default, Debug, PartialEq, Eq)]
66struct ExposedCacheNode {
67 /// How many local nodes (in this subtree) are exposed with write permissions.
68 local_writes: u16,
69 /// How many local nodes (in this subtree) are exposed with read permissions.
70 local_reads: u16,
8271}
83impl WildcardState {
84 /// The maximum access level that could happen from an exposed
85 /// node that is local to this node.
86 fn max_local_access(&self) -> WildcardAccessLevel {
87 use WildcardAccessLevel::*;
88 max(
89 self.exposed_as,
90 if self.child_writes > 0 {
91 Write
92 } else if self.child_reads > 0 {
93 Read
94 } else {
95 None
96 },
97 )
98 }
9972
100 /// From where relative to the node with this wildcard info a read or write access could happen.
101 /// If `only_foreign` is true then we treat `LocalAccess` as impossible. This means we return
102 /// `None` if only a `LocalAccess` is possible, and we treat `EitherAccess` as a
103 /// `ForeignAccess`.
73impl ExposedCache {
74 /// Returns the relatedness of a wildcard access to a node.
75 ///
76 /// This function only considers a single subtree. If the current subtree does not contain
77 /// any valid exposed nodes then the function return `None`.
78 ///
79 /// * `root`: The root of the subtree the node belongs to.
80 /// * `id`: The id of the node.
81 /// * `kind`: The kind of the wildcard access.
82 /// * `is_wildcard_tree`: This nodes belongs to a wildcard subtree.
83 /// This means we always treat foreign accesses as possible.
84 /// * `only_foreign`: Assume the access cannot come from a local node.
10485 pub fn access_relatedness(
10586 &self,
87 root: UniIndex,
88 id: UniIndex,
10689 kind: AccessKind,
90 is_wildcard_tree: bool,
10791 only_foreign: bool,
10892 ) -> Option<WildcardAccessRelatedness> {
109 let rel = match kind {
110 AccessKind::Read => self.read_access_relatedness(),
111 AccessKind::Write => self.write_access_relatedness(),
93 // All nodes in the tree are local to the root, so we can use the root to get the total
94 // number of valid exposed nodes in the tree.
95 let root = self.0.get(root).cloned().unwrap_or_default();
96 let node = self.0.get(id).cloned().unwrap_or_default();
97
98 let (total_num, local_num) = match kind {
99 AccessKind::Read => (root.local_reads, node.local_reads),
100 AccessKind::Write => (root.local_writes, node.local_writes),
112101 };
113 if only_foreign {
114 use WildcardAccessRelatedness as E;
115 match rel {
116 Some(E::EitherAccess | E::ForeignAccess) => Some(E::ForeignAccess),
117 Some(E::LocalAccess) | None => None,
118 }
119 } else {
120 rel
121 }
122 }
123102
124 /// From where relative to the node with this wildcard info a read access could happen.
125 fn read_access_relatedness(&self) -> Option<WildcardAccessRelatedness> {
126 let has_foreign = self.max_foreign_access >= WildcardAccessLevel::Read;
127 let has_local = self.max_local_access() >= WildcardAccessLevel::Read;
128 use WildcardAccessRelatedness as E;
129 match (has_foreign, has_local) {
130 (true, true) => Some(E::EitherAccess),
131 (true, false) => Some(E::ForeignAccess),
132 (false, true) => Some(E::LocalAccess),
133 (false, false) => None,
134 }
135 }
136
137 /// From where relative to the node with this wildcard info a write access could happen.
138 fn write_access_relatedness(&self) -> Option<WildcardAccessRelatedness> {
139 let has_foreign = self.max_foreign_access == WildcardAccessLevel::Write;
140 let has_local = self.max_local_access() == WildcardAccessLevel::Write;
141 use WildcardAccessRelatedness as E;
142 match (has_foreign, has_local) {
143 (true, true) => Some(E::EitherAccess),
144 (true, false) => Some(E::ForeignAccess),
145 (false, true) => Some(E::LocalAccess),
146 (false, false) => None,
147 }
148 }
149
150 /// Gets the access tracking information for a new child node of a parent with this
151 /// wildcard info.
152 /// The new node doesn't have any child reads/writes, but calculates `max_foreign_access`
153 /// from its parent.
154 pub fn for_new_child(&self) -> Self {
155 Self {
156 max_foreign_access: max(self.max_foreign_access, self.max_local_access()),
157 ..Default::default()
158 }
159 }
160 /// Crates the initial `WildcardState` for a wildcard root.
161 /// This has `max_foreign_access==Write` as it actually is the child of *some* exposed node
162 /// through which we can receive foreign accesses.
163 ///
164 /// This is different from the main root which has `max_foreign_access==None`, since there
165 /// cannot be a foreign access to the root of the allocation.
166 pub fn for_wildcard_root() -> Self {
167 Self { max_foreign_access: WildcardAccessLevel::Write, ..Default::default() }
168 }
169
170 /// Pushes the nodes of `children` onto the stack who's `max_foreign_access`
171 /// needs to be updated.
172 ///
173 /// * `children`: A list of nodes with the same parent. `children` doesn't
174 /// necessarily have to contain all children of parent, but can just be
175 /// a subset.
176 ///
177 /// * `child_reads`, `child_writes`: How many of `children` have `max_local_access()`
178 /// of at least `read`/`write`
179 ///
180 /// * `new_foreign_access`, `old_foreign_access`:
181 /// The max possible access level that is foreign to all `children`
182 /// (i.e., it is not local to *any* of them).
183 /// This can be calculated as the max of the parent's `exposed_as()`, `max_foreign_access`
184 /// and of all `max_local_access()` of any nodes with the same parent that are
185 /// not listed in `children`.
186 ///
187 /// This access level changed from `old` to `new`, which is why we need to
188 /// update `children`.
189 fn push_relevant_children(
190 stack: &mut Vec<(UniIndex, WildcardAccessLevel)>,
191 new_foreign_access: WildcardAccessLevel,
192 old_foreign_access: WildcardAccessLevel,
193 child_reads: u16,
194 child_writes: u16,
195 children: impl Iterator<Item = UniIndex>,
196
197 wildcard_accesses: &UniValMap<WildcardState>,
198 ) {
199 use WildcardAccessLevel::*;
200
201 // Nothing changed so we don't need to update anything.
202 if new_foreign_access == old_foreign_access {
203 return;
204 }
205
206 // We need to consider that the children's `max_local_access()` affect each
207 // other's `max_foreign_access`, but do not affect their own `max_foreign_access`.
208
209 // The new `max_foreign_acces` for children with `max_local_access()==Write`.
210 let write_foreign_access = max(
211 new_foreign_access,
212 if child_writes > 1 {
213 // There exists at least one more child with exposed write access.
214 // This means that a foreign write through that node is possible.
215 Write
216 } else if child_reads > 1 {
217 // There exists at least one more child with exposed read access,
218 // but no other with write access.
219 // This means that a foreign read but no write through that node
220 // is possible.
221 Read
222 } else {
223 // There are no other nodes with read or write access.
224 // This means no foreign writes through other children are possible.
225 None
226 },
227 );
228
229 // The new `max_foreign_acces` for children with `max_local_access()==Read`.
230 let read_foreign_access = max(
231 new_foreign_access,
232 if child_writes > 0 {
233 // There exists at least one child with write access (and it's not this one).
234 Write
235 } else if child_reads > 1 {
236 // There exists at least one more child with exposed read access,
237 // but no other with write access.
238 Read
239 } else {
240 // There are no other nodes with read or write access,
241 None
242 },
243 );
244
245 // The new `max_foreign_acces` for children with `max_local_access()==None`.
246 let none_foreign_access = max(
247 new_foreign_access,
248 if child_writes > 0 {
249 // There exists at least one child with write access (and it's not this one).
250 Write
251 } else if child_reads > 0 {
252 // There exists at least one child with read access (and it's not this one),
253 // but none with write access.
254 Read
103 // If this is a wildcard tree then an access can always be foreign as
104 // it could come from another tree.
105 // We can represent this by adding 1 to the total which means there
106 // always exists a foreign exposed node.
107 // (We cannot bake this into the root's count as then if `node == root` it would
108 // affect both `total` and `local`.)
109 let total_num = total_num + u16::from(is_wildcard_tree);
110
111 use WildcardAccessRelatedness::*;
112 let relatedness = if total_num == 0 {
113 // we return None if the tree does not contain any valid exposed nodes.
114 None
115 } else {
116 Some(if total_num == local_num {
117 // If all valid exposed nodes are local to this node then the access is local.
118 LocalAccess
119 } else if local_num == 0 {
120 // If the node does not have any exposed nodes as children then the access is foreign.
121 ForeignAccess
255122 } else {
256 // No children are exposed as read or write.
257 None
258 },
259 );
260
261 stack.extend(children.filter_map(|child| {
262 let state = wildcard_accesses.get(child).cloned().unwrap_or_default();
263
264 let new_foreign_access = match state.max_local_access() {
265 Write => write_foreign_access,
266 Read => read_foreign_access,
267 None => none_foreign_access,
268 };
123 // If some but not all of the valid exposed nodes are local then we cannot determine the correct relatedness.
124 EitherAccess
125 })
126 };
269127
270 if new_foreign_access != state.max_foreign_access {
271 Some((child, new_foreign_access))
272 } else {
273 Option::None
128 if only_foreign {
129 // This is definitely not a local access; clamp the result accordingly.
130 match relatedness {
131 Some(LocalAccess) => None,
132 Some(ForeignAccess) => Some(ForeignAccess),
133 Some(EitherAccess) => Some(ForeignAccess),
134 None => None,
274135 }
275 }));
136 } else {
137 relatedness
138 }
276139 }
277
278140 /// Update the tracking information of a tree, to reflect that the node specified by `id` is
279 /// now exposed with `new_exposed_as`.
141 /// now exposed with `new_exposed_as` permission.
280142 ///
281143 /// Propagates the Willard access information over the tree. This needs to be called every
282144 /// time the access level of an exposed node changes, to keep the state in sync with
283145 /// the rest of the tree.
146 ///
147 /// * `from`: The previous access level of the exposed node.
148 /// Set to `None` if the node was not exposed before.
149 /// * `to`: The new access level.
284150 pub fn update_exposure(
285 id: UniIndex,
286 new_exposed_as: WildcardAccessLevel,
151 &mut self,
287152 nodes: &UniValMap<Node>,
288 wildcard_accesses: &mut UniValMap<WildcardState>,
153 id: UniIndex,
154 from: WildcardAccessLevel,
155 to: WildcardAccessLevel,
289156 ) {
290 let mut entry = wildcard_accesses.entry(id);
291 let src_state = entry.or_insert(Default::default());
292 let old_exposed_as = src_state.exposed_as;
293
294157 // If the exposure doesn't change, then we don't need to update anything.
295 if old_exposed_as == new_exposed_as {
158 if from == to {
296159 return;
297160 }
298161
299 let src_old_local_access = src_state.max_local_access();
300
301 src_state.exposed_as = new_exposed_as;
302
303 let src_new_local_access = src_state.max_local_access();
304
305 // Stack of nodes for which the max_foreign_access field needs to be updated.
306 // Will be filled with the children of this node and its parents children before
307 // we begin downwards traversal.
308 let mut stack: Vec<(UniIndex, WildcardAccessLevel)> = Vec::new();
309
310 // Add the direct children of this node to the stack.
311 {
162 // Update the counts of this node and all its ancestors.
163 let mut next_id = Some(id);
164 while let Some(id) = next_id {
312165 let node = nodes.get(id).unwrap();
313 Self::push_relevant_children(
314 &mut stack,
315 // new_foreign_access
316 max(src_state.max_foreign_access, new_exposed_as),
317 // old_foreign_access
318 max(src_state.max_foreign_access, old_exposed_as),
319 // Consider all children.
320 src_state.child_reads,
321 src_state.child_writes,
322 node.children.iter().copied(),
323 wildcard_accesses,
324 );
325 }
326 // We need to propagate the tracking info up the tree, for this we traverse
327 // up the parents.
328 // We can skip propagating info to the parent and siblings of a node if its
329 // access didn't change.
330 {
331 // The child from which we came.
332 let mut child = id;
333 // This is the `max_local_access()` of the child we came from, before
334 // this update...
335 let mut old_child_access = src_old_local_access;
336 // and after this update.
337 let mut new_child_access = src_new_local_access;
338 while let Some(parent_id) = nodes.get(child).unwrap().parent {
339 let parent_node = nodes.get(parent_id).unwrap();
340 let mut entry = wildcard_accesses.entry(parent_id);
341 let parent_state = entry.or_insert(Default::default());
342
343 let old_parent_local_access = parent_state.max_local_access();
344 use WildcardAccessLevel::*;
345 // Updating this node's tracking state for its children.
346 match (old_child_access, new_child_access) {
347 (None | Read, Write) => parent_state.child_writes += 1,
348 (Write, None | Read) => parent_state.child_writes -= 1,
349 _ => {}
350 }
351 match (old_child_access, new_child_access) {
352 (None, Read | Write) => parent_state.child_reads += 1,
353 (Read | Write, None) => parent_state.child_reads -= 1,
354 _ => {}
355 }
356
357 let new_parent_local_access = parent_state.max_local_access();
358
359 {
360 // We need to update the `max_foreign_access` of `child`'s
361 // siblings. For this we can reuse the `push_relevant_children`
362 // function.
363 //
364 // We pass it just the siblings without child itself. Since
365 // `child`'s `max_local_access()` is foreign to all of its
366 // siblings we can pass it as part of the foreign access.
367
368 let parent_access =
369 max(parent_state.exposed_as, parent_state.max_foreign_access);
370 // This is how many of `child`'s siblings have read/write local access.
371 // If `child` itself has access, then we need to subtract its access from the count.
372 let sibling_reads =
373 parent_state.child_reads - if new_child_access >= Read { 1 } else { 0 };
374 let sibling_writes =
375 parent_state.child_writes - if new_child_access >= Write { 1 } else { 0 };
376 Self::push_relevant_children(
377 &mut stack,
378 // new_foreign_access
379 max(parent_access, new_child_access),
380 // old_foreign_access
381 max(parent_access, old_child_access),
382 // Consider only siblings of child.
383 sibling_reads,
384 sibling_writes,
385 parent_node.children.iter().copied().filter(|id| child != *id),
386 wildcard_accesses,
387 );
388 }
389 if old_parent_local_access == new_parent_local_access {
390 // We didn't change `max_local_access()` for parent, so we don't need to propagate further upwards.
391 break;
392 }
393
394 old_child_access = old_parent_local_access;
395 new_child_access = new_parent_local_access;
396 child = parent_id;
166 let mut state = self.0.entry(id);
167 let state = state.or_insert(Default::default());
168
169 use WildcardAccessLevel::*;
170 match (from, to) {
171 (None | Read, Write) => state.local_writes += 1,
172 (Write, None | Read) => state.local_writes -= 1,
173 _ => {}
397174 }
398 }
399 // Traverses down the tree to update max_foreign_access fields of children and cousins who need to be updated.
400 while let Some((id, new_access)) = stack.pop() {
401 let node = nodes.get(id).unwrap();
402 let mut entry = wildcard_accesses.entry(id);
403 let state = entry.or_insert(Default::default());
404
405 let old_access = state.max_foreign_access;
406 state.max_foreign_access = new_access;
407
408 Self::push_relevant_children(
409 &mut stack,
410 // new_foreign_access
411 max(state.exposed_as, new_access),
412 // old_foreign_access
413 max(state.exposed_as, old_access),
414 // Consider all children.
415 state.child_reads,
416 state.child_writes,
417 node.children.iter().copied(),
418 wildcard_accesses,
419 );
175 match (from, to) {
176 (None, Read | Write) => state.local_reads += 1,
177 (Read | Write, None) => state.local_reads -= 1,
178 _ => {}
179 }
180 next_id = node.parent;
420181 }
421182 }
183 /// Removes a node from the datastructure.
184 ///
185 /// The caller needs to ensure that the node does not have any children.
186 pub fn remove(&mut self, idx: UniIndex) {
187 self.0.remove(idx);
188 }
422189}
423190
424191impl Tree {
......@@ -428,25 +195,28 @@ impl Tree {
428195 pub fn expose_tag(&mut self, tag: BorTag, protected: bool) {
429196 let id = self.tag_mapping.get(&tag).unwrap();
430197 let node = self.nodes.get_mut(id).unwrap();
431 node.is_exposed = true;
432 let node = self.nodes.get(id).unwrap();
433
434 // When the first tag gets exposed then we initialize the
435 // wildcard state for every node and location in the tree.
436 for (_, loc) in self.locations.iter_mut_all() {
437 let perm = loc
438 .perms
439 .get(id)
440 .map(|p| p.permission())
441 .unwrap_or_else(|| node.default_location_state().permission());
442
443 let access_type = perm.strongest_allowed_local_access(protected);
444 WildcardState::update_exposure(
445 id,
446 access_type,
447 &self.nodes,
448 &mut loc.wildcard_accesses,
449 );
198 if !node.is_exposed {
199 node.is_exposed = true;
200 let node = self.nodes.get(id).unwrap();
201
202 for (_, loc) in self.locations.iter_mut_all() {
203 let perm = loc
204 .perms
205 .get(id)
206 .map(|p| p.permission())
207 .unwrap_or_else(|| node.default_location_state().permission());
208
209 let access_level = perm.strongest_allowed_local_access(protected);
210 // An unexposed node gets treated as access level `None`. Therefore,
211 // the initial exposure transitions from `None` to the node's actual
212 // `access_level`.
213 loc.exposed_cache.update_exposure(
214 &self.nodes,
215 id,
216 WildcardAccessLevel::None,
217 access_level,
218 );
219 }
450220 }
451221 }
452222
......@@ -457,10 +227,19 @@ impl Tree {
457227
458228 // We check if the node is already exposed, as we don't want to expose any
459229 // nodes which aren't already exposed.
460
461 if self.nodes.get(idx).unwrap().is_exposed {
462 // Updates the exposure to the new permission on every location.
463 self.expose_tag(tag, /* protected */ false);
230 let node = self.nodes.get(idx).unwrap();
231 if node.is_exposed {
232 for (_, loc) in self.locations.iter_mut_all() {
233 let perm = loc
234 .perms
235 .get(idx)
236 .map(|p| p.permission())
237 .unwrap_or_else(|| node.default_location_state().permission());
238 // We are transitioning from protected to unprotected.
239 let old_access_type = perm.strongest_allowed_local_access(/*protected*/ true);
240 let access_type = perm.strongest_allowed_local_access(/*protected*/ false);
241 loc.exposed_cache.update_exposure(&self.nodes, idx, old_access_type, access_type);
242 }
464243 }
465244 }
466245}
......@@ -472,20 +251,15 @@ impl Tree {
472251 pub fn verify_wildcard_consistency(&self, global: &GlobalState) {
473252 // We rely on the fact that `roots` is ordered according to tag from low to high.
474253 assert!(self.roots.is_sorted_by_key(|idx| self.nodes.get(*idx).unwrap().tag));
475 let main_root_idx = self.roots[0];
476254
477255 let protected_tags = &global.borrow().protected_tags;
478256 for (_, loc) in self.locations.iter_all() {
479 let wildcard_accesses = &loc.wildcard_accesses;
257 let exposed_cache = &loc.exposed_cache;
480258 let perms = &loc.perms;
481 // Checks if accesses is empty.
482 if wildcard_accesses.is_empty() {
483 return;
484 }
485259 for (id, node) in self.nodes.iter() {
486 let state = wildcard_accesses.get(id).unwrap();
260 let state = exposed_cache.0.get(id).cloned().unwrap_or_default();
487261
488 let expected_exposed_as = if node.is_exposed {
262 let exposed_as = if node.is_exposed {
489263 let perm =
490264 perms.get(id).copied().unwrap_or_else(|| node.default_location_state());
491265
......@@ -495,72 +269,25 @@ impl Tree {
495269 WildcardAccessLevel::None
496270 };
497271
498 // The foreign wildcard accesses possible at a node are determined by which
499 // accesses can originate from their siblings, their parent, and from above
500 // their parent.
501 let expected_max_foreign_access = if let Some(parent) = node.parent {
502 let parent_node = self.nodes.get(parent).unwrap();
503 let parent_state = wildcard_accesses.get(parent).unwrap();
504
505 let max_sibling_access = parent_node
506 .children
507 .iter()
508 .copied()
509 .filter(|child| *child != id)
510 .map(|child| {
511 let state = wildcard_accesses.get(child).unwrap();
512 state.max_local_access()
513 })
514 .fold(WildcardAccessLevel::None, max);
515
516 max_sibling_access
517 .max(parent_state.max_foreign_access)
518 .max(parent_state.exposed_as)
519 } else {
520 if main_root_idx == id {
521 // There can never be a foreign access to the root of the allocation.
522 // So its foreign access level is always `None`.
523 WildcardAccessLevel::None
524 } else {
525 // For wildcard roots any access on a different subtree can be foreign
526 // to it. So a wildcard root has the maximum possible foreign access
527 // level.
528 WildcardAccessLevel::Write
529 }
530 };
531
532 // Count how many children can be the source of wildcard reads or writes
533 // (either directly, or via their children).
534 let child_accesses = node.children.iter().copied().map(|child| {
535 let state = wildcard_accesses.get(child).unwrap();
536 state.max_local_access()
537 });
538 let expected_child_reads =
539 child_accesses.clone().filter(|a| *a >= WildcardAccessLevel::Read).count();
540 let expected_child_writes =
541 child_accesses.filter(|a| *a >= WildcardAccessLevel::Write).count();
542
543 assert_eq!(
544 expected_exposed_as, state.exposed_as,
545 "tag {:?} (id:{id:?}) should be exposed as {expected_exposed_as:?} but is exposed as {:?}",
546 node.tag, state.exposed_as
547 );
548 assert_eq!(
549 expected_max_foreign_access, state.max_foreign_access,
550 "expected {:?}'s (id:{id:?}) max_foreign_access to be {:?} instead of {:?}",
551 node.tag, expected_max_foreign_access, state.max_foreign_access
552 );
553 let child_reads: usize = state.child_reads.into();
272 let (child_reads, child_writes) = node
273 .children
274 .iter()
275 .copied()
276 .map(|id| exposed_cache.0.get(id).cloned().unwrap_or_default())
277 .fold((0, 0), |acc, wc| (acc.0 + wc.local_reads, acc.1 + wc.local_writes));
278 let expected_reads =
279 child_reads + u16::from(exposed_as >= WildcardAccessLevel::Read);
280 let expected_writes =
281 child_writes + u16::from(exposed_as >= WildcardAccessLevel::Write);
554282 assert_eq!(
555 expected_child_reads, child_reads,
556 "expected {:?}'s (id:{id:?}) child_reads to be {} instead of {}",
557 node.tag, expected_child_reads, child_reads
283 state.local_reads, expected_reads,
284 "expected {:?}'s (id:{id:?}) local_reads to be {expected_reads:?} instead of {:?} (child_reads: {child_reads:?}, exposed_as: {exposed_as:?})",
285 node.tag, state.local_reads
558286 );
559 let child_writes: usize = state.child_writes.into();
560287 assert_eq!(
561 expected_child_writes, child_writes,
562 "expected {:?}'s (id:{id:?}) child_writes to be {} instead of {}",
563 node.tag, expected_child_writes, child_writes
288 state.local_writes, expected_writes,
289 "expected {:?}'s (id:{id:?}) local_writes to be {expected_writes:?} instead of {:?} (child_writes: {child_writes:?}, exposed_as: {exposed_as:?})",
290 node.tag, state.local_writes
564291 );
565292 }
566293 }
src/tools/miri/src/concurrency/data_race.rs+1-1
......@@ -371,7 +371,7 @@ impl AccessType {
371371
372372 if let Some(size) = size {
373373 if size == Size::ZERO {
374 // In this case there were multiple read accesss with different sizes and then a write.
374 // In this case there were multiple read accesses with different sizes and then a write.
375375 // We will be reporting *one* of the other reads, but we don't have enough information
376376 // to determine which one had which size.
377377 assert!(self == AccessType::AtomicLoad);
src/tools/miri/src/concurrency/genmc/global_allocations.rs+1-1
......@@ -62,7 +62,7 @@ impl GlobalStateInner {
6262 let entry = match self.base_addr.entry(alloc_id) {
6363 Entry::Occupied(occupied_entry) => {
6464 // Looks like some other thread allocated this for us
65 // between when we released the read lock and aquired the write lock,
65 // between when we released the read lock and acquired the write lock,
6666 // so we just return that value.
6767 return interp_ok(*occupied_entry.get());
6868 }
src/tools/miri/src/concurrency/genmc/mod.rs+5-5
......@@ -252,7 +252,7 @@ impl GenmcCtx {
252252 /// Inform GenMC about an atomic load.
253253 /// Returns that value that the load should read.
254254 ///
255 /// `old_value` is the value that a non-atomic load would read here, or `None` if the memory is uninitalized.
255 /// `old_value` is the value that a non-atomic load would read here, or `None` if the memory is uninitialized.
256256 pub(crate) fn atomic_load<'tcx>(
257257 &self,
258258 ecx: &InterpCx<'tcx, MiriMachine<'tcx>>,
......@@ -275,7 +275,7 @@ impl GenmcCtx {
275275 /// Inform GenMC about an atomic store.
276276 /// Returns `true` if the stored value should be reflected in Miri's memory.
277277 ///
278 /// `old_value` is the value that a non-atomic load would read here, or `None` if the memory is uninitalized.
278 /// `old_value` is the value that a non-atomic load would read here, or `None` if the memory is uninitialized.
279279 pub(crate) fn atomic_store<'tcx>(
280280 &self,
281281 ecx: &InterpCx<'tcx, MiriMachine<'tcx>>,
......@@ -320,7 +320,7 @@ impl GenmcCtx {
320320 ///
321321 /// Returns `(old_val, Option<new_val>)`. `new_val` might not be the latest write in coherence order, which is indicated by `None`.
322322 ///
323 /// `old_value` is the value that a non-atomic load would read here, or `None` if the memory is uninitalized.
323 /// `old_value` is the value that a non-atomic load would read here, or `None` if the memory is uninitialized.
324324 pub(crate) fn atomic_rmw_op<'tcx>(
325325 &self,
326326 ecx: &InterpCx<'tcx, MiriMachine<'tcx>>,
......@@ -345,7 +345,7 @@ impl GenmcCtx {
345345
346346 /// Returns `(old_val, Option<new_val>)`. `new_val` might not be the latest write in coherence order, which is indicated by `None`.
347347 ///
348 /// `old_value` is the value that a non-atomic load would read here, or `None` if the memory is uninitalized.
348 /// `old_value` is the value that a non-atomic load would read here, or `None` if the memory is uninitialized.
349349 pub(crate) fn atomic_exchange<'tcx>(
350350 &self,
351351 ecx: &InterpCx<'tcx, MiriMachine<'tcx>>,
......@@ -370,7 +370,7 @@ impl GenmcCtx {
370370 ///
371371 /// Returns the old value read by the compare exchange, optionally the value that Miri should write back to its memory, and whether the compare-exchange was a success or not.
372372 ///
373 /// `old_value` is the value that a non-atomic load would read here, or `None` if the memory is uninitalized.
373 /// `old_value` is the value that a non-atomic load would read here, or `None` if the memory is uninitialized.
374374 pub(crate) fn atomic_compare_exchange<'tcx>(
375375 &self,
376376 ecx: &InterpCx<'tcx, MiriMachine<'tcx>>,
src/tools/miri/src/concurrency/genmc/run.rs+1-1
......@@ -30,7 +30,7 @@ pub fn run_genmc_mode<'tcx>(
3030 config: &MiriConfig,
3131 eval_entry: impl Fn(Rc<GenmcCtx>) -> Result<(), NonZeroI32>,
3232) -> Result<(), NonZeroI32> {
33 // Check for supported target: endianess and pointer size must match the host.
33 // Check for supported target: endianness and pointer size must match the host.
3434 if tcx.data_layout.endian != Endian::Little || tcx.data_layout.pointer_size().bits() != 64 {
3535 tcx.dcx().fatal("GenMC only supports 64bit little-endian targets");
3636 }
src/tools/miri/src/concurrency/weak_memory.rs+1-1
......@@ -389,7 +389,7 @@ impl<'tcx> StoreBuffer {
389389 })
390390 .filter(|&store_elem| {
391391 if is_seqcst && store_elem.is_seqcst {
392 // An SC load needs to ignore all but last store maked SC (stores not marked SC are not
392 // An SC load needs to ignore all but last store marked SC (stores not marked SC are not
393393 // affected)
394394 let include = !found_sc;
395395 found_sc = true;
src/tools/miri/src/eval.rs+1-1
......@@ -113,7 +113,7 @@ pub struct MiriConfig {
113113 pub float_nondet: bool,
114114 /// Whether floating-point operations can have a non-deterministic rounding error.
115115 pub float_rounding_error: FloatRoundingErrorMode,
116 /// Whether Miri artifically introduces short reads/writes on file descriptors.
116 /// Whether Miri artificially introduces short reads/writes on file descriptors.
117117 pub short_fd_operations: bool,
118118 /// A list of crates that are considered user-relevant.
119119 pub user_relevant_crates: Vec<String>,
src/tools/miri/src/helpers.rs+2-2
......@@ -138,7 +138,7 @@ pub fn iter_exported_symbols<'tcx>(
138138 }
139139
140140 // Next, all our dependencies.
141 // `dependency_formats` includes all the transitive informations needed to link a crate,
141 // `dependency_formats` includes all the transitive information needed to link a crate,
142142 // which is what we need here since we need to dig out `exported_symbols` from all transitive
143143 // dependencies.
144144 let dependency_formats = tcx.dependency_formats(());
......@@ -1148,7 +1148,7 @@ impl ToUsize for u32 {
11481148}
11491149
11501150/// Similarly, a maximum address size of `u64` is assumed widely here, so let's have ergonomic
1151/// converion from `usize` to `u64`.
1151/// conversion from `usize` to `u64`.
11521152pub trait ToU64 {
11531153 fn to_u64(self) -> u64;
11541154}
src/tools/miri/src/machine.rs+2-2
......@@ -654,7 +654,7 @@ pub struct MiriMachine<'tcx> {
654654 /// Whether floating-point operations can have a non-deterministic rounding error.
655655 pub float_rounding_error: FloatRoundingErrorMode,
656656
657 /// Whether Miri artifically introduces short reads/writes on file descriptors.
657 /// Whether Miri artificially introduces short reads/writes on file descriptors.
658658 pub short_fd_operations: bool,
659659}
660660
......@@ -1802,7 +1802,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
18021802 // We have to skip the frame that is just being popped.
18031803 ecx.active_thread_mut().recompute_top_user_relevant_frame(/* skip */ 1);
18041804 }
1805 // tracing-tree can autoamtically annotate scope changes, but it gets very confused by our
1805 // tracing-tree can automatically annotate scope changes, but it gets very confused by our
18061806 // concurrency and what it prints is just plain wrong. So we print our own information
18071807 // instead. (Cc https://github.com/rust-lang/miri/issues/2266)
18081808 info!("Leaving {}", ecx.frame().instance());
src/tools/miri/src/shims/aarch64.rs+26
......@@ -58,7 +58,33 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
5858 this.write_immediate(*res_lane, &dest)?;
5959 }
6060 }
61 // Vector table lookup: each index selects a byte from the 16-byte table, out-of-range -> 0.
62 // Used to implement vtbl1_u8 function.
63 // LLVM does not have a portable shuffle that takes non-const indices
64 // so we need to implement this ourselves.
65 // https://developer.arm.com/architectures/instruction-sets/intrinsics/vtbl1_u8
66 "neon.tbl1.v16i8" => {
67 let [table, indices] =
68 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
69
70 let (table, table_len) = this.project_to_simd(table)?;
71 let (indices, idx_len) = this.project_to_simd(indices)?;
72 let (dest, dest_len) = this.project_to_simd(dest)?;
73 assert_eq!(table_len, 16);
74 assert_eq!(idx_len, dest_len);
6175
76 for i in 0..dest_len {
77 let idx = this.read_immediate(&this.project_index(&indices, i)?)?;
78 let idx_u = idx.to_scalar().to_u8()?;
79 let val = if u64::from(idx_u) < table_len {
80 let t = this.read_immediate(&this.project_index(&table, idx_u.into())?)?;
81 t.to_scalar()
82 } else {
83 Scalar::from_u8(0)
84 };
85 this.write_scalar(val, &this.project_index(&dest, i)?)?;
86 }
87 }
6288 _ => return interp_ok(EmulateItemResult::NotSupported),
6389 }
6490 interp_ok(EmulateItemResult::NeedsReturn)
src/tools/miri/src/shims/native_lib/trace/child.rs+1-1
......@@ -31,7 +31,7 @@ pub struct Supervisor {
3131 /// Used for synchronisation, allowing us to receive confirmation that the
3232 /// parent process has handled the request from `message_tx`.
3333 confirm_rx: ipc::IpcReceiver<Confirmation>,
34 /// Receiver for memory acceses that ocurred during the FFI call.
34 /// Receiver for memory accesses that occurred during the FFI call.
3535 event_rx: ipc::IpcReceiver<MemEvents>,
3636}
3737
src/tools/miri/src/shims/native_lib/trace/parent.rs-2
......@@ -395,8 +395,6 @@ fn capstone_find_events(
395395 _ => (),
396396 }
397397 }
398 // FIXME: arm64
399 _ => unimplemented!(),
400398 }
401399
402400 false
src/tools/miri/src/shims/os_str.rs+1-1
......@@ -316,7 +316,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
316316 // The new path is still absolute on Windows.
317317 path.remove(0);
318318 }
319 // If this starts withs a `\` but not a `\\`, then this was absolute on Unix but is
319 // If this starts with a `\` but not a `\\`, then this was absolute on Unix but is
320320 // relative on Windows (relative to "the root of the current directory", e.g. the
321321 // drive letter).
322322 else if path.first() == Some(&sep) && path.get(1) != Some(&sep) {
src/tools/miri/src/shims/time.rs+2-2
......@@ -401,11 +401,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
401401 };
402402
403403 let timeout_anchor = if flags == 0 {
404 // No flags set, the timespec should be interperted as a duration
404 // No flags set, the timespec should be interpreted as a duration
405405 // to sleep for
406406 TimeoutAnchor::Relative
407407 } else if flags == this.eval_libc_i32("TIMER_ABSTIME") {
408 // Only flag TIMER_ABSTIME set, the timespec should be interperted as
408 // Only flag TIMER_ABSTIME set, the timespec should be interpreted as
409409 // an absolute time.
410410 TimeoutAnchor::Absolute
411411 } else {
src/tools/miri/src/shims/unix/foreign_items.rs+1-1
......@@ -1045,7 +1045,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
10451045 &[Os::Linux, Os::FreeBsd, Os::Illumos, Os::Solaris, Os::Android, Os::MacOs],
10461046 link_name,
10471047 )?;
1048 // This function looks and behaves excatly like miri_start_unwind.
1048 // This function looks and behaves exactly like miri_start_unwind.
10491049 let [payload] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
10501050 this.handle_miri_start_unwind(payload)?;
10511051 return interp_ok(EmulateItemResult::NeedsUnwind);
src/tools/miri/src/shims/unix/freebsd/sync.rs+1-1
......@@ -169,7 +169,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
169169 let Some(futex_ref) =
170170 this.get_sync_or_init(obj, |_| FreeBsdFutex { futex: Default::default() })
171171 else {
172 // From Linux implemenation:
172 // From Linux implementation:
173173 // No AllocId, or no live allocation at that AllocId.
174174 // Return an error code. (That seems nicer than silently doing something non-intuitive.)
175175 // This means that if an address gets reused by a new allocation,
src/tools/miri/src/shims/unix/linux/foreign_items.rs+2-2
......@@ -165,7 +165,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
165165 )? {
166166 ThreadNameResult::Ok => Scalar::from_u32(0),
167167 ThreadNameResult::NameTooLong => this.eval_libc("ERANGE"),
168 // Act like we faild to open `/proc/self/task/$tid/comm`.
168 // Act like we failed to open `/proc/self/task/$tid/comm`.
169169 ThreadNameResult::ThreadNotFound => this.eval_libc("ENOENT"),
170170 };
171171 this.write_scalar(res, dest)?;
......@@ -186,7 +186,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
186186 )? {
187187 ThreadNameResult::Ok => Scalar::from_u32(0),
188188 ThreadNameResult::NameTooLong => unreachable!(),
189 // Act like we faild to open `/proc/self/task/$tid/comm`.
189 // Act like we failed to open `/proc/self/task/$tid/comm`.
190190 ThreadNameResult::ThreadNotFound => this.eval_libc("ENOENT"),
191191 }
192192 } else {
src/tools/miri/src/shims/unix/linux_like/epoll.rs+1-1
......@@ -176,7 +176,7 @@ impl EpollInterestTable {
176176 if let Some(epolls) = self.0.remove(&id) {
177177 for epoll in epolls.iter().filter_map(|(_id, epoll)| epoll.upgrade()) {
178178 // This is a still-live epoll with interest in this FD. Remove all
179 // relevent interests (including from the ready set).
179 // relevant interests (including from the ready set).
180180 epoll
181181 .interest_list
182182 .borrow_mut()
src/tools/miri/src/shims/unix/macos/sync.rs+1-1
......@@ -169,7 +169,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
169169
170170 let is_shared = flags == shared;
171171 let timeout = clock_timeout.map(|(_, anchor, timeout)| {
172 // The only clock that is currenlty supported is the monotonic clock.
172 // The only clock that is currently supported is the monotonic clock.
173173 // While the deadline argument of `os_sync_wait_on_address_with_deadline`
174174 // is actually not in nanoseconds but in the units of `mach_current_time`,
175175 // the two are equivalent in miri.
src/tools/miri/src/shims/windows/foreign_items.rs+1-1
......@@ -1199,7 +1199,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
11991199 "`_Unwind_RaiseException` is not supported on non-MinGW Windows",
12001200 );
12011201 }
1202 // This function looks and behaves excatly like miri_start_unwind.
1202 // This function looks and behaves exactly like miri_start_unwind.
12031203 let [payload] = this.check_shim_sig(
12041204 shim_sig!(extern "C" fn(*mut _) -> unwind::libunwind::_Unwind_Reason_Code),
12051205 link_name,
src/tools/miri/src/shims/windows/sync.rs+1-1
......@@ -67,7 +67,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
6767 )
6868 }
6969
70 /// Returns `true` if we were succssful, `false` if we would block.
70 /// Returns `true` if we were successful, `false` if we would block.
7171 fn init_once_try_begin(
7272 &mut self,
7373 init_once_ref: &InitOnceRef,
src/tools/miri/src/shims/x86/avx2.rs+1-1
......@@ -194,7 +194,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
194194 // Used to implement the _mm256_sign_epi{8,16,32} functions.
195195 // Negates elements from `left` when the corresponding element in
196196 // `right` is negative. If an element from `right` is zero, zero
197 // is writen to the corresponding output element.
197 // is written to the corresponding output element.
198198 // Basically, we multiply `left` with `right.signum()`.
199199 "psign.b" | "psign.w" | "psign.d" => {
200200 let [left, right] =
src/tools/miri/src/shims/x86/bmi.rs+1-1
......@@ -44,7 +44,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
4444 let right = if is_64_bit { right.to_u64()? } else { u64::from(right.to_u32()?) };
4545
4646 let result = match unprefixed_name {
47 // Extract a contigous range of bits from an unsigned integer.
47 // Extract a contiguous range of bits from an unsigned integer.
4848 // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_bextr_u32
4949 "bextr" => {
5050 let start = u32::try_from(right & 0xff).unwrap();
src/tools/miri/src/shims/x86/sse.rs+2-2
......@@ -24,8 +24,8 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
2424 // Prefix should have already been checked.
2525 let unprefixed_name = link_name.as_str().strip_prefix("llvm.x86.sse.").unwrap();
2626 // All these intrinsics operate on 128-bit (f32x4) SIMD vectors unless stated otherwise.
27 // Many intrinsic names are sufixed with "ps" (packed single) or "ss" (scalar single),
28 // where single means single precision floating point (f32). "ps" means thet the operation
27 // Many intrinsic names are suffixed with "ps" (packed single) or "ss" (scalar single),
28 // where single means single precision floating point (f32). "ps" means that the operation
2929 // is performed on each element of the vector, while "ss" means that the operation is
3030 // performed only on the first element, copying the remaining elements from the input
3131 // vector (for binary operations, from the left-hand side).
src/tools/miri/src/shims/x86/sse2.rs+3-3
......@@ -26,14 +26,14 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
2626
2727 // These intrinsics operate on 128-bit (f32x4, f64x2, i8x16, i16x8, i32x4, i64x2) SIMD
2828 // vectors unless stated otherwise.
29 // Many intrinsic names are sufixed with "ps" (packed single), "ss" (scalar signle),
29 // Many intrinsic names are suffixed with "ps" (packed single), "ss" (scalar single),
3030 // "pd" (packed double) or "sd" (scalar double), where single means single precision
3131 // floating point (f32) and double means double precision floating point (f64). "ps"
32 // and "pd" means thet the operation is performed on each element of the vector, while
32 // and "pd" means that the operation is performed on each element of the vector, while
3333 // "ss" and "sd" means that the operation is performed only on the first element, copying
3434 // the remaining elements from the input vector (for binary operations, from the left-hand
3535 // side).
36 // Intrinsincs sufixed with "epiX" or "epuX" operate with X-bit signed or unsigned
36 // Intrinsics suffixed with "epiX" or "epuX" operate with X-bit signed or unsigned
3737 // vectors.
3838 match unprefixed_name {
3939 // Used to implement the _mm_sad_epu8 function.
src/tools/miri/src/shims/x86/sse41.rs+1-1
......@@ -115,7 +115,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
115115 round_all::<rustc_apfloat::ieee::Double>(this, op, rounding, dest)?;
116116 }
117117 // Used to implement the _mm_minpos_epu16 function.
118 // Find the minimum unsinged 16-bit integer in `op` and
118 // Find the minimum unsigned 16-bit integer in `op` and
119119 // returns its value and position.
120120 "phminposuw" => {
121121 let [op] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
src/tools/miri/src/shims/x86/sse42.rs+3-3
......@@ -213,7 +213,7 @@ fn deconstruct_args<'tcx>(
213213 };
214214
215215 // The fourth letter of each string comparison intrinsic is either 'e' for "explicit" or 'i' for "implicit".
216 // The distinction will correspond to the intrinsics type signature. In this constext, "explicit" and "implicit"
216 // The distinction will correspond to the intrinsics type signature. In this context, "explicit" and "implicit"
217217 // refer to the way the string length is determined. The length is either passed explicitly in the "explicit"
218218 // case or determined by a null terminator in the "implicit" case.
219219 let is_explicit = match unprefixed_name.as_bytes().get(4) {
......@@ -297,7 +297,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
297297 deconstruct_args(unprefixed_name, this, link_name, abi, args)?;
298298 let mask = compare_strings(this, &str1, &str2, len, imm)?;
299299
300 // The sixth bit inside the immediate byte distiguishes
300 // The sixth bit inside the immediate byte distinguishes
301301 // between a bit mask or a byte mask when generating a mask.
302302 if imm & 0b100_0000 != 0 {
303303 let (array_layout, size) = if imm & USE_WORDS != 0 {
......@@ -347,7 +347,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
347347 let mask = compare_strings(this, &str1, &str2, len, imm)?;
348348
349349 let len = default_len::<u32>(imm);
350 // The sixth bit inside the immediate byte distiguishes between the least
350 // The sixth bit inside the immediate byte distinguishes between the least
351351 // significant bit and the most significant bit when generating an index.
352352 let result = if imm & 0b100_0000 != 0 {
353353 // most significant bit
src/tools/miri/src/shims/x86/ssse3.rs+1-1
......@@ -68,7 +68,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
6868 // Used to implement the _mm_sign_epi{8,16,32} functions.
6969 // Negates elements from `left` when the corresponding element in
7070 // `right` is negative. If an element from `right` is zero, zero
71 // is writen to the corresponding output element.
71 // is written to the corresponding output element.
7272 // Basically, we multiply `left` with `right.signum()`.
7373 "psign.b.128" | "psign.w.128" | "psign.d.128" => {
7474 let [left, right] =
src/tools/miri/tests/deps/Cargo.lock+2-2
......@@ -46,9 +46,9 @@ checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43"
4646
4747[[package]]
4848name = "bytes"
49version = "1.10.1"
49version = "1.11.1"
5050source = "registry+https://github.com/rust-lang/crates.io-index"
51checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a"
51checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33"
5252
5353[[package]]
5454name = "cfg-if"
src/tools/miri/tests/deps/src/main.rs+3-1
......@@ -1 +1,3 @@
1fn main() {}
1fn main() {
2 unreachable!()
3}
src/tools/miri/tests/fail-dep/libc/prctl-get-name-buffer-too-small.stderr-1
......@@ -11,7 +11,6 @@ help: ALLOC was allocated here:
1111 |
1212LL | let mut buf = vec![0u8; 15];
1313 | ^^^^^^^^^^^^^
14 = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
1514
1615note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
1716
src/tools/miri/tests/fail/match/all_variants_uninhabited.rs+1-1
......@@ -5,7 +5,7 @@ enum Never {}
55fn main() {
66 unsafe {
77 match *std::ptr::null::<Result<Never, Never>>() {
8 //~^ ERROR: read discriminant of an uninhabited enum variant
8 //~^ ERROR: read discriminant of an uninhabited enum variant
99 Ok(_) => {
1010 lol();
1111 }
src/tools/miri/tests/fail/match/closures/uninhabited-variant2.rs+2-1
......@@ -22,7 +22,8 @@ fn main() {
2222 // After rust-lang/rust#138961, constructing the closure performs a reborrow of r.
2323 // Nevertheless, the discriminant is only actually inspected when the closure
2424 // is called.
25 match r { //~ ERROR: read discriminant of an uninhabited enum variant
25 match r {
26 //~^ ERROR: read discriminant of an uninhabited enum variant
2627 E::V0 => {}
2728 E::V1(_) => {}
2829 }
src/tools/miri/tests/fail/match/only_inhabited_variant.rs+4-3
......@@ -4,8 +4,8 @@
44#[repr(C)]
55#[allow(dead_code)]
66enum E {
7 V0, // discriminant: 0
8 V1(!), // 1
7 V0, // discriminant: 0
8 V1(!), // 1
99}
1010
1111fn main() {
......@@ -14,7 +14,8 @@ fn main() {
1414 let val = 1u32;
1515 let ptr = (&raw const val).cast::<E>();
1616 let r = unsafe { &*ptr };
17 match r { //~ ERROR: read discriminant of an uninhabited enum variant
17 match r {
18 //~^ ERROR: read discriminant of an uninhabited enum variant
1819 E::V0 => {}
1920 E::V1(_) => {}
2021 }
src/tools/miri/tests/fail/match/single_variant.rs+4-3
......@@ -20,12 +20,13 @@ fn main() {
2020 let x: &[u8; 2] = &[21, 37];
2121 let y: &Exhaustive = std::mem::transmute(x);
2222 match y {
23 Exhaustive::A(_) => {},
23 Exhaustive::A(_) => {}
2424 }
2525
2626 let y: &NonExhaustive = std::mem::transmute(x);
27 match y { //~ ERROR: enum value has invalid tag
28 NonExhaustive::A(_) => {},
27 match y {
28 //~^ ERROR: enum value has invalid tag
29 NonExhaustive::A(_) => {}
2930 }
3031 }
3132}
src/tools/miri/tests/fail/match/single_variant_uninit.rs+2-1
......@@ -28,7 +28,8 @@ fn main() {
2828 _ => {}
2929 }
3030
31 match *nexh { //~ ERROR: memory is uninitialized
31 match *nexh {
32 //~^ ERROR: memory is uninitialized
3233 NonExhaustive::A(ref _val) => {}
3334 _ => {}
3435 }
src/tools/miri/tests/fail/validity/uninhabited_variant.rs created+17
......@@ -0,0 +1,17 @@
1// NOTE: this is essentially a smoke-test, with more comprehensive tests living in the rustc
2// repository at tests/ui/consts/const-eval/ub-enum.rs
3#![feature(never_type)]
4
5#[repr(C)]
6#[allow(dead_code)]
7enum E {
8 V1, // discriminant: 0
9 V2(!), // 1
10}
11
12fn main() {
13 unsafe {
14 std::mem::transmute::<u32, E>(1);
15 //~^ ERROR: encountered an uninhabited enum variant
16 }
17}
src/tools/miri/tests/fail/validity/uninhabited_variant.stderr created+13
......@@ -0,0 +1,13 @@
1error: Undefined Behavior: constructing invalid value at .<enum-tag>: encountered an uninhabited enum variant
2 --> tests/fail/validity/uninhabited_variant.rs:LL:CC
3 |
4LL | std::mem::transmute::<u32, E>(1);
5 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here
6 |
7 = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
8 = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
9
10note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
11
12error: aborting due to 1 previous error
13
src/tools/miri/tests/pass/align_strange_enum_discriminant_offset.rs+2-3
......@@ -1,5 +1,4 @@
1#![allow(unused)]
2
1#[allow(unused)]
32#[repr(u16)]
43enum DeviceKind {
54 Nil = 0,
......@@ -19,5 +18,5 @@ fn main() {
1918 let x = None::<(DeviceInfo, u8)>;
2019 let y = None::<(DeviceInfo, u16)>;
2120 let z = None::<(DeviceInfo, u64)>;
22 format!("{} {} {}", x.is_some(), y.is_some(), y.is_some());
21 let _out = format!("{} {} {}", x.is_some(), y.is_some(), z.is_some());
2322}
src/tools/miri/tests/pass/async-closure.rs-1
......@@ -1,5 +1,4 @@
11#![feature(async_fn_traits)]
2#![allow(unused)]
32
43use std::future::Future;
54use std::ops::{AsyncFn, AsyncFnMut, AsyncFnOnce};
src/tools/miri/tests/pass/shims/aarch64/intrinsics-aarch64-neon.rs+29-2
......@@ -4,17 +4,19 @@
44
55use std::arch::aarch64::*;
66use std::arch::is_aarch64_feature_detected;
7use std::mem::transmute;
78
89fn main() {
910 assert!(is_aarch64_feature_detected!("neon"));
1011
1112 unsafe {
12 test_neon();
13 test_vpmaxq_u8();
14 test_tbl1_v16i8_basic();
1315 }
1416}
1517
1618#[target_feature(enable = "neon")]
17unsafe fn test_neon() {
19unsafe fn test_vpmaxq_u8() {
1820 // Adapted from library/stdarch/crates/core_arch/src/aarch64/neon/mod.rs
1921 unsafe fn test_vpmaxq_u8() {
2022 let a = vld1q_u8([1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8].as_ptr());
......@@ -38,3 +40,28 @@ unsafe fn test_neon() {
3840 }
3941 test_vpmaxq_u8_is_unsigned();
4042}
43
44#[target_feature(enable = "neon")]
45fn test_tbl1_v16i8_basic() {
46 unsafe {
47 // table = 0..15
48 let table: uint8x16_t =
49 transmute::<[u8; 16], _>([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]);
50 // indices
51 let idx: uint8x16_t =
52 transmute::<[u8; 16], _>([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]);
53 let got = vqtbl1q_u8(table, idx);
54 let got_arr: [u8; 16] = transmute(got);
55 assert_eq!(got_arr, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]);
56
57 // Also try different order and out-of-range indices (16, 255).
58 let idx2: uint8x16_t =
59 transmute::<[u8; 16], _>([15, 16, 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]);
60 let got2 = vqtbl1q_u8(table, idx2);
61 let got2_arr: [u8; 16] = transmute(got2);
62 assert_eq!(got2_arr[0], 15);
63 assert_eq!(got2_arr[1], 0); // out-of-range
64 assert_eq!(got2_arr[2], 0); // out-of-range
65 assert_eq!(&got2_arr[3..16], &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12][..]);
66 }
67}
src/tools/miri/tests/ui.rs+14-8
......@@ -132,14 +132,19 @@ fn miri_config(
132132 // (It's a separate crate, so we don't get an env var from cargo.)
133133 program: miri_path()
134134 .with_file_name(format!("cargo-miri{}", env::consts::EXE_SUFFIX)),
135 // There is no `cargo miri build` so we just use `cargo miri run`.
136135 // Add `-Zbinary-dep-depinfo` since it is needed for bootstrap builds (and doesn't harm otherwise).
137 args: ["miri", "run", "--quiet", "-Zbinary-dep-depinfo"]
136 args: ["miri", "build", "-Zbinary-dep-depinfo"]
138137 .into_iter()
139138 .map(Into::into)
140139 .collect(),
141 // Reset `RUSTFLAGS` to work around <https://github.com/rust-lang/rust/pull/119574#issuecomment-1876878344>.
142 envs: vec![("RUSTFLAGS".into(), None)],
140 envs: vec![
141 // Reset `RUSTFLAGS` to work around <https://github.com/rust-lang/rust/pull/119574#issuecomment-1876878344>.
142 ("RUSTFLAGS".into(), None),
143 // Reset `MIRIFLAGS` because it caused trouble in the past and should not be needed.
144 ("MIRIFLAGS".into(), None),
145 // Allow `cargo miri build`.
146 ("MIRI_BUILD_TEST_DEPS".into(), Some("1".into())),
147 ],
143148 ..CommandBuilder::cargo()
144149 },
145150 crate_manifest_path: Path::new("tests/deps").join("Cargo.toml"),
......@@ -361,15 +366,16 @@ fn run_dep_mode(target: String, args: impl Iterator<Item = OsString>) -> Result<
361366 miri_config(&target, "", Mode::RunDep, Some(WithDependencies { bless: false }));
362367 config.comment_defaults.base().custom.remove("edition"); // `./miri` adds an `--edition` in `args`, so don't set it twice
363368 config.fill_host_and_target()?;
369 let dep_builder = BuildManager::one_off(config.clone());
370 // Only set these for the actual run, not the dep builder, so invalid flags do not fail
371 // the dependency build.
364372 config.program.args = args.collect();
373 let test_config = TestConfig::one_off_runner(config, PathBuf::new());
365374
366 let test_config = TestConfig::one_off_runner(config.clone(), PathBuf::new());
367
368 let build_manager = BuildManager::one_off(config);
369375 let mut cmd = test_config.config.program.build(&test_config.config.out_dir);
370376 cmd.arg("--target").arg(test_config.config.target.as_ref().unwrap());
371377 // Build dependencies
372 test_config.apply_custom(&mut cmd, &build_manager).unwrap();
378 test_config.apply_custom(&mut cmd, &dep_builder).expect("failed to build dependencies");
373379
374380 if cmd.spawn()?.wait()?.success() { Ok(()) } else { std::process::exit(1) }
375381}
src/tools/rust-analyzer/.github/workflows/ci.yaml+29-8
......@@ -96,7 +96,7 @@ jobs:
9696 run: |
9797 rustup update --no-self-update stable
9898 rustup default stable
99 rustup component add --toolchain stable rust-src clippy rustfmt
99 rustup component add --toolchain stable rust-src rustfmt
100100 # We also install a nightly rustfmt, because we use `--file-lines` in
101101 # a test.
102102 rustup toolchain install nightly --profile minimal --component rustfmt
......@@ -128,10 +128,6 @@ jobs:
128128 - name: Run cargo-machete
129129 run: cargo machete
130130
131 - name: Run Clippy
132 if: matrix.os == 'macos-latest'
133 run: cargo clippy --all-targets -- -D clippy::disallowed_macros -D clippy::dbg_macro -D clippy::todo -D clippy::print_stdout -D clippy::print_stderr
134
135131 analysis-stats:
136132 if: github.repository == 'rust-lang/rust-analyzer'
137133 runs-on: ubuntu-latest
......@@ -178,6 +174,28 @@ jobs:
178174
179175 - run: cargo fmt -- --check
180176
177 clippy:
178 if: github.repository == 'rust-lang/rust-analyzer'
179 runs-on: ubuntu-latest
180
181 steps:
182 - name: Checkout repository
183 uses: actions/checkout@v4
184
185 # Note that clippy output is currently dependent on whether rust-src is installed,
186 # https://github.com/rust-lang/rust-clippy/issues/14625
187 - name: Install Rust toolchain
188 run: |
189 rustup update --no-self-update stable
190 rustup default stable
191 rustup component add --toolchain stable rust-src clippy
192
193 # https://github.com/actions-rust-lang/setup-rust-toolchain/blob/main/rust.json
194 - name: Install Rust Problem Matcher
195 run: echo "::add-matcher::.github/rust.json"
196
197 - run: cargo clippy --all-targets -- -D clippy::disallowed_macros -D clippy::dbg_macro -D clippy::todo -D clippy::print_stdout -D clippy::print_stderr
198
181199 miri:
182200 if: github.repository == 'rust-lang/rust-analyzer'
183201 runs-on: ubuntu-latest
......@@ -188,8 +206,11 @@ jobs:
188206
189207 - name: Install Rust toolchain
190208 run: |
191 rustup update --no-self-update nightly
192 rustup default nightly
209 # FIXME: Pin nightly due to a regression in miri on nightly-2026-02-12.
210 # See https://github.com/rust-lang/miri/issues/4855.
211 # Revert to plain `nightly` once this is fixed upstream.
212 rustup toolchain install nightly-2026-02-10
213 rustup default nightly-2026-02-10
193214 rustup component add miri
194215
195216 # - name: Cache Dependencies
......@@ -309,7 +330,7 @@ jobs:
309330 run: typos
310331
311332 conclusion:
312 needs: [rust, rust-cross, typescript, typo-check, proc-macro-srv, miri, rustfmt, analysis-stats]
333 needs: [rust, rust-cross, typescript, typo-check, proc-macro-srv, miri, rustfmt, clippy, analysis-stats]
313334 # We need to ensure this job does *not* get skipped if its dependencies fail,
314335 # because a skipped job is considered a success by GitHub. So we have to
315336 # overwrite `if:`. We use `!cancelled()` to ensure the job does still not get run
src/tools/rust-analyzer/Cargo.lock+7-6
......@@ -1845,6 +1845,7 @@ dependencies = [
18451845 "paths",
18461846 "postcard",
18471847 "proc-macro-srv",
1848 "rayon",
18481849 "rustc-hash 2.1.1",
18491850 "semver",
18501851 "serde",
......@@ -2453,9 +2454,9 @@ checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
24532454
24542455[[package]]
24552456name = "salsa"
2456version = "0.26.0"
2457version = "0.25.2"
24572458source = "registry+https://github.com/rust-lang/crates.io-index"
2458checksum = "f77debccd43ba198e9cee23efd7f10330ff445e46a98a2b107fed9094a1ee676"
2459checksum = "e2e2aa2fca57727371eeafc975acc8e6f4c52f8166a78035543f6ee1c74c2dcc"
24592460dependencies = [
24602461 "boxcar",
24612462 "crossbeam-queue",
......@@ -2478,15 +2479,15 @@ dependencies = [
24782479
24792480[[package]]
24802481name = "salsa-macro-rules"
2481version = "0.26.0"
2482version = "0.25.2"
24822483source = "registry+https://github.com/rust-lang/crates.io-index"
2483checksum = "ea07adbf42d91cc076b7daf3b38bc8168c19eb362c665964118a89bc55ef19a5"
2484checksum = "1bfc2a1e7bf06964105515451d728f2422dedc3a112383324a00b191a5c397a3"
24842485
24852486[[package]]
24862487name = "salsa-macros"
2487version = "0.26.0"
2488version = "0.25.2"
24882489source = "registry+https://github.com/rust-lang/crates.io-index"
2489checksum = "d16d4d8b66451b9c75ddf740b7fc8399bc7b8ba33e854a5d7526d18708f67b05"
2490checksum = "3d844c1aa34946da46af683b5c27ec1088a3d9d84a2b837a108223fd830220e1"
24902491dependencies = [
24912492 "proc-macro2",
24922493 "quote",
src/tools/rust-analyzer/Cargo.toml+2-2
......@@ -135,13 +135,13 @@ rayon = "1.10.0"
135135rowan = "=0.15.17"
136136# Ideally we'd not enable the macros feature but unfortunately the `tracked` attribute does not work
137137# on impls without it
138salsa = { version = "0.26", default-features = false, features = [
138salsa = { version = "0.25.2", default-features = false, features = [
139139 "rayon",
140140 "salsa_unstable",
141141 "macros",
142142 "inventory",
143143] }
144salsa-macros = "0.26"
144salsa-macros = "0.25.2"
145145semver = "1.0.26"
146146serde = { version = "1.0.219" }
147147serde_derive = { version = "1.0.219" }
src/tools/rust-analyzer/crates/base-db/src/editioned_file_id.rs+1-1
......@@ -60,7 +60,7 @@ const _: () = {
6060 }
6161 }
6262
63 impl zalsa_::HashEqLike<WithoutCrate> for EditionedFileIdData {
63 impl zalsa_struct_::HashEqLike<WithoutCrate> for EditionedFileIdData {
6464 #[inline]
6565 fn hash<H: Hasher>(&self, state: &mut H) {
6666 Hash::hash(self, state);
src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs+39-3
......@@ -32,8 +32,8 @@ use triomphe::Arc;
3232use tt::TextRange;
3333
3434use crate::{
35 AdtId, BlockId, BlockLoc, DefWithBodyId, FunctionId, GenericDefId, ImplId, MacroId,
36 ModuleDefId, ModuleId, TraitId, TypeAliasId, UnresolvedMacro,
35 AdtId, BlockId, BlockLoc, DefWithBodyId, FunctionId, GenericDefId, ImplId, ItemContainerId,
36 MacroId, ModuleDefId, ModuleId, TraitId, TypeAliasId, UnresolvedMacro,
3737 attrs::AttrFlags,
3838 db::DefDatabase,
3939 expr_store::{
......@@ -141,9 +141,19 @@ pub(super) fn lower_body(
141141 source_map_self_param = Some(collector.expander.in_file(AstPtr::new(&self_param_syn)));
142142 }
143143
144 let is_extern = matches!(
145 owner,
146 DefWithBodyId::FunctionId(id)
147 if matches!(id.loc(db).container, ItemContainerId::ExternBlockId(_)),
148 );
149
144150 for param in param_list.params() {
145151 if collector.check_cfg(&param) {
146 let param_pat = collector.collect_pat_top(param.pat());
152 let param_pat = if is_extern {
153 collector.collect_extern_fn_param(param.pat())
154 } else {
155 collector.collect_pat_top(param.pat())
156 };
147157 params.push(param_pat);
148158 }
149159 }
......@@ -2248,6 +2258,32 @@ impl<'db> ExprCollector<'db> {
22482258 }
22492259 }
22502260
2261 fn collect_extern_fn_param(&mut self, pat: Option<ast::Pat>) -> PatId {
2262 // `extern` functions cannot have pattern-matched parameters, and furthermore, the identifiers
2263 // in their parameters are always interpreted as bindings, even if in a normal function they
2264 // won't be, because they would refer to a path pattern.
2265 let Some(pat) = pat else { return self.missing_pat() };
2266
2267 match &pat {
2268 ast::Pat::IdentPat(bp) => {
2269 // FIXME: Emit an error if `!bp.is_simple_ident()`.
2270
2271 let name = bp.name().map(|nr| nr.as_name()).unwrap_or_else(Name::missing);
2272 let hygiene = bp
2273 .name()
2274 .map(|name| self.hygiene_id_for(name.syntax().text_range()))
2275 .unwrap_or(HygieneId::ROOT);
2276 let binding = self.alloc_binding(name, BindingAnnotation::Unannotated, hygiene);
2277 let pat =
2278 self.alloc_pat(Pat::Bind { id: binding, subpat: None }, AstPtr::new(&pat));
2279 self.add_definition_to_binding(binding, pat);
2280 pat
2281 }
2282 // FIXME: Emit an error.
2283 _ => self.missing_pat(),
2284 }
2285 }
2286
22512287 // region: patterns
22522288
22532289 fn collect_pat_top(&mut self, pat: Option<ast::Pat>) -> PatId {
src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs+5
......@@ -483,6 +483,11 @@ impl ItemScope {
483483 self.declarations.push(def)
484484 }
485485
486 pub(crate) fn remove_from_value_ns(&mut self, name: &Name, def: ModuleDefId) {
487 let entry = self.values.shift_remove(name);
488 assert!(entry.is_some_and(|entry| entry.def == def))
489 }
490
486491 pub(crate) fn get_legacy_macro(&self, name: &Name) -> Option<&[MacroId]> {
487492 self.legacy_macros.get(name).map(|it| &**it)
488493 }
src/tools/rust-analyzer/crates/hir-def/src/nameres.rs+8
......@@ -211,6 +211,7 @@ struct DefMapCrateData {
211211 /// Side table for resolving derive helpers.
212212 exported_derives: FxHashMap<MacroId, Box<[Name]>>,
213213 fn_proc_macro_mapping: FxHashMap<FunctionId, ProcMacroId>,
214 fn_proc_macro_mapping_back: FxHashMap<ProcMacroId, FunctionId>,
214215
215216 /// Custom tool modules registered with `#![register_tool]`.
216217 registered_tools: Vec<Symbol>,
......@@ -230,6 +231,7 @@ impl DefMapCrateData {
230231 Self {
231232 exported_derives: FxHashMap::default(),
232233 fn_proc_macro_mapping: FxHashMap::default(),
234 fn_proc_macro_mapping_back: FxHashMap::default(),
233235 registered_tools: PREDEFINED_TOOLS.iter().map(|it| Symbol::intern(it)).collect(),
234236 unstable_features: FxHashSet::default(),
235237 rustc_coherence_is_core: false,
......@@ -244,6 +246,7 @@ impl DefMapCrateData {
244246 let Self {
245247 exported_derives,
246248 fn_proc_macro_mapping,
249 fn_proc_macro_mapping_back,
247250 registered_tools,
248251 unstable_features,
249252 rustc_coherence_is_core: _,
......@@ -254,6 +257,7 @@ impl DefMapCrateData {
254257 } = self;
255258 exported_derives.shrink_to_fit();
256259 fn_proc_macro_mapping.shrink_to_fit();
260 fn_proc_macro_mapping_back.shrink_to_fit();
257261 registered_tools.shrink_to_fit();
258262 unstable_features.shrink_to_fit();
259263 }
......@@ -570,6 +574,10 @@ impl DefMap {
570574 self.data.fn_proc_macro_mapping.get(&id).copied()
571575 }
572576
577 pub fn proc_macro_as_fn(&self, id: ProcMacroId) -> Option<FunctionId> {
578 self.data.fn_proc_macro_mapping_back.get(&id).copied()
579 }
580
573581 pub fn krate(&self) -> Crate {
574582 self.krate
575583 }
src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs+10-2
......@@ -634,6 +634,7 @@ impl<'db> DefCollector<'db> {
634634 crate_data.exported_derives.insert(proc_macro_id.into(), helpers);
635635 }
636636 crate_data.fn_proc_macro_mapping.insert(fn_id, proc_macro_id);
637 crate_data.fn_proc_macro_mapping_back.insert(proc_macro_id, fn_id);
637638 }
638639
639640 /// Define a macro with `macro_rules`.
......@@ -2095,6 +2096,8 @@ impl ModCollector<'_, '_> {
20952096
20962097 let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]);
20972098
2099 update_def(self.def_collector, fn_id.into(), &it.name, vis, false);
2100
20982101 if self.def_collector.def_map.block.is_none()
20992102 && self.def_collector.is_proc_macro
21002103 && self.module_id == self.def_collector.def_map.root
......@@ -2105,9 +2108,14 @@ impl ModCollector<'_, '_> {
21052108 InFile::new(self.file_id(), id),
21062109 fn_id,
21072110 );
2108 }
21092111
2110 update_def(self.def_collector, fn_id.into(), &it.name, vis, false);
2112 // A proc macro is implemented as a function, but it's treated as a macro, not a function.
2113 // You cannot call it like a function, for example, except in its defining crate.
2114 // So we keep the function definition, but remove it from the scope, leaving only the macro.
2115 self.def_collector.def_map[module_id]
2116 .scope
2117 .remove_from_value_ns(&it.name, fn_id.into());
2118 }
21112119 }
21122120 ModItemId::Struct(id) => {
21132121 let it = &self.item_tree[id];
src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/macros.rs+2-4
......@@ -1068,10 +1068,8 @@ pub fn derive_macro_2(_item: TokenStream) -> TokenStream {
10681068 - AnotherTrait : macro#
10691069 - DummyTrait : macro#
10701070 - TokenStream : type value
1071 - attribute_macro : value macro#
1072 - derive_macro : value
1073 - derive_macro_2 : value
1074 - function_like_macro : value macro!
1071 - attribute_macro : macro#
1072 - function_like_macro : macro!
10751073 "#]],
10761074 );
10771075}
src/tools/rust-analyzer/crates/hir-def/src/resolver.rs+36-37
......@@ -32,7 +32,7 @@ use crate::{
3232 BindingId, ExprId, LabelId,
3333 generics::{GenericParams, TypeOrConstParamData},
3434 },
35 item_scope::{BUILTIN_SCOPE, BuiltinShadowMode, ImportOrExternCrate, ImportOrGlob, ItemScope},
35 item_scope::{BUILTIN_SCOPE, BuiltinShadowMode, ImportOrExternCrate, ItemScope},
3636 lang_item::LangItemTarget,
3737 nameres::{DefMap, LocalDefMap, MacroSubNs, ResolvePathResultPrefixInfo, block_def_map},
3838 per_ns::PerNs,
......@@ -111,8 +111,8 @@ pub enum TypeNs {
111111
112112#[derive(Debug, Clone, PartialEq, Eq, Hash)]
113113pub enum ResolveValueResult {
114 ValueNs(ValueNs, Option<ImportOrGlob>),
115 Partial(TypeNs, usize, Option<ImportOrExternCrate>),
114 ValueNs(ValueNs),
115 Partial(TypeNs, usize),
116116}
117117
118118#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
......@@ -332,20 +332,17 @@ impl<'db> Resolver<'db> {
332332 Path::Normal(it) => &it.mod_path,
333333 Path::LangItem(l, None) => {
334334 return Some((
335 ResolveValueResult::ValueNs(
336 match *l {
337 LangItemTarget::FunctionId(it) => ValueNs::FunctionId(it),
338 LangItemTarget::StaticId(it) => ValueNs::StaticId(it),
339 LangItemTarget::StructId(it) => ValueNs::StructId(it),
340 LangItemTarget::EnumVariantId(it) => ValueNs::EnumVariantId(it),
341 LangItemTarget::UnionId(_)
342 | LangItemTarget::ImplId(_)
343 | LangItemTarget::TypeAliasId(_)
344 | LangItemTarget::TraitId(_)
345 | LangItemTarget::EnumId(_) => return None,
346 },
347 None,
348 ),
335 ResolveValueResult::ValueNs(match *l {
336 LangItemTarget::FunctionId(it) => ValueNs::FunctionId(it),
337 LangItemTarget::StaticId(it) => ValueNs::StaticId(it),
338 LangItemTarget::StructId(it) => ValueNs::StructId(it),
339 LangItemTarget::EnumVariantId(it) => ValueNs::EnumVariantId(it),
340 LangItemTarget::UnionId(_)
341 | LangItemTarget::ImplId(_)
342 | LangItemTarget::TypeAliasId(_)
343 | LangItemTarget::TraitId(_)
344 | LangItemTarget::EnumId(_) => return None,
345 }),
349346 ResolvePathResultPrefixInfo::default(),
350347 ));
351348 }
......@@ -363,7 +360,7 @@ impl<'db> Resolver<'db> {
363360 };
364361 // Remaining segments start from 0 because lang paths have no segments other than the remaining.
365362 return Some((
366 ResolveValueResult::Partial(type_ns, 0, None),
363 ResolveValueResult::Partial(type_ns, 0),
367364 ResolvePathResultPrefixInfo::default(),
368365 ));
369366 }
......@@ -388,10 +385,7 @@ impl<'db> Resolver<'db> {
388385
389386 if let Some(e) = entry {
390387 return Some((
391 ResolveValueResult::ValueNs(
392 ValueNs::LocalBinding(e.binding()),
393 None,
394 ),
388 ResolveValueResult::ValueNs(ValueNs::LocalBinding(e.binding())),
395389 ResolvePathResultPrefixInfo::default(),
396390 ));
397391 }
......@@ -404,14 +398,14 @@ impl<'db> Resolver<'db> {
404398 && *first_name == sym::Self_
405399 {
406400 return Some((
407 ResolveValueResult::ValueNs(ValueNs::ImplSelf(impl_), None),
401 ResolveValueResult::ValueNs(ValueNs::ImplSelf(impl_)),
408402 ResolvePathResultPrefixInfo::default(),
409403 ));
410404 }
411405 if let Some(id) = params.find_const_by_name(first_name, *def) {
412406 let val = ValueNs::GenericParam(id);
413407 return Some((
414 ResolveValueResult::ValueNs(val, None),
408 ResolveValueResult::ValueNs(val),
415409 ResolvePathResultPrefixInfo::default(),
416410 ));
417411 }
......@@ -431,7 +425,7 @@ impl<'db> Resolver<'db> {
431425 if let &GenericDefId::ImplId(impl_) = def {
432426 if *first_name == sym::Self_ {
433427 return Some((
434 ResolveValueResult::Partial(TypeNs::SelfType(impl_), 1, None),
428 ResolveValueResult::Partial(TypeNs::SelfType(impl_), 1),
435429 ResolvePathResultPrefixInfo::default(),
436430 ));
437431 }
......@@ -440,14 +434,14 @@ impl<'db> Resolver<'db> {
440434 {
441435 let ty = TypeNs::AdtSelfType(adt);
442436 return Some((
443 ResolveValueResult::Partial(ty, 1, None),
437 ResolveValueResult::Partial(ty, 1),
444438 ResolvePathResultPrefixInfo::default(),
445439 ));
446440 }
447441 if let Some(id) = params.find_type_by_name(first_name, *def) {
448442 let ty = TypeNs::GenericParam(id);
449443 return Some((
450 ResolveValueResult::Partial(ty, 1, None),
444 ResolveValueResult::Partial(ty, 1),
451445 ResolvePathResultPrefixInfo::default(),
452446 ));
453447 }
......@@ -473,7 +467,7 @@ impl<'db> Resolver<'db> {
473467 && let Some(builtin) = BuiltinType::by_name(first_name)
474468 {
475469 return Some((
476 ResolveValueResult::Partial(TypeNs::BuiltinType(builtin), 1, None),
470 ResolveValueResult::Partial(TypeNs::BuiltinType(builtin), 1),
477471 ResolvePathResultPrefixInfo::default(),
478472 ));
479473 }
......@@ -488,7 +482,7 @@ impl<'db> Resolver<'db> {
488482 hygiene: HygieneId,
489483 ) -> Option<ValueNs> {
490484 match self.resolve_path_in_value_ns(db, path, hygiene)? {
491 ResolveValueResult::ValueNs(it, _) => Some(it),
485 ResolveValueResult::ValueNs(it) => Some(it),
492486 ResolveValueResult::Partial(..) => None,
493487 }
494488 }
......@@ -1153,12 +1147,12 @@ impl<'db> ModuleItemMap<'db> {
11531147 );
11541148 match unresolved_idx {
11551149 None => {
1156 let (value, import) = to_value_ns(module_def)?;
1157 Some((ResolveValueResult::ValueNs(value, import), prefix_info))
1150 let value = to_value_ns(module_def, self.def_map)?;
1151 Some((ResolveValueResult::ValueNs(value), prefix_info))
11581152 }
11591153 Some(unresolved_idx) => {
1160 let def = module_def.take_types_full()?;
1161 let ty = match def.def {
1154 let def = module_def.take_types()?;
1155 let ty = match def {
11621156 ModuleDefId::AdtId(it) => TypeNs::AdtId(it),
11631157 ModuleDefId::TraitId(it) => TypeNs::TraitId(it),
11641158 ModuleDefId::TypeAliasId(it) => TypeNs::TypeAliasId(it),
......@@ -1171,7 +1165,7 @@ impl<'db> ModuleItemMap<'db> {
11711165 | ModuleDefId::MacroId(_)
11721166 | ModuleDefId::StaticId(_) => return None,
11731167 };
1174 Some((ResolveValueResult::Partial(ty, unresolved_idx, def.import), prefix_info))
1168 Some((ResolveValueResult::Partial(ty, unresolved_idx), prefix_info))
11751169 }
11761170 }
11771171 }
......@@ -1194,8 +1188,13 @@ impl<'db> ModuleItemMap<'db> {
11941188 }
11951189}
11961190
1197fn to_value_ns(per_ns: PerNs) -> Option<(ValueNs, Option<ImportOrGlob>)> {
1198 let (def, import) = per_ns.take_values_import()?;
1191fn to_value_ns(per_ns: PerNs, def_map: &DefMap) -> Option<ValueNs> {
1192 let def = per_ns.take_values().or_else(|| {
1193 let Some(MacroId::ProcMacroId(proc_macro)) = per_ns.take_macros() else { return None };
1194 // If we cannot resolve to value ns, but we can resolve to a proc macro, and this is the crate
1195 // defining this proc macro - inside this crate, we should treat the macro as a function.
1196 def_map.proc_macro_as_fn(proc_macro).map(ModuleDefId::FunctionId)
1197 })?;
11991198 let res = match def {
12001199 ModuleDefId::FunctionId(it) => ValueNs::FunctionId(it),
12011200 ModuleDefId::AdtId(AdtId::StructId(it)) => ValueNs::StructId(it),
......@@ -1210,7 +1209,7 @@ fn to_value_ns(per_ns: PerNs) -> Option<(ValueNs, Option<ImportOrGlob>)> {
12101209 | ModuleDefId::MacroId(_)
12111210 | ModuleDefId::ModuleId(_) => return None,
12121211 };
1213 Some((res, import))
1212 Some(res)
12141213}
12151214
12161215fn to_type_ns(per_ns: PerNs) -> Option<(TypeNs, Option<ImportOrExternCrate>)> {
src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs+1-1
......@@ -430,7 +430,7 @@ impl<'db> UnsafeVisitor<'db> {
430430 fn mark_unsafe_path(&mut self, node: ExprOrPatId, path: &Path) {
431431 let hygiene = self.body.expr_or_pat_path_hygiene(node);
432432 let value_or_partial = self.resolver.resolve_path_in_value_ns(self.db, path, hygiene);
433 if let Some(ResolveValueResult::ValueNs(ValueNs::StaticId(id), _)) = value_or_partial {
433 if let Some(ResolveValueResult::ValueNs(ValueNs::StaticId(id))) = value_or_partial {
434434 let static_data = self.db.static_signature(id);
435435 if static_data.flags.contains(StaticFlags::MUTABLE) {
436436 self.on_unsafe_op(node, UnsafetyReason::MutableStatic);
src/tools/rust-analyzer/crates/hir-ty/src/infer.rs+2-2
......@@ -1584,7 +1584,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
15841584 return (self.err_ty(), None);
15851585 };
15861586 match res {
1587 ResolveValueResult::ValueNs(value, _) => match value {
1587 ResolveValueResult::ValueNs(value) => match value {
15881588 ValueNs::EnumVariantId(var) => {
15891589 let args = path_ctx.substs_from_path(var.into(), true, false);
15901590 drop(ctx);
......@@ -1608,7 +1608,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
16081608 return (self.err_ty(), None);
16091609 }
16101610 },
1611 ResolveValueResult::Partial(typens, unresolved, _) => (typens, Some(unresolved)),
1611 ResolveValueResult::Partial(typens, unresolved) => (typens, Some(unresolved)),
16121612 }
16131613 } else {
16141614 match path_ctx.resolve_path_in_type_ns() {
src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs+1-1
......@@ -751,7 +751,7 @@ impl<'db> InferenceContext<'_, 'db> {
751751
752752 if let Some(lhs_ty) = lhs_ty {
753753 self.write_pat_ty(target, lhs_ty);
754 self.infer_expr_coerce(value, &Expectation::has_type(lhs_ty), ExprIsRead::No);
754 self.infer_expr_coerce(value, &Expectation::has_type(lhs_ty), ExprIsRead::Yes);
755755 } else {
756756 let rhs_ty = self.infer_expr(value, &Expectation::none(), ExprIsRead::Yes);
757757 let resolver_guard =
src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs+1-1
......@@ -673,7 +673,7 @@ impl<'db> InferenceContext<'_, 'db> {
673673pub(super) fn contains_explicit_ref_binding(body: &Body, pat_id: PatId) -> bool {
674674 let mut res = false;
675675 body.walk_pats(pat_id, &mut |pat| {
676 res |= matches!(body[pat], Pat::Bind { id, .. } if body[id].mode == BindingAnnotation::Ref);
676 res |= matches!(body[pat], Pat::Bind { id, .. } if matches!(body[id].mode, BindingAnnotation::Ref | BindingAnnotation::RefMut));
677677 });
678678 res
679679}
src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs+2-2
......@@ -164,11 +164,11 @@ impl<'db> InferenceContext<'_, 'db> {
164164 let value_or_partial = path_ctx.resolve_path_in_value_ns(hygiene)?;
165165
166166 match value_or_partial {
167 ResolveValueResult::ValueNs(it, _) => {
167 ResolveValueResult::ValueNs(it) => {
168168 drop_ctx(ctx, no_diagnostics);
169169 (it, None)
170170 }
171 ResolveValueResult::Partial(def, remaining_index, _) => {
171 ResolveValueResult::Partial(def, remaining_index) => {
172172 // there may be more intermediate segments between the resolved one and
173173 // the end. Only the last segment needs to be resolved to a value; from
174174 // the segments before that, we need to get either a type or a trait ref.
src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs+4-6
......@@ -396,12 +396,10 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> {
396396 }
397397
398398 let (mod_segments, enum_segment, resolved_segment_idx) = match res {
399 ResolveValueResult::Partial(_, unresolved_segment, _) => {
399 ResolveValueResult::Partial(_, unresolved_segment) => {
400400 (segments.take(unresolved_segment - 1), None, unresolved_segment - 1)
401401 }
402 ResolveValueResult::ValueNs(ValueNs::EnumVariantId(_), _)
403 if prefix_info.enum_variant =>
404 {
402 ResolveValueResult::ValueNs(ValueNs::EnumVariantId(_)) if prefix_info.enum_variant => {
405403 (segments.strip_last_two(), segments.len().checked_sub(2), segments.len() - 1)
406404 }
407405 ResolveValueResult::ValueNs(..) => (segments.strip_last(), None, segments.len() - 1),
......@@ -431,7 +429,7 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> {
431429 }
432430
433431 match &res {
434 ResolveValueResult::ValueNs(resolution, _) => {
432 ResolveValueResult::ValueNs(resolution) => {
435433 let resolved_segment_idx = self.current_segment_u32();
436434 let resolved_segment = self.current_or_prev_segment;
437435
......@@ -469,7 +467,7 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> {
469467 | ValueNs::ConstId(_) => {}
470468 }
471469 }
472 ResolveValueResult::Partial(resolution, _, _) => {
470 ResolveValueResult::Partial(resolution, _) => {
473471 if !self.handle_type_ns_resolution(resolution) {
474472 return None;
475473 }
src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs+1-1
......@@ -1625,7 +1625,7 @@ impl<'db> Evaluator<'db> {
16251625 };
16261626 match target_ty {
16271627 rustc_type_ir::FloatTy::F32 => Owned((value as f32).to_le_bytes().to_vec()),
1628 rustc_type_ir::FloatTy::F64 => Owned((value as f64).to_le_bytes().to_vec()),
1628 rustc_type_ir::FloatTy::F64 => Owned(value.to_le_bytes().to_vec()),
16291629 rustc_type_ir::FloatTy::F16 | rustc_type_ir::FloatTy::F128 => {
16301630 not_supported!("unstable floating point type f16 and f128");
16311631 }
src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs+2-2
......@@ -1429,7 +1429,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> {
14291429 .resolve_path_in_value_ns(self.db, c, HygieneId::ROOT)
14301430 .ok_or_else(unresolved_name)?;
14311431 match pr {
1432 ResolveValueResult::ValueNs(v, _) => {
1432 ResolveValueResult::ValueNs(v) => {
14331433 if let ValueNs::ConstId(c) = v {
14341434 self.lower_const_to_operand(
14351435 GenericArgs::empty(self.interner()),
......@@ -1439,7 +1439,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> {
14391439 not_supported!("bad path in range pattern");
14401440 }
14411441 }
1442 ResolveValueResult::Partial(_, _, _) => {
1442 ResolveValueResult::Partial(_, _) => {
14431443 not_supported!("associated constants in range pattern")
14441444 }
14451445 }
src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs+2-2
......@@ -373,7 +373,7 @@ impl<'db> MirLowerCtx<'_, 'db> {
373373
374374 if let (
375375 MatchingMode::Assign,
376 ResolveValueResult::ValueNs(ValueNs::LocalBinding(binding), _),
376 ResolveValueResult::ValueNs(ValueNs::LocalBinding(binding)),
377377 ) = (mode, &pr)
378378 {
379379 let local = self.binding_local(*binding)?;
......@@ -398,7 +398,7 @@ impl<'db> MirLowerCtx<'_, 'db> {
398398 {
399399 break 'b (c, x.1);
400400 }
401 if let ResolveValueResult::ValueNs(ValueNs::ConstId(c), _) = pr {
401 if let ResolveValueResult::ValueNs(ValueNs::ConstId(c)) = pr {
402402 break 'b (c, GenericArgs::empty(self.interner()));
403403 }
404404 not_supported!("path in pattern position that is not const or variant")
src/tools/rust-analyzer/crates/hir-ty/src/next_solver/predicate.rs+4-3
......@@ -714,9 +714,9 @@ impl<'db> rustc_type_ir::inherent::Predicate<DbInterner<'db>> for Predicate<'db>
714714 fn allow_normalization(self) -> bool {
715715 // TODO: this should probably live in rustc_type_ir
716716 match self.inner().as_ref().skip_binder() {
717 PredicateKind::Clause(ClauseKind::WellFormed(_))
718 | PredicateKind::AliasRelate(..)
719 | PredicateKind::NormalizesTo(..) => false,
717 PredicateKind::Clause(ClauseKind::WellFormed(_)) | PredicateKind::AliasRelate(..) => {
718 false
719 }
720720 PredicateKind::Clause(ClauseKind::Trait(_))
721721 | PredicateKind::Clause(ClauseKind::RegionOutlives(_))
722722 | PredicateKind::Clause(ClauseKind::TypeOutlives(_))
......@@ -729,6 +729,7 @@ impl<'db> rustc_type_ir::inherent::Predicate<DbInterner<'db>> for Predicate<'db>
729729 | PredicateKind::Coerce(_)
730730 | PredicateKind::Clause(ClauseKind::ConstEvaluatable(_))
731731 | PredicateKind::ConstEquate(_, _)
732 | PredicateKind::NormalizesTo(..)
732733 | PredicateKind::Ambiguous => true,
733734 }
734735 }
src/tools/rust-analyzer/crates/hir-ty/src/tests/never_type.rs+42
......@@ -760,6 +760,48 @@ fn coerce_ref_binding() -> ! {
760760 )
761761}
762762
763#[test]
764fn diverging_place_match_ref_mut() {
765 check_infer_with_mismatches(
766 r#"
767//- minicore: sized
768fn coerce_ref_mut_binding() -> ! {
769 unsafe {
770 let x: *mut ! = 0 as _;
771 let ref mut _x: () = *x;
772 }
773}
774"#,
775 expect![[r#"
776 33..120 '{ ... } }': !
777 39..118 'unsafe... }': !
778 60..61 'x': *mut !
779 72..73 '0': i32
780 72..78 '0 as _': *mut !
781 92..102 'ref mut _x': &'? mut ()
782 109..111 '*x': !
783 110..111 'x': *mut !
784 109..111: expected (), got !
785 "#]],
786 )
787}
788
789#[test]
790fn assign_never_place_no_mismatch() {
791 check_no_mismatches(
792 r#"
793//- minicore: sized
794fn foo() {
795 unsafe {
796 let p: *mut ! = 0 as _;
797 let mut x: () = ();
798 x = *p;
799 }
800}
801"#,
802 );
803}
804
763805#[test]
764806fn never_place_isnt_diverging() {
765807 check_infer_with_mismatches(
src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs+83-1
......@@ -2363,7 +2363,6 @@ fn test() {
23632363}
23642364"#,
23652365 expect![[r#"
2366 46..49 'Foo': Foo<N>
23672366 93..97 'self': Foo<N>
23682367 108..125 '{ ... }': usize
23692368 118..119 'N': usize
......@@ -2688,3 +2687,86 @@ pub trait FilterT<F: FilterT<F, V = Self::V> = Self> {
26882687 "#,
26892688 );
26902689}
2690
2691#[test]
2692fn regression_21605() {
2693 check_infer(
2694 r#"
2695//- minicore: fn, coerce_unsized, dispatch_from_dyn, iterator, iterators
2696pub struct Filter<'a, 'b, T>
2697where
2698 T: 'b,
2699 'a: 'b,
2700{
2701 filter_fn: dyn Fn(&'a T) -> bool,
2702 t: Option<T>,
2703 b: &'b (),
2704}
2705
2706impl<'a, 'b, T> Filter<'a, 'b, T>
2707where
2708 T: 'b,
2709 'a: 'b,
2710{
2711 pub fn new(filter_fn: dyn Fn(&T) -> bool) -> Self {
2712 Self {
2713 filter_fn: filter_fn,
2714 t: None,
2715 b: &(),
2716 }
2717 }
2718}
2719
2720pub trait FilterExt<T> {
2721 type Output;
2722 fn filter(&self, filter: &Filter<T>) -> Self::Output;
2723}
2724
2725impl<const N: usize, T> FilterExt<T> for [T; N]
2726where
2727 T: IntoIterator,
2728{
2729 type Output = T;
2730 fn filter(&self, filter: &Filter<T>) -> Self::Output {
2731 let _ = self.into_iter().filter(filter.filter_fn);
2732 loop {}
2733 }
2734}
2735"#,
2736 expect![[r#"
2737 214..223 'filter_fn': dyn Fn(&'? T) -> bool + 'static
2738 253..360 '{ ... }': Filter<'a, 'b, T>
2739 263..354 'Self {... }': Filter<'a, 'b, T>
2740 293..302 'filter_fn': dyn Fn(&'? T) -> bool + 'static
2741 319..323 'None': Option<T>
2742 340..343 '&()': &'? ()
2743 341..343 '()': ()
2744 421..425 'self': &'? Self
2745 427..433 'filter': &'? Filter<'?, '?, T>
2746 580..584 'self': &'? [T; N]
2747 586..592 'filter': &'? Filter<'?, '?, T>
2748 622..704 '{ ... }': T
2749 636..637 '_': Filter<Iter<'?, T>, dyn Fn(&'? T) -> bool + '?>
2750 640..644 'self': &'? [T; N]
2751 640..656 'self.i...iter()': Iter<'?, T>
2752 640..681 'self.i...er_fn)': Filter<Iter<'?, T>, dyn Fn(&'? T) -> bool + '?>
2753 664..670 'filter': &'? Filter<'?, '?, T>
2754 664..680 'filter...ter_fn': dyn Fn(&'? T) -> bool + 'static
2755 691..698 'loop {}': !
2756 696..698 '{}': ()
2757 "#]],
2758 );
2759}
2760
2761#[test]
2762fn extern_fns_cannot_have_param_patterns() {
2763 check_no_mismatches(
2764 r#"
2765pub(crate) struct Builder<'a>(&'a ());
2766
2767unsafe extern "C" {
2768 pub(crate) fn foo<'a>(Builder: &Builder<'a>);
2769}
2770 "#,
2771 );
2772}
src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs+35
......@@ -4074,3 +4074,38 @@ static S: &[u8; 158] = include_bytes!("/foo/bar/baz.txt");
40744074 "#,
40754075 );
40764076}
4077
4078#[test]
4079fn proc_macros_are_functions_inside_defining_crate_and_macros_outside() {
4080 check_types(
4081 r#"
4082//- /pm.rs crate:pm
4083#![crate_type = "proc-macro"]
4084
4085#[proc_macro_attribute]
4086pub fn proc_macro() {}
4087
4088fn foo() {
4089 proc_macro;
4090 // ^^^^^^^^^^ fn proc_macro()
4091}
4092
4093mod bar {
4094 use super::proc_macro;
4095
4096 fn baz() {
4097 super::proc_macro;
4098 // ^^^^^^^^^^^^^^^^^ fn proc_macro()
4099 proc_macro;
4100 // ^^^^^^^^^^ fn proc_macro()
4101 }
4102}
4103
4104//- /lib.rs crate:lib deps:pm
4105fn foo() {
4106 pm::proc_macro;
4107 // ^^^^^^^^^^^^^^ {unknown}
4108}
4109 "#,
4110 );
4111}
src/tools/rust-analyzer/crates/hir/src/display.rs+11-2
......@@ -172,8 +172,13 @@ fn write_function<'db>(f: &mut HirFormatter<'_, 'db>, func_id: FunctionId) -> Re
172172
173173 write_generic_params(GenericDefId::FunctionId(func_id), f)?;
174174
175 let too_long_param = data.params.len() > 4;
175176 f.write_char('(')?;
176177
178 if too_long_param {
179 f.write_str("\n ")?;
180 }
181
177182 let mut first = true;
178183 let mut skip_self = 0;
179184 if let Some(self_param) = func.self_param(db) {
......@@ -182,11 +187,12 @@ fn write_function<'db>(f: &mut HirFormatter<'_, 'db>, func_id: FunctionId) -> Re
182187 skip_self = 1;
183188 }
184189
190 let comma = if too_long_param { ",\n " } else { ", " };
185191 // FIXME: Use resolved `param.ty` once we no longer discard lifetimes
186192 let body = db.body(func_id.into());
187193 for (type_ref, param) in data.params.iter().zip(func.assoc_fn_params(db)).skip(skip_self) {
188194 if !first {
189 f.write_str(", ")?;
195 f.write_str(comma)?;
190196 } else {
191197 first = false;
192198 }
......@@ -201,11 +207,14 @@ fn write_function<'db>(f: &mut HirFormatter<'_, 'db>, func_id: FunctionId) -> Re
201207
202208 if data.is_varargs() {
203209 if !first {
204 f.write_str(", ")?;
210 f.write_str(comma)?;
205211 }
206212 f.write_str("...")?;
207213 }
208214
215 if too_long_param {
216 f.write_char('\n')?;
217 }
209218 f.write_char(')')?;
210219
211220 // `FunctionData::ret_type` will be `::core::future::Future<Output = ...>` for async fns.
src/tools/rust-analyzer/crates/hir/src/lib.rs+34-5
......@@ -2244,6 +2244,39 @@ impl DefWithBody {
22442244 acc.push(diag.into())
22452245 }
22462246 }
2247
2248 /// Returns an iterator over the inferred types of all expressions in this body.
2249 pub fn expression_types<'db>(
2250 self,
2251 db: &'db dyn HirDatabase,
2252 ) -> impl Iterator<Item = Type<'db>> {
2253 self.id().into_iter().flat_map(move |def_id| {
2254 let infer = InferenceResult::for_body(db, def_id);
2255 let resolver = def_id.resolver(db);
2256
2257 infer.expression_types().map(move |(_, ty)| Type::new_with_resolver(db, &resolver, ty))
2258 })
2259 }
2260
2261 /// Returns an iterator over the inferred types of all patterns in this body.
2262 pub fn pattern_types<'db>(self, db: &'db dyn HirDatabase) -> impl Iterator<Item = Type<'db>> {
2263 self.id().into_iter().flat_map(move |def_id| {
2264 let infer = InferenceResult::for_body(db, def_id);
2265 let resolver = def_id.resolver(db);
2266
2267 infer.pattern_types().map(move |(_, ty)| Type::new_with_resolver(db, &resolver, ty))
2268 })
2269 }
2270
2271 /// Returns an iterator over the inferred types of all bindings in this body.
2272 pub fn binding_types<'db>(self, db: &'db dyn HirDatabase) -> impl Iterator<Item = Type<'db>> {
2273 self.id().into_iter().flat_map(move |def_id| {
2274 let infer = InferenceResult::for_body(db, def_id);
2275 let resolver = def_id.resolver(db);
2276
2277 infer.binding_types().map(move |(_, ty)| Type::new_with_resolver(db, &resolver, ty))
2278 })
2279 }
22472280}
22482281
22492282fn expr_store_diagnostics<'db>(
......@@ -6068,11 +6101,7 @@ impl<'db> Type<'db> {
60686101
60696102 match name {
60706103 Some(name) => {
6071 match ctx.probe_for_name(
6072 method_resolution::Mode::MethodCall,
6073 name.clone(),
6074 self_ty,
6075 ) {
6104 match ctx.probe_for_name(method_resolution::Mode::Path, name.clone(), self_ty) {
60766105 Ok(candidate)
60776106 | Err(method_resolution::MethodError::PrivateMatch(candidate)) => {
60786107 let id = candidate.item.into();
src/tools/rust-analyzer/crates/ide-assists/src/handlers/auto_import.rs+32-1
......@@ -352,7 +352,7 @@ mod tests {
352352 let config = TEST_CONFIG;
353353 let ctx = AssistContext::new(sema, &config, frange);
354354 let mut acc = Assists::new(&ctx, AssistResolveStrategy::All);
355 auto_import(&mut acc, &ctx);
355 hir::attach_db(&db, || auto_import(&mut acc, &ctx));
356356 let assists = acc.finish();
357357
358358 let labels = assists.iter().map(|assist| assist.label.to_string()).collect::<Vec<_>>();
......@@ -1897,4 +1897,35 @@ fn foo(_: S) {}
18971897"#,
18981898 );
18991899 }
1900
1901 #[test]
1902 fn with_after_segments() {
1903 let before = r#"
1904mod foo {
1905 pub mod wanted {
1906 pub fn abc() {}
1907 }
1908}
1909
1910mod bar {
1911 pub mod wanted {}
1912}
1913
1914mod baz {
1915 pub fn wanted() {}
1916}
1917
1918mod quux {
1919 pub struct wanted;
1920}
1921impl quux::wanted {
1922 fn abc() {}
1923}
1924
1925fn f() {
1926 wanted$0::abc;
1927}
1928 "#;
1929 check_auto_import_order(before, &["Import `foo::wanted`", "Import `quux::wanted`"]);
1930 }
19001931}
src/tools/rust-analyzer/crates/ide-assists/src/handlers/bind_unused_param.rs+1-1
......@@ -2,7 +2,7 @@ use crate::assist_context::{AssistContext, Assists};
22use ide_db::{LineIndexDatabase, assists::AssistId, defs::Definition};
33use syntax::{
44 AstNode,
5 ast::{self, HasName, edit_in_place::Indent},
5 ast::{self, HasName, edit::AstNodeEdit},
66};
77
88// Assist: bind_unused_param
src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_to_enum.rs+3-3
......@@ -11,9 +11,10 @@ use ide_db::{
1111 source_change::SourceChangeBuilder,
1212};
1313use itertools::Itertools;
14use syntax::ast::edit::AstNodeEdit;
1415use syntax::{
1516 AstNode, NodeOrToken, SyntaxKind, SyntaxNode, T,
16 ast::{self, HasName, edit::IndentLevel, edit_in_place::Indent, make},
17 ast::{self, HasName, edit::IndentLevel, make},
1718};
1819
1920use crate::{
......@@ -479,10 +480,9 @@ fn add_enum_def(
479480 ctx.sema.scope(name.syntax()).map(|scope| scope.module())
480481 })
481482 .any(|module| module.nearest_non_block_module(ctx.db()) != *target_module);
482 let enum_def = make_bool_enum(make_enum_pub);
483483
484484 let indent = IndentLevel::from_node(&insert_before);
485 enum_def.reindent_to(indent);
485 let enum_def = make_bool_enum(make_enum_pub).reset_indent().indent(indent);
486486
487487 edit.insert(
488488 insert_before.text_range().start(),
src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_let_else_to_match.rs+3-3
......@@ -1,7 +1,6 @@
11use syntax::T;
22use syntax::ast::RangeItem;
3use syntax::ast::edit::IndentLevel;
4use syntax::ast::edit_in_place::Indent;
3use syntax::ast::edit::AstNodeEdit;
54use syntax::ast::syntax_factory::SyntaxFactory;
65use syntax::ast::{self, AstNode, HasName, LetStmt, Pat};
76
......@@ -93,7 +92,8 @@ pub(crate) fn convert_let_else_to_match(acc: &mut Assists, ctx: &AssistContext<'
9392 );
9493 let else_arm = make.match_arm(make.wildcard_pat().into(), None, else_expr);
9594 let match_ = make.expr_match(init, make.match_arm_list([binding_arm, else_arm]));
96 match_.reindent_to(IndentLevel::from_node(let_stmt.syntax()));
95 let match_ = match_.reset_indent();
96 let match_ = match_.indent(let_stmt.indent_level());
9797
9898 if bindings.is_empty() {
9999 editor.replace(let_stmt.syntax(), match_.syntax());
src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_return_type_to_struct.rs+82-45
......@@ -5,15 +5,20 @@ use ide_db::{
55 assists::AssistId,
66 defs::Definition,
77 helpers::mod_path_to_ast,
8 imports::insert_use::{ImportScope, insert_use},
8 imports::insert_use::{ImportScope, insert_use_with_editor},
99 search::{FileReference, UsageSearchResult},
1010 source_change::SourceChangeBuilder,
1111 syntax_helpers::node_ext::{for_each_tail_expr, walk_expr},
1212};
1313use syntax::{
1414 AstNode, SyntaxNode,
15 ast::{self, HasName, edit::IndentLevel, edit_in_place::Indent, make},
16 match_ast, ted,
15 ast::{
16 self, HasName,
17 edit::{AstNodeEdit, IndentLevel},
18 syntax_factory::SyntaxFactory,
19 },
20 match_ast,
21 syntax_editor::SyntaxEditor,
1722};
1823
1924use crate::assist_context::{AssistContext, Assists};
......@@ -67,14 +72,15 @@ pub(crate) fn convert_tuple_return_type_to_struct(
6772 "Convert tuple return type to tuple struct",
6873 target,
6974 move |edit| {
70 let ret_type = edit.make_mut(ret_type);
71 let fn_ = edit.make_mut(fn_);
75 let mut syntax_editor = edit.make_editor(ret_type.syntax());
76 let syntax_factory = SyntaxFactory::with_mappings();
7277
7378 let usages = Definition::Function(fn_def).usages(&ctx.sema).all();
7479 let struct_name = format!("{}Result", stdx::to_camel_case(&fn_name.to_string()));
7580 let parent = fn_.syntax().ancestors().find_map(<Either<ast::Impl, ast::Trait>>::cast);
7681 add_tuple_struct_def(
7782 edit,
83 &syntax_factory,
7884 ctx,
7985 &usages,
8086 parent.as_ref().map(|it| it.syntax()).unwrap_or(fn_.syntax()),
......@@ -83,15 +89,23 @@ pub(crate) fn convert_tuple_return_type_to_struct(
8389 &target_module,
8490 );
8591
86 ted::replace(
92 syntax_editor.replace(
8793 ret_type.syntax(),
88 make::ret_type(make::ty(&struct_name)).syntax().clone_for_update(),
94 syntax_factory.ret_type(syntax_factory.ty(&struct_name)).syntax(),
8995 );
9096
9197 if let Some(fn_body) = fn_.body() {
92 replace_body_return_values(ast::Expr::BlockExpr(fn_body), &struct_name);
98 replace_body_return_values(
99 &mut syntax_editor,
100 &syntax_factory,
101 ast::Expr::BlockExpr(fn_body),
102 &struct_name,
103 );
93104 }
94105
106 syntax_editor.add_mappings(syntax_factory.finish_with_mappings());
107 edit.add_file_edits(ctx.vfs_file_id(), syntax_editor);
108
95109 replace_usages(edit, ctx, &usages, &struct_name, &target_module);
96110 },
97111 )
......@@ -106,24 +120,37 @@ fn replace_usages(
106120 target_module: &hir::Module,
107121) {
108122 for (file_id, references) in usages.iter() {
109 edit.edit_file(file_id.file_id(ctx.db()));
123 let Some(first_ref) = references.first() else { continue };
124
125 let mut editor = edit.make_editor(first_ref.name.syntax().as_node().unwrap());
126 let syntax_factory = SyntaxFactory::with_mappings();
110127
111 let refs_with_imports =
112 augment_references_with_imports(edit, ctx, references, struct_name, target_module);
128 let refs_with_imports = augment_references_with_imports(
129 &syntax_factory,
130 ctx,
131 references,
132 struct_name,
133 target_module,
134 );
113135
114136 refs_with_imports.into_iter().rev().for_each(|(name, import_data)| {
115137 if let Some(fn_) = name.syntax().parent().and_then(ast::Fn::cast) {
116138 cov_mark::hit!(replace_trait_impl_fns);
117139
118140 if let Some(ret_type) = fn_.ret_type() {
119 ted::replace(
141 editor.replace(
120142 ret_type.syntax(),
121 make::ret_type(make::ty(struct_name)).syntax().clone_for_update(),
143 syntax_factory.ret_type(syntax_factory.ty(struct_name)).syntax(),
122144 );
123145 }
124146
125147 if let Some(fn_body) = fn_.body() {
126 replace_body_return_values(ast::Expr::BlockExpr(fn_body), struct_name);
148 replace_body_return_values(
149 &mut editor,
150 &syntax_factory,
151 ast::Expr::BlockExpr(fn_body),
152 struct_name,
153 );
127154 }
128155 } else {
129156 // replace tuple patterns
......@@ -143,22 +170,30 @@ fn replace_usages(
143170 _ => None,
144171 });
145172 for tuple_pat in tuple_pats {
146 ted::replace(
173 editor.replace(
147174 tuple_pat.syntax(),
148 make::tuple_struct_pat(
149 make::path_from_text(struct_name),
150 tuple_pat.fields(),
151 )
152 .clone_for_update()
153 .syntax(),
175 syntax_factory
176 .tuple_struct_pat(
177 syntax_factory.path_from_text(struct_name),
178 tuple_pat.fields(),
179 )
180 .syntax(),
154181 );
155182 }
156183 }
157 // add imports across modules where needed
158184 if let Some((import_scope, path)) = import_data {
159 insert_use(&import_scope, path, &ctx.config.insert_use);
185 insert_use_with_editor(
186 &import_scope,
187 path,
188 &ctx.config.insert_use,
189 &mut editor,
190 &syntax_factory,
191 );
160192 }
161 })
193 });
194
195 editor.add_mappings(syntax_factory.finish_with_mappings());
196 edit.add_file_edits(file_id.file_id(ctx.db()), editor);
162197 }
163198}
164199
......@@ -176,7 +211,7 @@ fn node_to_pats(node: SyntaxNode) -> Option<Vec<ast::Pat>> {
176211}
177212
178213fn augment_references_with_imports(
179 edit: &mut SourceChangeBuilder,
214 syntax_factory: &SyntaxFactory,
180215 ctx: &AssistContext<'_>,
181216 references: &[FileReference],
182217 struct_name: &str,
......@@ -191,8 +226,6 @@ fn augment_references_with_imports(
191226 ctx.sema.scope(name.syntax()).map(|scope| (name, scope.module()))
192227 })
193228 .map(|(name, ref_module)| {
194 let new_name = edit.make_mut(name);
195
196229 // if the referenced module is not the same as the target one and has not been seen before, add an import
197230 let import_data = if ref_module.nearest_non_block_module(ctx.db()) != *target_module
198231 && !visited_modules.contains(&ref_module)
......@@ -201,8 +234,7 @@ fn augment_references_with_imports(
201234
202235 let cfg =
203236 ctx.config.find_path_config(ctx.sema.is_nightly(ref_module.krate(ctx.sema.db)));
204 let import_scope =
205 ImportScope::find_insert_use_container(new_name.syntax(), &ctx.sema);
237 let import_scope = ImportScope::find_insert_use_container(name.syntax(), &ctx.sema);
206238 let path = ref_module
207239 .find_use_path(
208240 ctx.sema.db,
......@@ -211,12 +243,12 @@ fn augment_references_with_imports(
211243 cfg,
212244 )
213245 .map(|mod_path| {
214 make::path_concat(
246 syntax_factory.path_concat(
215247 mod_path_to_ast(
216248 &mod_path,
217249 target_module.krate(ctx.db()).edition(ctx.db()),
218250 ),
219 make::path_from_text(struct_name),
251 syntax_factory.path_from_text(struct_name),
220252 )
221253 });
222254
......@@ -225,7 +257,7 @@ fn augment_references_with_imports(
225257 None
226258 };
227259
228 (new_name, import_data)
260 (name, import_data)
229261 })
230262 .collect()
231263}
......@@ -233,6 +265,7 @@ fn augment_references_with_imports(
233265// Adds the definition of the tuple struct before the parent function.
234266fn add_tuple_struct_def(
235267 edit: &mut SourceChangeBuilder,
268 syntax_factory: &SyntaxFactory,
236269 ctx: &AssistContext<'_>,
237270 usages: &UsageSearchResult,
238271 parent: &SyntaxNode,
......@@ -248,22 +281,27 @@ fn add_tuple_struct_def(
248281 ctx.sema.scope(name.syntax()).map(|scope| scope.module())
249282 })
250283 .any(|module| module.nearest_non_block_module(ctx.db()) != *target_module);
251 let visibility = if make_struct_pub { Some(make::visibility_pub()) } else { None };
284 let visibility = if make_struct_pub { Some(syntax_factory.visibility_pub()) } else { None };
252285
253 let field_list = ast::FieldList::TupleFieldList(make::tuple_field_list(
254 tuple_ty.fields().map(|ty| make::tuple_field(visibility.clone(), ty)),
286 let field_list = ast::FieldList::TupleFieldList(syntax_factory.tuple_field_list(
287 tuple_ty.fields().map(|ty| syntax_factory.tuple_field(visibility.clone(), ty)),
255288 ));
256 let struct_name = make::name(struct_name);
257 let struct_def = make::struct_(visibility, struct_name, None, field_list).clone_for_update();
289 let struct_name = syntax_factory.name(struct_name);
290 let struct_def = syntax_factory.struct_(visibility, struct_name, None, field_list);
258291
259292 let indent = IndentLevel::from_node(parent);
260 struct_def.reindent_to(indent);
293 let struct_def = struct_def.indent(indent);
261294
262295 edit.insert(parent.text_range().start(), format!("{struct_def}\n\n{indent}"));
263296}
264297
265298/// Replaces each returned tuple in `body` with the constructor of the tuple struct named `struct_name`.
266fn replace_body_return_values(body: ast::Expr, struct_name: &str) {
299fn replace_body_return_values(
300 syntax_editor: &mut SyntaxEditor,
301 syntax_factory: &SyntaxFactory,
302 body: ast::Expr,
303 struct_name: &str,
304) {
267305 let mut exprs_to_wrap = Vec::new();
268306
269307 let tail_cb = &mut |e: &_| tail_cb_impl(&mut exprs_to_wrap, e);
......@@ -278,12 +316,11 @@ fn replace_body_return_values(body: ast::Expr, struct_name: &str) {
278316
279317 for ret_expr in exprs_to_wrap {
280318 if let ast::Expr::TupleExpr(tuple_expr) = &ret_expr {
281 let struct_constructor = make::expr_call(
282 make::expr_path(make::ext::ident_path(struct_name)),
283 make::arg_list(tuple_expr.fields()),
284 )
285 .clone_for_update();
286 ted::replace(ret_expr.syntax(), struct_constructor.syntax());
319 let struct_constructor = syntax_factory.expr_call(
320 syntax_factory.expr_path(syntax_factory.ident_path(struct_name)),
321 syntax_factory.arg_list(tuple_expr.fields()),
322 );
323 syntax_editor.replace(ret_expr.syntax(), struct_constructor.syntax());
287324 }
288325 }
289326}
src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_tuple_binding.rs+52-33
......@@ -8,8 +8,8 @@ use ide_db::{
88use itertools::Itertools;
99use syntax::{
1010 T,
11 ast::{self, AstNode, FieldExpr, HasName, IdentPat, make},
12 ted,
11 ast::{self, AstNode, FieldExpr, HasName, IdentPat, syntax_factory::SyntaxFactory},
12 syntax_editor::{Position, SyntaxEditor},
1313};
1414
1515use crate::{
......@@ -89,13 +89,20 @@ fn destructure_tuple_edit_impl(
8989 data: &TupleData,
9090 in_sub_pattern: bool,
9191) {
92 let assignment_edit = edit_tuple_assignment(ctx, edit, data, in_sub_pattern);
93 let current_file_usages_edit = edit_tuple_usages(data, edit, ctx, in_sub_pattern);
92 let mut syntax_editor = edit.make_editor(data.ident_pat.syntax());
93 let syntax_factory = SyntaxFactory::with_mappings();
9494
95 assignment_edit.apply();
95 let assignment_edit =
96 edit_tuple_assignment(ctx, edit, &mut syntax_editor, &syntax_factory, data, in_sub_pattern);
97 let current_file_usages_edit = edit_tuple_usages(data, ctx, &syntax_factory, in_sub_pattern);
98
99 assignment_edit.apply(&mut syntax_editor, &syntax_factory);
96100 if let Some(usages_edit) = current_file_usages_edit {
97 usages_edit.into_iter().for_each(|usage_edit| usage_edit.apply(edit))
101 usages_edit.into_iter().for_each(|usage_edit| usage_edit.apply(edit, &mut syntax_editor))
98102 }
103
104 syntax_editor.add_mappings(syntax_factory.finish_with_mappings());
105 edit.add_file_edits(ctx.vfs_file_id(), syntax_editor);
99106}
100107
101108fn collect_data(ident_pat: IdentPat, ctx: &AssistContext<'_>) -> Option<TupleData> {
......@@ -165,11 +172,11 @@ struct TupleData {
165172fn edit_tuple_assignment(
166173 ctx: &AssistContext<'_>,
167174 edit: &mut SourceChangeBuilder,
175 editor: &mut SyntaxEditor,
176 make: &SyntaxFactory,
168177 data: &TupleData,
169178 in_sub_pattern: bool,
170179) -> AssignmentEdit {
171 let ident_pat = edit.make_mut(data.ident_pat.clone());
172
173180 let tuple_pat = {
174181 let original = &data.ident_pat;
175182 let is_ref = original.ref_token().is_some();
......@@ -177,10 +184,11 @@ fn edit_tuple_assignment(
177184 let fields = data
178185 .field_names
179186 .iter()
180 .map(|name| ast::Pat::from(make::ident_pat(is_ref, is_mut, make::name(name))));
181 make::tuple_pat(fields).clone_for_update()
187 .map(|name| ast::Pat::from(make.ident_pat(is_ref, is_mut, make.name(name))));
188 make.tuple_pat(fields)
182189 };
183 let is_shorthand_field = ident_pat
190 let is_shorthand_field = data
191 .ident_pat
184192 .name()
185193 .as_ref()
186194 .and_then(ast::RecordPatField::for_field_name)
......@@ -189,14 +197,20 @@ fn edit_tuple_assignment(
189197 if let Some(cap) = ctx.config.snippet_cap {
190198 // place cursor on first tuple name
191199 if let Some(ast::Pat::IdentPat(first_pat)) = tuple_pat.fields().next() {
192 edit.add_tabstop_before(
193 cap,
194 first_pat.name().expect("first ident pattern should have a name"),
195 )
200 let annotation = edit.make_tabstop_before(cap);
201 editor.add_annotation(
202 first_pat.name().expect("first ident pattern should have a name").syntax(),
203 annotation,
204 );
196205 }
197206 }
198207
199 AssignmentEdit { ident_pat, tuple_pat, in_sub_pattern, is_shorthand_field }
208 AssignmentEdit {
209 ident_pat: data.ident_pat.clone(),
210 tuple_pat,
211 in_sub_pattern,
212 is_shorthand_field,
213 }
200214}
201215struct AssignmentEdit {
202216 ident_pat: ast::IdentPat,
......@@ -206,23 +220,30 @@ struct AssignmentEdit {
206220}
207221
208222impl AssignmentEdit {
209 fn apply(self) {
223 fn apply(self, syntax_editor: &mut SyntaxEditor, syntax_mapping: &SyntaxFactory) {
210224 // with sub_pattern: keep original tuple and add subpattern: `tup @ (_0, _1)`
211225 if self.in_sub_pattern {
212 self.ident_pat.set_pat(Some(self.tuple_pat.into()))
226 self.ident_pat.set_pat_with_editor(
227 Some(self.tuple_pat.into()),
228 syntax_editor,
229 syntax_mapping,
230 )
213231 } else if self.is_shorthand_field {
214 ted::insert(ted::Position::after(self.ident_pat.syntax()), self.tuple_pat.syntax());
215 ted::insert_raw(ted::Position::after(self.ident_pat.syntax()), make::token(T![:]));
232 syntax_editor.insert(Position::after(self.ident_pat.syntax()), self.tuple_pat.syntax());
233 syntax_editor
234 .insert(Position::after(self.ident_pat.syntax()), syntax_mapping.whitespace(" "));
235 syntax_editor
236 .insert(Position::after(self.ident_pat.syntax()), syntax_mapping.token(T![:]));
216237 } else {
217 ted::replace(self.ident_pat.syntax(), self.tuple_pat.syntax())
238 syntax_editor.replace(self.ident_pat.syntax(), self.tuple_pat.syntax())
218239 }
219240 }
220241}
221242
222243fn edit_tuple_usages(
223244 data: &TupleData,
224 edit: &mut SourceChangeBuilder,
225245 ctx: &AssistContext<'_>,
246 make: &SyntaxFactory,
226247 in_sub_pattern: bool,
227248) -> Option<Vec<EditTupleUsage>> {
228249 // We need to collect edits first before actually applying them
......@@ -238,20 +259,20 @@ fn edit_tuple_usages(
238259 .as_ref()?
239260 .as_slice()
240261 .iter()
241 .filter_map(|r| edit_tuple_usage(ctx, edit, r, data, in_sub_pattern))
262 .filter_map(|r| edit_tuple_usage(ctx, make, r, data, in_sub_pattern))
242263 .collect_vec();
243264
244265 Some(edits)
245266}
246267fn edit_tuple_usage(
247268 ctx: &AssistContext<'_>,
248 builder: &mut SourceChangeBuilder,
269 make: &SyntaxFactory,
249270 usage: &FileReference,
250271 data: &TupleData,
251272 in_sub_pattern: bool,
252273) -> Option<EditTupleUsage> {
253274 match detect_tuple_index(usage, data) {
254 Some(index) => Some(edit_tuple_field_usage(ctx, builder, data, index)),
275 Some(index) => Some(edit_tuple_field_usage(ctx, make, data, index)),
255276 None if in_sub_pattern => {
256277 cov_mark::hit!(destructure_tuple_call_with_subpattern);
257278 None
......@@ -262,20 +283,18 @@ fn edit_tuple_usage(
262283
263284fn edit_tuple_field_usage(
264285 ctx: &AssistContext<'_>,
265 builder: &mut SourceChangeBuilder,
286 make: &SyntaxFactory,
266287 data: &TupleData,
267288 index: TupleIndex,
268289) -> EditTupleUsage {
269290 let field_name = &data.field_names[index.index];
270 let field_name = make::expr_path(make::ext::ident_path(field_name));
291 let field_name = make.expr_path(make.ident_path(field_name));
271292
272293 if data.ref_type.is_some() {
273294 let (replace_expr, ref_data) = determine_ref_and_parens(ctx, &index.field_expr);
274 let replace_expr = builder.make_mut(replace_expr);
275 EditTupleUsage::ReplaceExpr(replace_expr, ref_data.wrap_expr(field_name))
295 EditTupleUsage::ReplaceExpr(replace_expr, ref_data.wrap_expr_with_factory(field_name, make))
276296 } else {
277 let field_expr = builder.make_mut(index.field_expr);
278 EditTupleUsage::ReplaceExpr(field_expr.into(), field_name)
297 EditTupleUsage::ReplaceExpr(index.field_expr.into(), field_name)
279298 }
280299}
281300enum EditTupleUsage {
......@@ -291,14 +310,14 @@ enum EditTupleUsage {
291310}
292311
293312impl EditTupleUsage {
294 fn apply(self, edit: &mut SourceChangeBuilder) {
313 fn apply(self, edit: &mut SourceChangeBuilder, syntax_editor: &mut SyntaxEditor) {
295314 match self {
296315 EditTupleUsage::NoIndex(range) => {
297316 edit.insert(range.start(), "/*");
298317 edit.insert(range.end(), "*/");
299318 }
300319 EditTupleUsage::ReplaceExpr(target_expr, replace_with) => {
301 ted::replace(target_expr.syntax(), replace_with.clone_for_update().syntax())
320 syntax_editor.replace(target_expr.syntax(), replace_with.syntax())
302321 }
303322 }
304323 }
src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_getter_or_setter.rs+100-61
......@@ -2,13 +2,16 @@ use ide_db::{famous_defs::FamousDefs, source_change::SourceChangeBuilder};
22use stdx::{format_to, to_lower_snake_case};
33use syntax::{
44 TextRange,
5 ast::{self, AstNode, HasName, HasVisibility, edit_in_place::Indent, make},
6 ted,
5 ast::{
6 self, AstNode, HasGenericParams, HasName, HasVisibility, edit::AstNodeEdit,
7 syntax_factory::SyntaxFactory,
8 },
9 syntax_editor::Position,
710};
811
912use crate::{
1013 AssistContext, AssistId, Assists, GroupLabel,
11 utils::{convert_reference_type, find_struct_impl, generate_impl},
14 utils::{convert_reference_type, find_struct_impl},
1215};
1316
1417// Assist: generate_setter
......@@ -215,12 +218,14 @@ fn generate_getter_from_info(
215218 ctx: &AssistContext<'_>,
216219 info: &AssistInfo,
217220 record_field_info: &RecordFieldInfo,
221 syntax_factory: &SyntaxFactory,
218222) -> ast::Fn {
219223 let (ty, body) = if matches!(info.assist_type, AssistType::MutGet) {
224 let self_expr = syntax_factory.expr_path(syntax_factory.ident_path("self"));
220225 (
221 make::ty_ref(record_field_info.field_ty.clone(), true),
222 make::expr_ref(
223 make::expr_field(make::ext::expr_self(), &record_field_info.field_name.text()),
226 syntax_factory.ty_ref(record_field_info.field_ty.clone(), true),
227 syntax_factory.expr_ref(
228 syntax_factory.expr_field(self_expr, &record_field_info.field_name.text()).into(),
224229 true,
225230 ),
226231 )
......@@ -241,9 +246,14 @@ fn generate_getter_from_info(
241246 })()
242247 .unwrap_or_else(|| {
243248 (
244 make::ty_ref(record_field_info.field_ty.clone(), false),
245 make::expr_ref(
246 make::expr_field(make::ext::expr_self(), &record_field_info.field_name.text()),
249 syntax_factory.ty_ref(record_field_info.field_ty.clone(), false),
250 syntax_factory.expr_ref(
251 syntax_factory
252 .expr_field(
253 syntax_factory.expr_path(syntax_factory.ident_path("self")),
254 &record_field_info.field_name.text(),
255 )
256 .into(),
247257 false,
248258 ),
249259 )
......@@ -251,18 +261,18 @@ fn generate_getter_from_info(
251261 };
252262
253263 let self_param = if matches!(info.assist_type, AssistType::MutGet) {
254 make::mut_self_param()
264 syntax_factory.mut_self_param()
255265 } else {
256 make::self_param()
266 syntax_factory.self_param()
257267 };
258268
259269 let strukt = &info.strukt;
260 let fn_name = make::name(&record_field_info.fn_name);
261 let params = make::param_list(Some(self_param), []);
262 let ret_type = Some(make::ret_type(ty));
263 let body = make::block_expr([], Some(body));
270 let fn_name = syntax_factory.name(&record_field_info.fn_name);
271 let params = syntax_factory.param_list(Some(self_param), []);
272 let ret_type = Some(syntax_factory.ret_type(ty));
273 let body = syntax_factory.block_expr([], Some(body));
264274
265 make::fn_(
275 syntax_factory.fn_(
266276 None,
267277 strukt.visibility(),
268278 fn_name,
......@@ -278,28 +288,35 @@ fn generate_getter_from_info(
278288 )
279289}
280290
281fn generate_setter_from_info(info: &AssistInfo, record_field_info: &RecordFieldInfo) -> ast::Fn {
291fn generate_setter_from_info(
292 info: &AssistInfo,
293 record_field_info: &RecordFieldInfo,
294 syntax_factory: &SyntaxFactory,
295) -> ast::Fn {
282296 let strukt = &info.strukt;
283297 let field_name = &record_field_info.fn_name;
284 let fn_name = make::name(&format!("set_{field_name}"));
298 let fn_name = syntax_factory.name(&format!("set_{field_name}"));
285299 let field_ty = &record_field_info.field_ty;
286300
287301 // Make the param list
288302 // `(&mut self, $field_name: $field_ty)`
289 let field_param =
290 make::param(make::ident_pat(false, false, make::name(field_name)).into(), field_ty.clone());
291 let params = make::param_list(Some(make::mut_self_param()), [field_param]);
303 let field_param = syntax_factory.param(
304 syntax_factory.ident_pat(false, false, syntax_factory.name(field_name)).into(),
305 field_ty.clone(),
306 );
307 let params = syntax_factory.param_list(Some(syntax_factory.mut_self_param()), [field_param]);
292308
293309 // Make the assignment body
294310 // `self.$field_name = $field_name`
295 let self_expr = make::ext::expr_self();
296 let lhs = make::expr_field(self_expr, field_name);
297 let rhs = make::expr_path(make::ext::ident_path(field_name));
298 let assign_stmt = make::expr_stmt(make::expr_assignment(lhs, rhs).into());
299 let body = make::block_expr([assign_stmt.into()], None);
311 let self_expr = syntax_factory.expr_path(syntax_factory.ident_path("self"));
312 let lhs = syntax_factory.expr_field(self_expr, field_name);
313 let rhs = syntax_factory.expr_path(syntax_factory.ident_path(field_name));
314 let assign_stmt =
315 syntax_factory.expr_stmt(syntax_factory.expr_assignment(lhs.into(), rhs).into());
316 let body = syntax_factory.block_expr([assign_stmt.into()], None);
300317
301318 // Make the setter fn
302 make::fn_(
319 syntax_factory.fn_(
303320 None,
304321 strukt.visibility(),
305322 fn_name,
......@@ -403,47 +420,69 @@ fn build_source_change(
403420 info_of_record_fields: Vec<RecordFieldInfo>,
404421 assist_info: AssistInfo,
405422) {
406 let record_fields_count = info_of_record_fields.len();
407
408 let impl_def = if let Some(impl_def) = &assist_info.impl_def {
409 // We have an existing impl to add to
410 builder.make_mut(impl_def.clone())
411 } else {
412 // Generate a new impl to add the methods to
413 let impl_def = generate_impl(&ast::Adt::Struct(assist_info.strukt.clone()));
414
415 // Insert it after the adt
416 let strukt = builder.make_mut(assist_info.strukt.clone());
417
418 ted::insert_all_raw(
419 ted::Position::after(strukt.syntax()),
420 vec![make::tokens::blank_line().into(), impl_def.syntax().clone().into()],
421 );
422
423 impl_def
424 };
423 let syntax_factory = SyntaxFactory::without_mappings();
425424
426 let assoc_item_list = impl_def.get_or_create_assoc_item_list();
425 let items: Vec<ast::AssocItem> = info_of_record_fields
426 .iter()
427 .map(|record_field_info| {
428 let method = match assist_info.assist_type {
429 AssistType::Set => {
430 generate_setter_from_info(&assist_info, record_field_info, &syntax_factory)
431 }
432 _ => {
433 generate_getter_from_info(ctx, &assist_info, record_field_info, &syntax_factory)
434 }
435 };
436 let new_fn = method.clone_for_update();
437 let new_fn = new_fn.indent(1.into());
438 new_fn.into()
439 })
440 .collect();
427441
428 for (i, record_field_info) in info_of_record_fields.iter().enumerate() {
429 // Make the new getter or setter fn
430 let new_fn = match assist_info.assist_type {
431 AssistType::Set => generate_setter_from_info(&assist_info, record_field_info),
432 _ => generate_getter_from_info(ctx, &assist_info, record_field_info),
433 }
434 .clone_for_update();
435 new_fn.indent(1.into());
442 if let Some(impl_def) = &assist_info.impl_def {
443 // We have an existing impl to add to
444 let mut editor = builder.make_editor(impl_def.syntax());
445 impl_def.assoc_item_list().unwrap().add_items(&mut editor, items.clone());
436446
437 // Insert a tabstop only for last method we generate
438 if i == record_fields_count - 1
439 && let Some(cap) = ctx.config.snippet_cap
440 && let Some(name) = new_fn.name()
447 if let Some(cap) = ctx.config.snippet_cap
448 && let Some(ast::AssocItem::Fn(fn_)) = items.last()
449 && let Some(name) = fn_.name()
441450 {
442 builder.add_tabstop_before(cap, name);
451 let tabstop = builder.make_tabstop_before(cap);
452 editor.add_annotation(name.syntax(), tabstop);
443453 }
444454
445 assoc_item_list.add_item(new_fn.clone().into());
455 builder.add_file_edits(ctx.vfs_file_id(), editor);
456 return;
446457 }
458 let ty_params = assist_info.strukt.generic_param_list();
459 let ty_args = ty_params.as_ref().map(|it| it.to_generic_args());
460 let impl_def = syntax_factory.impl_(
461 None,
462 ty_params,
463 ty_args,
464 syntax_factory
465 .ty_path(syntax_factory.ident_path(&assist_info.strukt.name().unwrap().to_string()))
466 .into(),
467 None,
468 Some(syntax_factory.assoc_item_list(items)),
469 );
470 let mut editor = builder.make_editor(assist_info.strukt.syntax());
471 editor.insert_all(
472 Position::after(assist_info.strukt.syntax()),
473 vec![syntax_factory.whitespace("\n\n").into(), impl_def.syntax().clone().into()],
474 );
475
476 if let Some(cap) = ctx.config.snippet_cap
477 && let Some(assoc_list) = impl_def.assoc_item_list()
478 && let Some(ast::AssocItem::Fn(fn_)) = assoc_list.assoc_items().last()
479 && let Some(name) = fn_.name()
480 {
481 let tabstop = builder.make_tabstop_before(cap);
482 editor.add_annotation(name.syntax().clone(), tabstop);
483 }
484
485 builder.add_file_edits(ctx.vfs_file_id(), editor);
447486}
448487
449488#[cfg(test)]
src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_impl.rs+15-6
......@@ -1,5 +1,5 @@
11use syntax::{
2 ast::{self, AstNode, HasGenericParams, HasName, edit_in_place::Indent, make},
2 ast::{self, AstNode, HasGenericParams, HasName, edit::AstNodeEdit, make},
33 syntax_editor::{Position, SyntaxEditor},
44};
55
......@@ -8,10 +8,14 @@ use crate::{
88 utils::{self, DefaultMethods, IgnoreAssocItems},
99};
1010
11fn insert_impl(editor: &mut SyntaxEditor, impl_: &ast::Impl, nominal: &impl Indent) {
11fn insert_impl(
12 editor: &mut SyntaxEditor,
13 impl_: &ast::Impl,
14 nominal: &impl AstNodeEdit,
15) -> ast::Impl {
1216 let indent = nominal.indent_level();
1317
14 impl_.indent(indent);
18 let impl_ = impl_.indent(indent);
1519 editor.insert_all(
1620 Position::after(nominal.syntax()),
1721 vec![
......@@ -20,6 +24,8 @@ fn insert_impl(editor: &mut SyntaxEditor, impl_: &ast::Impl, nominal: &impl Inde
2024 impl_.syntax().clone().into(),
2125 ],
2226 );
27
28 impl_
2329}
2430
2531// Assist: generate_impl
......@@ -57,6 +63,8 @@ pub(crate) fn generate_impl(acc: &mut Assists, ctx: &AssistContext<'_>) -> Optio
5763 let impl_ = utils::generate_impl(&nominal);
5864
5965 let mut editor = edit.make_editor(nominal.syntax());
66
67 let impl_ = insert_impl(&mut editor, &impl_, &nominal);
6068 // Add a tabstop after the left curly brace
6169 if let Some(cap) = ctx.config.snippet_cap
6270 && let Some(l_curly) = impl_.assoc_item_list().and_then(|it| it.l_curly_token())
......@@ -65,7 +73,6 @@ pub(crate) fn generate_impl(acc: &mut Assists, ctx: &AssistContext<'_>) -> Optio
6573 editor.add_annotation(l_curly, tabstop);
6674 }
6775
68 insert_impl(&mut editor, &impl_, &nominal);
6976 edit.add_file_edits(ctx.vfs_file_id(), editor);
7077 },
7178 )
......@@ -106,6 +113,8 @@ pub(crate) fn generate_trait_impl(acc: &mut Assists, ctx: &AssistContext<'_>) ->
106113 let impl_ = utils::generate_trait_impl_intransitive(&nominal, make::ty_placeholder());
107114
108115 let mut editor = edit.make_editor(nominal.syntax());
116
117 let impl_ = insert_impl(&mut editor, &impl_, &nominal);
109118 // Make the trait type a placeholder snippet
110119 if let Some(cap) = ctx.config.snippet_cap {
111120 if let Some(trait_) = impl_.trait_() {
......@@ -119,7 +128,6 @@ pub(crate) fn generate_trait_impl(acc: &mut Assists, ctx: &AssistContext<'_>) ->
119128 }
120129 }
121130
122 insert_impl(&mut editor, &impl_, &nominal);
123131 edit.add_file_edits(ctx.vfs_file_id(), editor);
124132 },
125133 )
......@@ -206,6 +214,8 @@ pub(crate) fn generate_impl_trait(acc: &mut Assists, ctx: &AssistContext<'_>) ->
206214 make_impl_(Some(assoc_item_list))
207215 };
208216
217 let impl_ = insert_impl(&mut editor, &impl_, &trait_);
218
209219 if let Some(cap) = ctx.config.snippet_cap {
210220 if let Some(generics) = impl_.trait_().and_then(|it| it.generic_arg_list()) {
211221 for generic in generics.generic_args() {
......@@ -232,7 +242,6 @@ pub(crate) fn generate_impl_trait(acc: &mut Assists, ctx: &AssistContext<'_>) ->
232242 }
233243 }
234244
235 insert_impl(&mut editor, &impl_, &trait_);
236245 edit.add_file_edits(ctx.vfs_file_id(), editor);
237246 },
238247 )
src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_mut_trait_impl.rs+3-3
......@@ -1,7 +1,7 @@
11use ide_db::{famous_defs::FamousDefs, traits::resolve_target_trait};
22use syntax::{
33 AstNode, SyntaxElement, SyntaxNode, T,
4 ast::{self, edit::AstNodeEdit, edit_in_place::Indent, syntax_factory::SyntaxFactory},
4 ast::{self, edit::AstNodeEdit, syntax_factory::SyntaxFactory},
55 syntax_editor::{Element, Position, SyntaxEditor},
66};
77
......@@ -46,7 +46,7 @@ use crate::{AssistContext, AssistId, Assists};
4646// ```
4747pub(crate) fn generate_mut_trait_impl(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
4848 let impl_def = ctx.find_node_at_offset::<ast::Impl>()?;
49 let indent = Indent::indent_level(&impl_def);
49 let indent = impl_def.indent_level();
5050
5151 let ast::Type::PathType(path) = impl_def.trait_()? else {
5252 return None;
......@@ -78,7 +78,7 @@ pub(crate) fn generate_mut_trait_impl(acc: &mut Assists, ctx: &AssistContext<'_>
7878
7979 let new_impl = ast::Impl::cast(new_root.clone()).unwrap();
8080
81 Indent::indent(&new_impl, indent);
81 let new_impl = new_impl.indent(indent);
8282
8383 let mut editor = edit.make_editor(impl_def.syntax());
8484 editor.insert_all(
src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_new.rs+6-7
......@@ -3,7 +3,7 @@ use ide_db::{
33 use_trivial_constructor::use_trivial_constructor,
44};
55use syntax::{
6 ast::{self, AstNode, HasName, HasVisibility, StructKind, edit_in_place::Indent, make},
6 ast::{self, AstNode, HasName, HasVisibility, StructKind, edit::AstNodeEdit, make},
77 syntax_editor::Position,
88};
99
......@@ -150,14 +150,14 @@ pub(crate) fn generate_new(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option
150150 false,
151151 false,
152152 )
153 .clone_for_update();
154 fn_.indent(1.into());
153 .clone_for_update()
154 .indent(1.into());
155155
156156 let mut editor = builder.make_editor(strukt.syntax());
157157
158158 // Get the node for set annotation
159159 let contain_fn = if let Some(impl_def) = impl_def {
160 fn_.indent(impl_def.indent_level());
160 let fn_ = fn_.indent(impl_def.indent_level());
161161
162162 if let Some(l_curly) = impl_def.assoc_item_list().and_then(|list| list.l_curly_token())
163163 {
......@@ -182,9 +182,8 @@ pub(crate) fn generate_new(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option
182182 let indent_level = strukt.indent_level();
183183 let body = vec![ast::AssocItem::Fn(fn_)];
184184 let list = make::assoc_item_list(Some(body));
185 let impl_def = generate_impl_with_item(&ast::Adt::Struct(strukt.clone()), Some(list));
186
187 impl_def.indent(strukt.indent_level());
185 let impl_def = generate_impl_with_item(&ast::Adt::Struct(strukt.clone()), Some(list))
186 .indent(strukt.indent_level());
188187
189188 // Insert it after the adt
190189 editor.insert_all(
src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_trait_from_impl.rs+1-1
......@@ -2,7 +2,7 @@ use crate::assist_context::{AssistContext, Assists};
22use ide_db::assists::AssistId;
33use syntax::{
44 AstNode, SyntaxKind, T,
5 ast::{self, HasGenericParams, HasName, HasVisibility, edit_in_place::Indent, make},
5 ast::{self, HasGenericParams, HasName, HasVisibility, edit::AstNodeEdit, make},
66 syntax_editor::{Position, SyntaxEditor},
77};
88
src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs+52
......@@ -403,6 +403,12 @@ fn inline(
403403 .find(|tok| tok.kind() == SyntaxKind::SELF_TYPE_KW)
404404 {
405405 let replace_with = t.clone_subtree().syntax().clone_for_update();
406 if !is_in_type_path(&self_tok)
407 && let Some(ty) = ast::Type::cast(replace_with.clone())
408 && let Some(generic_arg_list) = ty.generic_arg_list()
409 {
410 ted::remove(generic_arg_list.syntax());
411 }
406412 ted::replace(self_tok, replace_with);
407413 }
408414 }
......@@ -588,6 +594,17 @@ fn inline(
588594 }
589595}
590596
597fn is_in_type_path(self_tok: &syntax::SyntaxToken) -> bool {
598 self_tok
599 .parent_ancestors()
600 .skip_while(|it| !ast::Path::can_cast(it.kind()))
601 .map_while(ast::Path::cast)
602 .last()
603 .and_then(|it| it.syntax().parent())
604 .and_then(ast::PathType::cast)
605 .is_some()
606}
607
591608fn path_expr_as_record_field(usage: &PathExpr) -> Option<ast::RecordExprField> {
592609 let path = usage.path()?;
593610 let name_ref = path.as_single_name_ref()?;
......@@ -1694,6 +1711,41 @@ fn main() {
16941711 )
16951712 }
16961713
1714 #[test]
1715 fn inline_trait_method_call_with_lifetimes() {
1716 check_assist(
1717 inline_call,
1718 r#"
1719trait Trait {
1720 fn f() -> Self;
1721}
1722struct Foo<'a>(&'a ());
1723impl<'a> Trait for Foo<'a> {
1724 fn f() -> Self { Self(&()) }
1725}
1726impl Foo<'_> {
1727 fn new() -> Self {
1728 Self::$0f()
1729 }
1730}
1731"#,
1732 r#"
1733trait Trait {
1734 fn f() -> Self;
1735}
1736struct Foo<'a>(&'a ());
1737impl<'a> Trait for Foo<'a> {
1738 fn f() -> Self { Self(&()) }
1739}
1740impl Foo<'_> {
1741 fn new() -> Self {
1742 Foo(&())
1743 }
1744}
1745"#,
1746 )
1747 }
1748
16971749 #[test]
16981750 fn method_by_reborrow() {
16991751 check_assist(
src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_lifetime.rs+140-69
......@@ -1,11 +1,12 @@
1use ide_db::FxHashSet;
1use ide_db::{FileId, FxHashSet};
22use syntax::{
3 AstNode, TextRange,
4 ast::{self, HasGenericParams, edit_in_place::GenericParamsOwnerEdit, make},
5 ted::{self, Position},
3 AstNode, SmolStr, T, TextRange, ToSmolStr,
4 ast::{self, HasGenericParams, HasName, syntax_factory::SyntaxFactory},
5 format_smolstr,
6 syntax_editor::{Element, Position, SyntaxEditor},
67};
78
8use crate::{AssistContext, AssistId, Assists, assist_context::SourceChangeBuilder};
9use crate::{AssistContext, AssistId, Assists};
910
1011static ASSIST_NAME: &str = "introduce_named_lifetime";
1112static ASSIST_LABEL: &str = "Introduce named lifetime";
......@@ -38,100 +39,108 @@ pub(crate) fn introduce_named_lifetime(acc: &mut Assists, ctx: &AssistContext<'_
3839 // FIXME: should also add support for the case fun(f: &Foo) -> &$0Foo
3940 let lifetime =
4041 ctx.find_node_at_offset::<ast::Lifetime>().filter(|lifetime| lifetime.text() == "'_")?;
42 let file_id = ctx.vfs_file_id();
4143 let lifetime_loc = lifetime.lifetime_ident_token()?.text_range();
4244
4345 if let Some(fn_def) = lifetime.syntax().ancestors().find_map(ast::Fn::cast) {
44 generate_fn_def_assist(acc, fn_def, lifetime_loc, lifetime)
46 generate_fn_def_assist(acc, fn_def, lifetime_loc, lifetime, file_id)
4547 } else if let Some(impl_def) = lifetime.syntax().ancestors().find_map(ast::Impl::cast) {
46 generate_impl_def_assist(acc, impl_def, lifetime_loc, lifetime)
48 generate_impl_def_assist(acc, impl_def, lifetime_loc, lifetime, file_id)
4749 } else {
4850 None
4951 }
5052}
5153
52/// Generate the assist for the fn def case
54/// Given a type parameter list, generate a unique lifetime parameter name
55/// which is not in the list
56fn generate_unique_lifetime_param_name(
57 existing_params: Option<ast::GenericParamList>,
58) -> Option<SmolStr> {
59 let used_lifetime_param: FxHashSet<SmolStr> = existing_params
60 .iter()
61 .flat_map(|params| params.lifetime_params())
62 .map(|p| p.syntax().text().to_smolstr())
63 .collect();
64 ('a'..='z').map(|c| format_smolstr!("'{c}")).find(|lt| !used_lifetime_param.contains(lt))
65}
66
5367fn generate_fn_def_assist(
5468 acc: &mut Assists,
5569 fn_def: ast::Fn,
5670 lifetime_loc: TextRange,
5771 lifetime: ast::Lifetime,
72 file_id: FileId,
5873) -> Option<()> {
59 let param_list: ast::ParamList = fn_def.param_list()?;
60 let new_lifetime_param = generate_unique_lifetime_param_name(fn_def.generic_param_list())?;
74 let param_list = fn_def.param_list()?;
75 let new_lifetime_name = generate_unique_lifetime_param_name(fn_def.generic_param_list())?;
6176 let self_param =
62 // use the self if it's a reference and has no explicit lifetime
6377 param_list.self_param().filter(|p| p.lifetime().is_none() && p.amp_token().is_some());
64 // compute the location which implicitly has the same lifetime as the anonymous lifetime
78
6579 let loc_needing_lifetime = if let Some(self_param) = self_param {
66 // if we have a self reference, use that
6780 Some(NeedsLifetime::SelfParam(self_param))
6881 } else {
69 // otherwise, if there's a single reference parameter without a named lifetime, use that
70 let fn_params_without_lifetime: Vec<_> = param_list
82 let unnamed_refs: Vec<_> = param_list
7183 .params()
7284 .filter_map(|param| match param.ty() {
73 Some(ast::Type::RefType(ascribed_type)) if ascribed_type.lifetime().is_none() => {
74 Some(NeedsLifetime::RefType(ascribed_type))
85 Some(ast::Type::RefType(ref_type)) if ref_type.lifetime().is_none() => {
86 Some(NeedsLifetime::RefType(ref_type))
7587 }
7688 _ => None,
7789 })
7890 .collect();
79 match fn_params_without_lifetime.len() {
80 1 => Some(fn_params_without_lifetime.into_iter().next()?),
91
92 match unnamed_refs.len() {
93 1 => Some(unnamed_refs.into_iter().next()?),
8194 0 => None,
82 // multiple unnamed is invalid. assist is not applicable
8395 _ => return None,
8496 }
8597 };
86 acc.add(AssistId::refactor(ASSIST_NAME), ASSIST_LABEL, lifetime_loc, |builder| {
87 let fn_def = builder.make_mut(fn_def);
88 let lifetime = builder.make_mut(lifetime);
89 let loc_needing_lifetime =
90 loc_needing_lifetime.and_then(|it| it.make_mut(builder).to_position());
91
92 fn_def.get_or_create_generic_param_list().add_generic_param(
93 make::lifetime_param(new_lifetime_param.clone()).clone_for_update().into(),
94 );
95 ted::replace(lifetime.syntax(), new_lifetime_param.clone_for_update().syntax());
96 if let Some(position) = loc_needing_lifetime {
97 ted::insert(position, new_lifetime_param.clone_for_update().syntax());
98
99 acc.add(AssistId::refactor(ASSIST_NAME), ASSIST_LABEL, lifetime_loc, |edit| {
100 let root = fn_def.syntax().ancestors().last().unwrap().clone();
101 let mut editor = SyntaxEditor::new(root);
102 let factory = SyntaxFactory::with_mappings();
103
104 if let Some(generic_list) = fn_def.generic_param_list() {
105 insert_lifetime_param(&mut editor, &factory, &generic_list, &new_lifetime_name);
106 } else {
107 insert_new_generic_param_list_fn(&mut editor, &factory, &fn_def, &new_lifetime_name);
98108 }
109
110 editor.replace(lifetime.syntax(), factory.lifetime(&new_lifetime_name).syntax());
111
112 if let Some(pos) = loc_needing_lifetime.and_then(|l| l.to_position()) {
113 editor.insert_all(
114 pos,
115 vec![
116 factory.lifetime(&new_lifetime_name).syntax().clone().into(),
117 factory.whitespace(" ").into(),
118 ],
119 );
120 }
121
122 edit.add_file_edits(file_id, editor);
99123 })
100124}
101125
102/// Generate the assist for the impl def case
103fn generate_impl_def_assist(
104 acc: &mut Assists,
105 impl_def: ast::Impl,
106 lifetime_loc: TextRange,
107 lifetime: ast::Lifetime,
126fn insert_new_generic_param_list_fn(
127 editor: &mut SyntaxEditor,
128 factory: &SyntaxFactory,
129 fn_def: &ast::Fn,
130 lifetime_name: &str,
108131) -> Option<()> {
109 let new_lifetime_param = generate_unique_lifetime_param_name(impl_def.generic_param_list())?;
110 acc.add(AssistId::refactor(ASSIST_NAME), ASSIST_LABEL, lifetime_loc, |builder| {
111 let impl_def = builder.make_mut(impl_def);
112 let lifetime = builder.make_mut(lifetime);
132 let name = fn_def.name()?;
113133
114 impl_def.get_or_create_generic_param_list().add_generic_param(
115 make::lifetime_param(new_lifetime_param.clone()).clone_for_update().into(),
116 );
117 ted::replace(lifetime.syntax(), new_lifetime_param.clone_for_update().syntax());
118 })
119}
134 editor.insert_all(
135 Position::after(name.syntax()),
136 vec![
137 factory.token(T![<]).syntax_element(),
138 factory.lifetime(lifetime_name).syntax().syntax_element(),
139 factory.token(T![>]).syntax_element(),
140 ],
141 );
120142
121/// Given a type parameter list, generate a unique lifetime parameter name
122/// which is not in the list
123fn generate_unique_lifetime_param_name(
124 existing_type_param_list: Option<ast::GenericParamList>,
125) -> Option<ast::Lifetime> {
126 match existing_type_param_list {
127 Some(type_params) => {
128 let used_lifetime_params: FxHashSet<_> =
129 type_params.lifetime_params().map(|p| p.syntax().text().to_string()).collect();
130 ('a'..='z').map(|it| format!("'{it}")).find(|it| !used_lifetime_params.contains(it))
131 }
132 None => Some("'a".to_owned()),
133 }
134 .map(|it| make::lifetime(&it))
143 Some(())
135144}
136145
137146enum NeedsLifetime {
......@@ -140,13 +149,6 @@ enum NeedsLifetime {
140149}
141150
142151impl NeedsLifetime {
143 fn make_mut(self, builder: &mut SourceChangeBuilder) -> Self {
144 match self {
145 Self::SelfParam(it) => Self::SelfParam(builder.make_mut(it)),
146 Self::RefType(it) => Self::RefType(builder.make_mut(it)),
147 }
148 }
149
150152 fn to_position(self) -> Option<Position> {
151153 match self {
152154 Self::SelfParam(it) => Some(Position::after(it.amp_token()?)),
......@@ -155,6 +157,75 @@ impl NeedsLifetime {
155157 }
156158}
157159
160fn generate_impl_def_assist(
161 acc: &mut Assists,
162 impl_def: ast::Impl,
163 lifetime_loc: TextRange,
164 lifetime: ast::Lifetime,
165 file_id: FileId,
166) -> Option<()> {
167 let new_lifetime_name = generate_unique_lifetime_param_name(impl_def.generic_param_list())?;
168
169 acc.add(AssistId::refactor(ASSIST_NAME), ASSIST_LABEL, lifetime_loc, |edit| {
170 let root = impl_def.syntax().ancestors().last().unwrap().clone();
171 let mut editor = SyntaxEditor::new(root);
172 let factory = SyntaxFactory::without_mappings();
173
174 if let Some(generic_list) = impl_def.generic_param_list() {
175 insert_lifetime_param(&mut editor, &factory, &generic_list, &new_lifetime_name);
176 } else {
177 insert_new_generic_param_list_imp(&mut editor, &factory, &impl_def, &new_lifetime_name);
178 }
179
180 editor.replace(lifetime.syntax(), factory.lifetime(&new_lifetime_name).syntax());
181
182 edit.add_file_edits(file_id, editor);
183 })
184}
185
186fn insert_new_generic_param_list_imp(
187 editor: &mut SyntaxEditor,
188 factory: &SyntaxFactory,
189 impl_: &ast::Impl,
190 lifetime_name: &str,
191) -> Option<()> {
192 let impl_kw = impl_.impl_token()?;
193
194 editor.insert_all(
195 Position::after(impl_kw),
196 vec![
197 factory.token(T![<]).syntax_element(),
198 factory.lifetime(lifetime_name).syntax().syntax_element(),
199 factory.token(T![>]).syntax_element(),
200 ],
201 );
202
203 Some(())
204}
205
206fn insert_lifetime_param(
207 editor: &mut SyntaxEditor,
208 factory: &SyntaxFactory,
209 generic_list: &ast::GenericParamList,
210 lifetime_name: &str,
211) -> Option<()> {
212 let r_angle = generic_list.r_angle_token()?;
213 let needs_comma = generic_list.generic_params().next().is_some();
214
215 let mut elements = Vec::new();
216
217 if needs_comma {
218 elements.push(factory.token(T![,]).syntax_element());
219 elements.push(factory.whitespace(" ").syntax_element());
220 }
221
222 let lifetime = factory.lifetime(lifetime_name);
223 elements.push(lifetime.syntax().clone().into());
224
225 editor.insert_all(Position::before(r_angle), elements);
226 Some(())
227}
228
158229#[cfg(test)]
159230mod tests {
160231 use super::*;
src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_const_to_impl.rs+6-2
......@@ -2,7 +2,10 @@ use hir::{AsAssocItem, AssocItemContainer, FileRange, HasSource};
22use ide_db::{assists::AssistId, defs::Definition, search::SearchScope};
33use syntax::{
44 SyntaxKind,
5 ast::{self, AstNode, edit::IndentLevel, edit_in_place::Indent},
5 ast::{
6 self, AstNode,
7 edit::{AstNodeEdit, IndentLevel},
8 },
69};
710
811use crate::assist_context::{AssistContext, Assists};
......@@ -136,7 +139,8 @@ pub(crate) fn move_const_to_impl(acc: &mut Assists, ctx: &AssistContext<'_>) ->
136139 let indent = IndentLevel::from_node(parent_fn.syntax());
137140
138141 let const_ = const_.clone_for_update();
139 const_.reindent_to(indent);
142 let const_ = const_.reset_indent();
143 let const_ = const_.indent(indent);
140144 builder.insert(insert_offset, format!("\n{indent}{const_}{fixup}"));
141145 },
142146 )
src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs+23
......@@ -1307,6 +1307,29 @@ impl<T: Clone> Clone for Foo<T> {
13071307 )
13081308 }
13091309
1310 #[test]
1311 fn add_custom_impl_clone_generic_tuple_struct_with_associated() {
1312 check_assist(
1313 replace_derive_with_manual_impl,
1314 r#"
1315//- minicore: clone, derive, deref
1316#[derive(Clo$0ne)]
1317struct Foo<T: core::ops::Deref>(T::Target);
1318"#,
1319 r#"
1320struct Foo<T: core::ops::Deref>(T::Target);
1321
1322impl<T: core::ops::Deref + Clone> Clone for Foo<T>
1323where T::Target: Clone
1324{
1325 $0fn clone(&self) -> Self {
1326 Self(self.0.clone())
1327 }
1328}
1329"#,
1330 )
1331 }
1332
13101333 #[test]
13111334 fn test_ignore_derive_macro_without_input() {
13121335 check_assist_not_applicable(
src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_if_let_with_match.rs+32-30
......@@ -3,7 +3,11 @@ use std::iter::successors;
33use ide_db::{RootDatabase, defs::NameClass, ty_filter::TryEnum};
44use syntax::{
55 AstNode, Edition, SyntaxKind, T, TextRange,
6 ast::{self, HasName, edit::IndentLevel, edit_in_place::Indent, syntax_factory::SyntaxFactory},
6 ast::{
7 self, HasName,
8 edit::{AstNodeEdit, IndentLevel},
9 syntax_factory::SyntaxFactory,
10 },
711 syntax_editor::SyntaxEditor,
812};
913
......@@ -54,8 +58,7 @@ pub(crate) fn replace_if_let_with_match(acc: &mut Assists, ctx: &AssistContext<'
5458 ast::ElseBranch::IfExpr(expr) => Some(expr),
5559 ast::ElseBranch::Block(block) => {
5660 let block = unwrap_trivial_block(block).clone_for_update();
57 block.reindent_to(IndentLevel(1));
58 else_block = Some(block);
61 else_block = Some(block.reset_indent().indent(IndentLevel(1)));
5962 None
6063 }
6164 });
......@@ -82,12 +85,13 @@ pub(crate) fn replace_if_let_with_match(acc: &mut Assists, ctx: &AssistContext<'
8285 (Some(pat), guard)
8386 }
8487 };
85 if let Some(guard) = &guard {
86 guard.dedent(indent);
87 guard.indent(IndentLevel(1));
88 }
89 let body = if_expr.then_branch()?.clone_for_update();
90 body.indent(IndentLevel(1));
88 let guard = if let Some(guard) = &guard {
89 Some(guard.dedent(indent).indent(IndentLevel(1)))
90 } else {
91 guard
92 };
93
94 let body = if_expr.then_branch()?.clone_for_update().indent(IndentLevel(1));
9195 cond_bodies.push((cond, guard, body));
9296 }
9397
......@@ -109,7 +113,8 @@ pub(crate) fn replace_if_let_with_match(acc: &mut Assists, ctx: &AssistContext<'
109113 let else_arm = make_else_arm(ctx, &make, else_block, &cond_bodies);
110114 let make_match_arm =
111115 |(pat, guard, body): (_, Option<ast::Expr>, ast::BlockExpr)| {
112 body.reindent_to(IndentLevel::single());
116 // Dedent from original position, then indent for match arm
117 let body = body.dedent(indent).indent(IndentLevel::single());
113118 let body = unwrap_trivial_block(body);
114119 match (pat, guard.map(|it| make.match_guard(it))) {
115120 (Some(pat), guard) => make.match_arm(pat, guard, body),
......@@ -122,8 +127,8 @@ pub(crate) fn replace_if_let_with_match(acc: &mut Assists, ctx: &AssistContext<'
122127 }
123128 };
124129 let arms = cond_bodies.into_iter().map(make_match_arm).chain([else_arm]);
125 let match_expr = make.expr_match(scrutinee_to_be_expr, make.match_arm_list(arms));
126 match_expr.indent(indent);
130 let match_expr =
131 make.expr_match(scrutinee_to_be_expr, make.match_arm_list(arms)).indent(indent);
127132 match_expr.into()
128133 };
129134
......@@ -131,10 +136,9 @@ pub(crate) fn replace_if_let_with_match(acc: &mut Assists, ctx: &AssistContext<'
131136 if_expr.syntax().parent().is_some_and(|it| ast::IfExpr::can_cast(it.kind()));
132137 let expr = if has_preceding_if_expr {
133138 // make sure we replace the `else if let ...` with a block so we don't end up with `else expr`
134 match_expr.dedent(indent);
135 match_expr.indent(IndentLevel(1));
136 let block_expr = make.block_expr([], Some(match_expr));
137 block_expr.indent(indent);
139 let block_expr = make
140 .block_expr([], Some(match_expr.dedent(indent).indent(IndentLevel(1))))
141 .indent(indent);
138142 block_expr.into()
139143 } else {
140144 match_expr
......@@ -267,10 +271,7 @@ pub(crate) fn replace_match_with_if_let(acc: &mut Assists, ctx: &AssistContext<'
267271 // wrap them in another BlockExpr.
268272 match expr {
269273 ast::Expr::BlockExpr(block) if block.modifier().is_none() => block,
270 expr => {
271 expr.indent(IndentLevel(1));
272 make.block_expr([], Some(expr))
273 }
274 expr => make.block_expr([], Some(expr.indent(IndentLevel(1)))),
274275 }
275276 };
276277
......@@ -292,18 +293,19 @@ pub(crate) fn replace_match_with_if_let(acc: &mut Assists, ctx: &AssistContext<'
292293 } else {
293294 condition
294295 };
295 let then_expr = then_expr.clone_for_update();
296 let else_expr = else_expr.clone_for_update();
297 then_expr.reindent_to(IndentLevel::single());
298 else_expr.reindent_to(IndentLevel::single());
296 let then_expr =
297 then_expr.clone_for_update().reset_indent().indent(IndentLevel::single());
298 let else_expr =
299 else_expr.clone_for_update().reset_indent().indent(IndentLevel::single());
299300 let then_block = make_block_expr(then_expr);
300301 let else_expr = if is_empty_expr(&else_expr) { None } else { Some(else_expr) };
301 let if_let_expr = make.expr_if(
302 condition,
303 then_block,
304 else_expr.map(make_block_expr).map(ast::ElseBranch::Block),
305 );
306 if_let_expr.indent(IndentLevel::from_node(match_expr.syntax()));
302 let if_let_expr = make
303 .expr_if(
304 condition,
305 then_block,
306 else_expr.map(make_block_expr).map(ast::ElseBranch::Block),
307 )
308 .indent(IndentLevel::from_node(match_expr.syntax()));
307309
308310 let mut editor = builder.make_editor(match_expr.syntax());
309311 editor.replace(match_expr.syntax(), if_let_expr.syntax());
src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_let_with_if_let.rs+6-2
......@@ -1,7 +1,11 @@
11use ide_db::ty_filter::TryEnum;
22use syntax::{
33 AstNode, T,
4 ast::{self, edit::IndentLevel, edit_in_place::Indent, syntax_factory::SyntaxFactory},
4 ast::{
5 self,
6 edit::{AstNodeEdit, IndentLevel},
7 syntax_factory::SyntaxFactory,
8 },
59};
610
711use crate::{AssistContext, AssistId, Assists};
......@@ -64,7 +68,7 @@ pub(crate) fn replace_let_with_if_let(acc: &mut Assists, ctx: &AssistContext<'_>
6468 if let_expr_needs_paren(&init) { make.expr_paren(init).into() } else { init };
6569
6670 let block = make.block_expr([], None);
67 block.indent(IndentLevel::from_node(let_stmt.syntax()));
71 let block = block.indent(IndentLevel::from_node(let_stmt.syntax()));
6872 let if_expr = make.expr_if(
6973 make.expr_let(pat, init_expr).into(),
7074 block,
src/tools/rust-analyzer/crates/ide-assists/src/utils.rs+52-1
......@@ -14,6 +14,7 @@ use ide_db::{
1414 path_transform::PathTransform,
1515 syntax_helpers::{node_ext::preorder_expr, prettify_macro_expansion},
1616};
17use itertools::Itertools;
1718use stdx::format_to;
1819use syntax::{
1920 AstNode, AstToken, Direction, NodeOrToken, SourceFile,
......@@ -765,6 +766,11 @@ fn generate_impl_inner(
765766 });
766767 let generic_args =
767768 generic_params.as_ref().map(|params| params.to_generic_args().clone_for_update());
769 let adt_assoc_bounds = trait_
770 .as_ref()
771 .zip(generic_params.as_ref())
772 .and_then(|(trait_, params)| generic_param_associated_bounds(adt, trait_, params));
773
768774 let ty = make::ty_path(make::ext::ident_path(&adt.name().unwrap().text()));
769775
770776 let cfg_attrs =
......@@ -780,7 +786,7 @@ fn generate_impl_inner(
780786 false,
781787 trait_,
782788 ty,
783 None,
789 adt_assoc_bounds,
784790 adt.where_clause(),
785791 body,
786792 ),
......@@ -789,6 +795,51 @@ fn generate_impl_inner(
789795 .clone_for_update()
790796}
791797
798fn generic_param_associated_bounds(
799 adt: &ast::Adt,
800 trait_: &ast::Type,
801 generic_params: &ast::GenericParamList,
802) -> Option<ast::WhereClause> {
803 let in_type_params = |name: &ast::NameRef| {
804 generic_params
805 .generic_params()
806 .filter_map(|param| match param {
807 ast::GenericParam::TypeParam(type_param) => type_param.name(),
808 _ => None,
809 })
810 .any(|param| param.text() == name.text())
811 };
812 let adt_body = match adt {
813 ast::Adt::Enum(e) => e.variant_list().map(|it| it.syntax().clone()),
814 ast::Adt::Struct(s) => s.field_list().map(|it| it.syntax().clone()),
815 ast::Adt::Union(u) => u.record_field_list().map(|it| it.syntax().clone()),
816 };
817 let mut trait_where_clause = adt_body
818 .into_iter()
819 .flat_map(|it| it.descendants())
820 .filter_map(ast::Path::cast)
821 .filter_map(|path| {
822 let qualifier = path.qualifier()?.as_single_segment()?;
823 let qualifier = qualifier
824 .name_ref()
825 .or_else(|| match qualifier.type_anchor()?.ty()? {
826 ast::Type::PathType(path_type) => path_type.path()?.as_single_name_ref(),
827 _ => None,
828 })
829 .filter(in_type_params)?;
830 Some((qualifier, path.segment()?.name_ref()?))
831 })
832 .map(|(qualifier, assoc_name)| {
833 let segments = [qualifier, assoc_name].map(make::path_segment);
834 let path = make::path_from_segments(segments, false);
835 let bounds = Some(make::type_bound(trait_.clone()));
836 make::where_pred(either::Either::Right(make::ty_path(path)), bounds)
837 })
838 .unique_by(|it| it.syntax().to_string())
839 .peekable();
840 trait_where_clause.peek().is_some().then(|| make::where_clause(trait_where_clause))
841}
842
792843pub(crate) fn add_method_to_adt(
793844 builder: &mut SourceChangeBuilder,
794845 adt: &ast::Adt,
src/tools/rust-analyzer/crates/ide-assists/src/utils/ref_field_expr.rs+17-1
......@@ -5,7 +5,7 @@
55//! based on the parent of the existing expression.
66use syntax::{
77 AstNode, T,
8 ast::{self, FieldExpr, MethodCallExpr, make},
8 ast::{self, FieldExpr, MethodCallExpr, make, syntax_factory::SyntaxFactory},
99};
1010
1111use crate::AssistContext;
......@@ -130,4 +130,20 @@ impl RefData {
130130
131131 expr
132132 }
133
134 pub(crate) fn wrap_expr_with_factory(
135 &self,
136 mut expr: ast::Expr,
137 syntax_factory: &SyntaxFactory,
138 ) -> ast::Expr {
139 if self.needs_deref {
140 expr = syntax_factory.expr_prefix(T![*], expr).into();
141 }
142
143 if self.needs_parentheses {
144 expr = syntax_factory.expr_paren(expr).into();
145 }
146
147 expr
148 }
133149}
src/tools/rust-analyzer/crates/ide-completion/src/context.rs+4-1
......@@ -821,7 +821,10 @@ impl<'db> CompletionContext<'db> {
821821 CompleteSemicolon::DoNotComplete
822822 } else if let Some(term_node) =
823823 sema.token_ancestors_with_macros(token.clone()).find(|node| {
824 matches!(node.kind(), BLOCK_EXPR | MATCH_ARM | CLOSURE_EXPR | ARG_LIST | PAREN_EXPR)
824 matches!(
825 node.kind(),
826 BLOCK_EXPR | MATCH_ARM | CLOSURE_EXPR | ARG_LIST | PAREN_EXPR | ARRAY_EXPR
827 )
825828 })
826829 {
827830 let next_token = iter::successors(token.next_token(), |it| it.next_token())
src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs+19
......@@ -905,6 +905,25 @@ fn baz(_: impl FnOnce()) {}
905905fn bar() {
906906 baz(foo()$0);
907907}
908"#,
909 );
910 }
911
912 #[test]
913 fn no_semicolon_in_array() {
914 check_edit(
915 r#"foo"#,
916 r#"
917fn foo() {}
918fn bar() {
919 let _ = [fo$0];
920}
921"#,
922 r#"
923fn foo() {}
924fn bar() {
925 let _ = [foo()$0];
926}
908927"#,
909928 );
910929 }
src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs+83-5
......@@ -9,7 +9,7 @@ use hir::{
99};
1010use itertools::Itertools;
1111use rustc_hash::{FxHashMap, FxHashSet};
12use smallvec::SmallVec;
12use smallvec::{SmallVec, smallvec};
1313use syntax::{
1414 AstNode, SyntaxNode,
1515 ast::{self, HasName, make},
......@@ -68,6 +68,8 @@ pub struct PathImportCandidate {
6868 pub qualifier: Vec<Name>,
6969 /// The name the item (struct, trait, enum, etc.) should have.
7070 pub name: NameToImport,
71 /// Potentially more segments that should resolve in the candidate.
72 pub after: Vec<Name>,
7173}
7274
7375/// A name that will be used during item lookups.
......@@ -376,7 +378,7 @@ fn path_applicable_imports(
376378) -> FxIndexSet<LocatedImport> {
377379 let _p = tracing::info_span!("ImportAssets::path_applicable_imports").entered();
378380
379 match &*path_candidate.qualifier {
381 let mut result = match &*path_candidate.qualifier {
380382 [] => {
381383 items_locator::items_with_name(
382384 db,
......@@ -433,6 +435,75 @@ fn path_applicable_imports(
433435 })
434436 .take(DEFAULT_QUERY_SEARCH_LIMIT)
435437 .collect(),
438 };
439
440 filter_candidates_by_after_path(db, scope, path_candidate, &mut result);
441
442 result
443}
444
445fn filter_candidates_by_after_path(
446 db: &RootDatabase,
447 scope: &SemanticsScope<'_>,
448 path_candidate: &PathImportCandidate,
449 imports: &mut FxIndexSet<LocatedImport>,
450) {
451 if imports.len() <= 1 {
452 // Short-circuit, as even if it doesn't match fully we want it.
453 return;
454 }
455
456 let Some((last_after, after_except_last)) = path_candidate.after.split_last() else {
457 return;
458 };
459
460 let original_imports = imports.clone();
461
462 let traits_in_scope = scope.visible_traits();
463 imports.retain(|import| {
464 let items = if after_except_last.is_empty() {
465 smallvec![import.original_item]
466 } else {
467 let ItemInNs::Types(ModuleDef::Module(item)) = import.original_item else {
468 return false;
469 };
470 // FIXME: This doesn't consider visibilities.
471 item.resolve_mod_path(db, after_except_last.iter().cloned())
472 .into_iter()
473 .flatten()
474 .collect::<SmallVec<[_; 3]>>()
475 };
476 items.into_iter().any(|item| {
477 let has_last_method = |ty: hir::Type<'_>| {
478 ty.iterate_path_candidates(db, scope, &traits_in_scope, Some(last_after), |_| {
479 Some(())
480 })
481 .is_some()
482 };
483 // FIXME: A trait can have an assoc type that has a function/const, that's two segments before last.
484 match item {
485 // A module? Can we resolve one more segment?
486 ItemInNs::Types(ModuleDef::Module(module)) => module
487 .resolve_mod_path(db, [last_after.clone()])
488 .is_some_and(|mut it| it.any(|_| true)),
489 // And ADT/Type Alias? That might be a method.
490 ItemInNs::Types(ModuleDef::Adt(it)) => has_last_method(it.ty(db)),
491 ItemInNs::Types(ModuleDef::BuiltinType(it)) => has_last_method(it.ty(db)),
492 ItemInNs::Types(ModuleDef::TypeAlias(it)) => has_last_method(it.ty(db)),
493 // A trait? Might have an associated item.
494 ItemInNs::Types(ModuleDef::Trait(it)) => it
495 .items(db)
496 .into_iter()
497 .any(|assoc_item| assoc_item.name(db) == Some(last_after.clone())),
498 // Other items? can't resolve one more segment.
499 _ => false,
500 }
501 })
502 });
503
504 if imports.is_empty() {
505 // Better one half-match than zero full matches.
506 *imports = original_imports;
436507 }
437508}
438509
......@@ -759,10 +830,14 @@ impl<'db> ImportCandidate<'db> {
759830 if sema.resolve_path(path).is_some() {
760831 return None;
761832 }
833 let after = std::iter::successors(path.parent_path(), |it| it.parent_path())
834 .map(|seg| seg.segment()?.name_ref().map(|name| Name::new_root(&name.text())))
835 .collect::<Option<_>>()?;
762836 path_import_candidate(
763837 sema,
764838 path.qualifier(),
765839 NameToImport::exact_case_sensitive(path.segment()?.name_ref()?.to_string()),
840 after,
766841 )
767842 }
768843
......@@ -777,6 +852,7 @@ impl<'db> ImportCandidate<'db> {
777852 Some(ImportCandidate::Path(PathImportCandidate {
778853 qualifier: vec![],
779854 name: NameToImport::exact_case_sensitive(name.to_string()),
855 after: vec![],
780856 }))
781857 }
782858
......@@ -785,7 +861,8 @@ impl<'db> ImportCandidate<'db> {
785861 fuzzy_name: String,
786862 sema: &Semantics<'db, RootDatabase>,
787863 ) -> Option<Self> {
788 path_import_candidate(sema, qualifier, NameToImport::fuzzy(fuzzy_name))
864 // Assume a fuzzy match does not want the segments after. Because... I guess why not?
865 path_import_candidate(sema, qualifier, NameToImport::fuzzy(fuzzy_name), Vec::new())
789866 }
790867}
791868
......@@ -793,6 +870,7 @@ fn path_import_candidate<'db>(
793870 sema: &Semantics<'db, RootDatabase>,
794871 qualifier: Option<ast::Path>,
795872 name: NameToImport,
873 after: Vec<Name>,
796874) -> Option<ImportCandidate<'db>> {
797875 Some(match qualifier {
798876 Some(qualifier) => match sema.resolve_path(&qualifier) {
......@@ -802,7 +880,7 @@ fn path_import_candidate<'db>(
802880 .segments()
803881 .map(|seg| seg.name_ref().map(|name| Name::new_root(&name.text())))
804882 .collect::<Option<Vec<_>>>()?;
805 ImportCandidate::Path(PathImportCandidate { qualifier, name })
883 ImportCandidate::Path(PathImportCandidate { qualifier, name, after })
806884 } else {
807885 return None;
808886 }
......@@ -826,7 +904,7 @@ fn path_import_candidate<'db>(
826904 }
827905 Some(_) => return None,
828906 },
829 None => ImportCandidate::Path(PathImportCandidate { qualifier: vec![], name }),
907 None => ImportCandidate::Path(PathImportCandidate { qualifier: vec![], name, after }),
830908 })
831909}
832910
src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use.rs+199-1
......@@ -9,8 +9,9 @@ use syntax::{
99 Direction, NodeOrToken, SyntaxKind, SyntaxNode, algo,
1010 ast::{
1111 self, AstNode, HasAttrs, HasModuleItem, HasVisibility, PathSegmentKind,
12 edit_in_place::Removable, make,
12 edit_in_place::Removable, make, syntax_factory::SyntaxFactory,
1313 },
14 syntax_editor::{Position, SyntaxEditor},
1415 ted,
1516};
1617
......@@ -146,6 +147,17 @@ pub fn insert_use(scope: &ImportScope, path: ast::Path, cfg: &InsertUseConfig) {
146147 insert_use_with_alias_option(scope, path, cfg, None);
147148}
148149
150/// Insert an import path into the given file/node. A `merge` value of none indicates that no import merging is allowed to occur.
151pub fn insert_use_with_editor(
152 scope: &ImportScope,
153 path: ast::Path,
154 cfg: &InsertUseConfig,
155 syntax_editor: &mut SyntaxEditor,
156 syntax_factory: &SyntaxFactory,
157) {
158 insert_use_with_alias_option_with_editor(scope, path, cfg, None, syntax_editor, syntax_factory);
159}
160
149161pub fn insert_use_as_alias(
150162 scope: &ImportScope,
151163 path: ast::Path,
......@@ -229,6 +241,71 @@ fn insert_use_with_alias_option(
229241 insert_use_(scope, use_item, cfg.group);
230242}
231243
244fn insert_use_with_alias_option_with_editor(
245 scope: &ImportScope,
246 path: ast::Path,
247 cfg: &InsertUseConfig,
248 alias: Option<ast::Rename>,
249 syntax_editor: &mut SyntaxEditor,
250 syntax_factory: &SyntaxFactory,
251) {
252 let _p = tracing::info_span!("insert_use_with_alias_option").entered();
253 let mut mb = match cfg.granularity {
254 ImportGranularity::Crate => Some(MergeBehavior::Crate),
255 ImportGranularity::Module => Some(MergeBehavior::Module),
256 ImportGranularity::One => Some(MergeBehavior::One),
257 ImportGranularity::Item => None,
258 };
259 if !cfg.enforce_granularity {
260 let file_granularity = guess_granularity_from_scope(scope);
261 mb = match file_granularity {
262 ImportGranularityGuess::Unknown => mb,
263 ImportGranularityGuess::Item => None,
264 ImportGranularityGuess::Module => Some(MergeBehavior::Module),
265 // We use the user's setting to infer if this is module or item.
266 ImportGranularityGuess::ModuleOrItem => match mb {
267 Some(MergeBehavior::Module) | None => mb,
268 // There isn't really a way to decide between module or item here, so we just pick one.
269 // FIXME: Maybe it is possible to infer based on semantic analysis?
270 Some(MergeBehavior::One | MergeBehavior::Crate) => Some(MergeBehavior::Module),
271 },
272 ImportGranularityGuess::Crate => Some(MergeBehavior::Crate),
273 ImportGranularityGuess::CrateOrModule => match mb {
274 Some(MergeBehavior::Crate | MergeBehavior::Module) => mb,
275 Some(MergeBehavior::One) | None => Some(MergeBehavior::Crate),
276 },
277 ImportGranularityGuess::One => Some(MergeBehavior::One),
278 };
279 }
280
281 let use_tree = syntax_factory.use_tree(path, None, alias, false);
282 if mb == Some(MergeBehavior::One) && use_tree.path().is_some() {
283 use_tree.wrap_in_tree_list();
284 }
285 let use_item = make::use_(None, None, use_tree).clone_for_update();
286 for attr in
287 scope.required_cfgs.iter().map(|attr| attr.syntax().clone_subtree().clone_for_update())
288 {
289 syntax_editor.insert(Position::first_child_of(use_item.syntax()), attr);
290 }
291
292 // merge into existing imports if possible
293 if let Some(mb) = mb {
294 let filter = |it: &_| !(cfg.skip_glob_imports && ast::Use::is_simple_glob(it));
295 for existing_use in
296 scope.as_syntax_node().children().filter_map(ast::Use::cast).filter(filter)
297 {
298 if let Some(merged) = try_merge_imports(&existing_use, &use_item, mb) {
299 syntax_editor.replace(existing_use.syntax(), merged.syntax());
300 return;
301 }
302 }
303 }
304 // either we weren't allowed to merge or there is no import that fits the merge conditions
305 // so look for the place we have to insert to
306 insert_use_with_editor_(scope, use_item, cfg.group, syntax_editor, syntax_factory);
307}
308
232309pub fn ast_to_remove_for_path_in_use_stmt(path: &ast::Path) -> Option<Box<dyn Removable>> {
233310 // FIXME: improve this
234311 if path.parent_path().is_some() {
......@@ -500,6 +577,127 @@ fn insert_use_(scope: &ImportScope, use_item: ast::Use, group_imports: bool) {
500577 }
501578}
502579
580fn insert_use_with_editor_(
581 scope: &ImportScope,
582 use_item: ast::Use,
583 group_imports: bool,
584 syntax_editor: &mut SyntaxEditor,
585 syntax_factory: &SyntaxFactory,
586) {
587 let scope_syntax = scope.as_syntax_node();
588 let insert_use_tree =
589 use_item.use_tree().expect("`use_item` should have a use tree for `insert_path`");
590 let group = ImportGroup::new(&insert_use_tree);
591 let path_node_iter = scope_syntax
592 .children()
593 .filter_map(|node| ast::Use::cast(node.clone()).zip(Some(node)))
594 .flat_map(|(use_, node)| {
595 let tree = use_.use_tree()?;
596 Some((tree, node))
597 });
598
599 if group_imports {
600 // Iterator that discards anything that's not in the required grouping
601 // This implementation allows the user to rearrange their import groups as this only takes the first group that fits
602 let group_iter = path_node_iter
603 .clone()
604 .skip_while(|(use_tree, ..)| ImportGroup::new(use_tree) != group)
605 .take_while(|(use_tree, ..)| ImportGroup::new(use_tree) == group);
606
607 // 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
608 let mut last = None;
609 // find the element that would come directly after our new import
610 let post_insert: Option<(_, SyntaxNode)> = group_iter
611 .inspect(|(.., node)| last = Some(node.clone()))
612 .find(|(use_tree, _)| use_tree_cmp(&insert_use_tree, use_tree) != Ordering::Greater);
613
614 if let Some((.., node)) = post_insert {
615 cov_mark::hit!(insert_group);
616 // insert our import before that element
617 return syntax_editor.insert(Position::before(node), use_item.syntax());
618 }
619 if let Some(node) = last {
620 cov_mark::hit!(insert_group_last);
621 // there is no element after our new import, so append it to the end of the group
622 return syntax_editor.insert(Position::after(node), use_item.syntax());
623 }
624
625 // the group we were looking for actually doesn't exist, so insert
626
627 let mut last = None;
628 // find the group that comes after where we want to insert
629 let post_group = path_node_iter
630 .inspect(|(.., node)| last = Some(node.clone()))
631 .find(|(use_tree, ..)| ImportGroup::new(use_tree) > group);
632 if let Some((.., node)) = post_group {
633 cov_mark::hit!(insert_group_new_group);
634 syntax_editor.insert(Position::before(&node), use_item.syntax());
635 if let Some(node) = algo::non_trivia_sibling(node.into(), Direction::Prev) {
636 syntax_editor.insert(Position::after(node), syntax_factory.whitespace("\n"));
637 }
638 return;
639 }
640 // there is no such group, so append after the last one
641 if let Some(node) = last {
642 cov_mark::hit!(insert_group_no_group);
643 syntax_editor.insert(Position::after(&node), use_item.syntax());
644 syntax_editor.insert(Position::after(node), syntax_factory.whitespace("\n"));
645 return;
646 }
647 } else {
648 // There exists a group, so append to the end of it
649 if let Some((_, node)) = path_node_iter.last() {
650 cov_mark::hit!(insert_no_grouping_last);
651 syntax_editor.insert(Position::after(node), use_item.syntax());
652 return;
653 }
654 }
655
656 let l_curly = match &scope.kind {
657 ImportScopeKind::File(_) => None,
658 // don't insert the imports before the item list/block expr's opening curly brace
659 ImportScopeKind::Module(item_list) => item_list.l_curly_token(),
660 // don't insert the imports before the item list's opening curly brace
661 ImportScopeKind::Block(block) => block.l_curly_token(),
662 };
663 // there are no imports in this file at all
664 // so put the import after all inner module attributes and possible license header comments
665 if let Some(last_inner_element) = scope_syntax
666 .children_with_tokens()
667 // skip the curly brace
668 .skip(l_curly.is_some() as usize)
669 .take_while(|child| match child {
670 NodeOrToken::Node(node) => is_inner_attribute(node.clone()),
671 NodeOrToken::Token(token) => {
672 [SyntaxKind::WHITESPACE, SyntaxKind::COMMENT, SyntaxKind::SHEBANG]
673 .contains(&token.kind())
674 }
675 })
676 .filter(|child| child.as_token().is_none_or(|t| t.kind() != SyntaxKind::WHITESPACE))
677 .last()
678 {
679 cov_mark::hit!(insert_empty_inner_attr);
680 syntax_editor.insert(Position::after(&last_inner_element), use_item.syntax());
681 syntax_editor.insert(Position::after(last_inner_element), syntax_factory.whitespace("\n"));
682 } else {
683 match l_curly {
684 Some(b) => {
685 cov_mark::hit!(insert_empty_module);
686 syntax_editor.insert(Position::after(&b), syntax_factory.whitespace("\n"));
687 syntax_editor.insert(Position::after(&b), use_item.syntax());
688 }
689 None => {
690 cov_mark::hit!(insert_empty_file);
691 syntax_editor.insert(
692 Position::first_child_of(scope_syntax),
693 syntax_factory.whitespace("\n\n"),
694 );
695 syntax_editor.insert(Position::first_child_of(scope_syntax), use_item.syntax());
696 }
697 }
698 }
699}
700
503701fn is_inner_attribute(node: SyntaxNode) -> bool {
504702 ast::Attr::cast(node).map(|attr| attr.kind()) == Some(ast::AttrKind::Inner)
505703}
src/tools/rust-analyzer/crates/ide/src/hover/tests.rs+93
......@@ -9719,6 +9719,99 @@ fn test_hover_function_with_pat_param() {
97199719 );
97209720}
97219721
9722#[test]
9723fn test_hover_function_with_too_long_param() {
9724 check(
9725 r#"
9726fn fn_$0(
9727 attrs: impl IntoIterator<Item = ast::Attr>,
9728 visibility: Option<ast::Visibility>,
9729 fn_name: ast::Name,
9730 type_params: Option<ast::GenericParamList>,
9731 where_clause: Option<ast::WhereClause>,
9732 params: ast::ParamList,
9733 body: ast::BlockExpr,
9734 ret_type: Option<ast::RetType>,
9735 is_async: bool,
9736 is_const: bool,
9737 is_unsafe: bool,
9738 is_gen: bool,
9739) -> ast::Fn {}
9740 "#,
9741 expect![[r#"
9742 *fn_*
9743
9744 ```rust
9745 ra_test_fixture
9746 ```
9747
9748 ```rust
9749 fn fn_(
9750 attrs: impl IntoIterator<Item = ast::Attr>,
9751 visibility: Option<ast::Visibility>,
9752 fn_name: ast::Name,
9753 type_params: Option<ast::GenericParamList>,
9754 where_clause: Option<ast::WhereClause>,
9755 params: ast::ParamList,
9756 body: ast::BlockExpr,
9757 ret_type: Option<ast::RetType>,
9758 is_async: bool,
9759 is_const: bool,
9760 is_unsafe: bool,
9761 is_gen: bool
9762 ) -> ast::Fn
9763 ```
9764 "#]],
9765 );
9766
9767 check(
9768 r#"
9769fn fn_$0(
9770 &self,
9771 attrs: impl IntoIterator<Item = ast::Attr>,
9772 visibility: Option<ast::Visibility>,
9773 fn_name: ast::Name,
9774 type_params: Option<ast::GenericParamList>,
9775 where_clause: Option<ast::WhereClause>,
9776 params: ast::ParamList,
9777 body: ast::BlockExpr,
9778 ret_type: Option<ast::RetType>,
9779 is_async: bool,
9780 is_const: bool,
9781 is_unsafe: bool,
9782 is_gen: bool,
9783 ...
9784) -> ast::Fn {}
9785 "#,
9786 expect![[r#"
9787 *fn_*
9788
9789 ```rust
9790 ra_test_fixture
9791 ```
9792
9793 ```rust
9794 fn fn_(
9795 &self,
9796 attrs: impl IntoIterator<Item = ast::Attr>,
9797 visibility: Option<ast::Visibility>,
9798 fn_name: ast::Name,
9799 type_params: Option<ast::GenericParamList>,
9800 where_clause: Option<ast::WhereClause>,
9801 params: ast::ParamList,
9802 body: ast::BlockExpr,
9803 ret_type: Option<ast::RetType>,
9804 is_async: bool,
9805 is_const: bool,
9806 is_unsafe: bool,
9807 is_gen: bool,
9808 ...
9809 ) -> ast::Fn
9810 ```
9811 "#]],
9812 );
9813}
9814
97229815#[test]
97239816fn hover_path_inside_block_scope() {
97249817 check(
src/tools/rust-analyzer/crates/ide/src/lib.rs+1-5
......@@ -67,7 +67,7 @@ use ide_db::{
6767 FxHashMap, FxIndexSet, LineIndexDatabase,
6868 base_db::{
6969 CrateOrigin, CrateWorkspaceData, Env, FileSet, RootQueryDb, SourceDatabase, VfsPath,
70 salsa::{CancellationToken, Cancelled, Database},
70 salsa::{Cancelled, Database},
7171 },
7272 prime_caches, symbol_index,
7373};
......@@ -947,10 +947,6 @@ impl Analysis {
947947 // We use `attach_db_allow_change()` and not `attach_db()` because fixture injection can change the database.
948948 hir::attach_db_allow_change(&self.db, || Cancelled::catch(|| f(&self.db)))
949949 }
950
951 pub fn cancellation_token(&self) -> CancellationToken {
952 self.db.cancellation_token()
953 }
954950}
955951
956952#[test]
src/tools/rust-analyzer/crates/ide/src/references.rs+2
......@@ -2073,6 +2073,7 @@ fn func() {}
20732073 expect![[r#"
20742074 identity Attribute FileId(1) 1..107 32..40
20752075
2076 FileId(0) 17..25 import
20762077 FileId(0) 43..51
20772078 "#]],
20782079 );
......@@ -2103,6 +2104,7 @@ mirror$0! {}
21032104 expect![[r#"
21042105 mirror ProcMacro FileId(1) 1..77 22..28
21052106
2107 FileId(0) 17..23 import
21062108 FileId(0) 26..32
21072109 "#]],
21082110 )
src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_macros.html+2-1
......@@ -41,7 +41,8 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
4141.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
4242.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
4343</style>
44<pre><code><span class="keyword">use</span> <span class="crate_root library">proc_macros</span><span class="operator">::</span><span class="brace">{</span><span class="function library">mirror</span><span class="comma">,</span> <span class="function library">identity</span><span class="comma">,</span> <span class="derive library">DeriveIdentity</span><span class="brace">}</span><span class="semicolon">;</span>
44<pre><code><span class="keyword">use</span> <span class="crate_root library">proc_macros</span><span class="operator">::</span><span class="brace">{</span><span class="proc_macro library">mirror</span><span class="comma">,</span> <span class="attribute library">identity</span><span class="comma">,</span> <span class="derive library">DeriveIdentity</span><span class="brace">}</span><span class="semicolon">;</span>
45<span class="keyword">use</span> <span class="crate_root library">pm</span><span class="operator">::</span><span class="attribute library">proc_macro</span><span class="semicolon">;</span>
4546
4647<span class="proc_macro library">mirror</span><span class="macro_bang">!</span> <span class="brace">{</span>
4748 <span class="brace macro proc_macro">{</span>
src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs+7-1
......@@ -55,8 +55,9 @@ fn macros() {
5555 r#"
5656//- proc_macros: mirror, identity, derive_identity
5757//- minicore: fmt, include, concat
58//- /lib.rs crate:lib
58//- /lib.rs crate:lib deps:pm
5959use proc_macros::{mirror, identity, DeriveIdentity};
60use pm::proc_macro;
6061
6162mirror! {
6263 {
......@@ -126,6 +127,11 @@ fn main() {
126127//- /foo/foo.rs crate:foo
127128mod foo {}
128129use self::foo as bar;
130//- /pm.rs crate:pm
131#![crate_type = "proc-macro"]
132
133#[proc_macro_attribute]
134pub fn proc_macro() {}
129135"#,
130136 expect_file!["./test_data/highlight_macros.html"],
131137 false,
src/tools/rust-analyzer/crates/load-cargo/src/lib.rs+2-5
......@@ -26,10 +26,7 @@ use ide_db::{
2626use itertools::Itertools;
2727use proc_macro_api::{
2828 MacroDylib, ProcMacroClient,
29 bidirectional_protocol::{
30 msg::{SubRequest, SubResponse},
31 reject_subrequests,
32 },
29 bidirectional_protocol::msg::{SubRequest, SubResponse},
3330};
3431use project_model::{CargoConfig, PackageRoot, ProjectManifest, ProjectWorkspace};
3532use span::{Span, SpanAnchor, SyntaxContext};
......@@ -446,7 +443,7 @@ pub fn load_proc_macro(
446443) -> ProcMacroLoadResult {
447444 let res: Result<Vec<_>, _> = (|| {
448445 let dylib = MacroDylib::new(path.to_path_buf());
449 let vec = server.load_dylib(dylib, Some(&reject_subrequests)).map_err(|e| {
446 let vec = server.load_dylib(dylib).map_err(|e| {
450447 ProcMacroLoadingError::ProcMacroSrvError(format!("{e}").into_boxed_str())
451448 })?;
452449 if vec.is_empty() {
src/tools/rust-analyzer/crates/proc-macro-api/Cargo.toml+1
......@@ -31,6 +31,7 @@ span = { path = "../span", version = "0.0.0", default-features = false}
3131intern.workspace = true
3232postcard.workspace = true
3333semver.workspace = true
34rayon.workspace = true
3435
3536[features]
3637sysroot-abi = ["proc-macro-srv", "proc-macro-srv/sysroot-abi"]
src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs+2-6
......@@ -198,12 +198,8 @@ impl ProcMacroClient {
198198 }
199199
200200 /// Loads a proc-macro dylib into the server process returning a list of `ProcMacro`s loaded.
201 pub fn load_dylib(
202 &self,
203 dylib: MacroDylib,
204 callback: Option<SubCallback<'_>>,
205 ) -> Result<Vec<ProcMacro>, ServerError> {
206 self.pool.load_dylib(&dylib, callback)
201 pub fn load_dylib(&self, dylib: MacroDylib) -> Result<Vec<ProcMacro>, ServerError> {
202 self.pool.load_dylib(&dylib)
207203 }
208204
209205 /// Checks if the proc-macro server has exited.
src/tools/rust-analyzer/crates/proc-macro-api/src/pool.rs+13-15
......@@ -1,10 +1,9 @@
11//! A pool of proc-macro server processes
22use std::sync::Arc;
33
4use crate::{
5 MacroDylib, ProcMacro, ServerError, bidirectional_protocol::SubCallback,
6 process::ProcMacroServerProcess,
7};
4use rayon::iter::{IntoParallelIterator, ParallelIterator};
5
6use crate::{MacroDylib, ProcMacro, ServerError, process::ProcMacroServerProcess};
87
98#[derive(Debug, Clone)]
109pub(crate) struct ProcMacroServerPool {
......@@ -50,11 +49,7 @@ impl ProcMacroServerPool {
5049 })
5150 }
5251
53 pub(crate) fn load_dylib(
54 &self,
55 dylib: &MacroDylib,
56 callback: Option<SubCallback<'_>>,
57 ) -> Result<Vec<ProcMacro>, ServerError> {
52 pub(crate) fn load_dylib(&self, dylib: &MacroDylib) -> Result<Vec<ProcMacro>, ServerError> {
5853 let _span = tracing::info_span!("ProcMacroServer::load_dylib").entered();
5954
6055 let dylib_path = Arc::new(dylib.path.clone());
......@@ -64,14 +59,17 @@ impl ProcMacroServerPool {
6459 let (first, rest) = self.workers.split_first().expect("worker pool must not be empty");
6560
6661 let macros = first
67 .find_proc_macros(&dylib.path, callback)?
62 .find_proc_macros(&dylib.path)?
6863 .map_err(|e| ServerError { message: e, io: None })?;
6964
70 for worker in rest {
71 worker
72 .find_proc_macros(&dylib.path, callback)?
73 .map_err(|e| ServerError { message: e, io: None })?;
74 }
65 rest.into_par_iter()
66 .map(|worker| {
67 worker
68 .find_proc_macros(&dylib.path)?
69 .map(|_| ())
70 .map_err(|e| ServerError { message: e, io: None })
71 })
72 .collect::<Result<(), _>>()?;
7573
7674 Ok(macros
7775 .into_iter()
src/tools/rust-analyzer/crates/proc-macro-api/src/process.rs+12-4
......@@ -18,7 +18,11 @@ use stdx::JodChild;
1818
1919use crate::{
2020 ProcMacro, ProcMacroKind, ProtocolFormat, ServerError,
21 bidirectional_protocol::{self, SubCallback, msg::BidirectionalMessage, reject_subrequests},
21 bidirectional_protocol::{
22 self, SubCallback,
23 msg::{BidirectionalMessage, SubResponse},
24 reject_subrequests,
25 },
2226 legacy_protocol::{self, SpanMode},
2327 version,
2428};
......@@ -207,14 +211,18 @@ impl ProcMacroServerProcess {
207211 pub(crate) fn find_proc_macros(
208212 &self,
209213 dylib_path: &AbsPath,
210 callback: Option<SubCallback<'_>>,
211214 ) -> Result<Result<Vec<(String, ProcMacroKind)>, String>, ServerError> {
212215 match self.protocol {
213216 Protocol::LegacyJson { .. } => legacy_protocol::find_proc_macros(self, dylib_path),
214217
215218 Protocol::BidirectionalPostcardPrototype { .. } => {
216 let cb = callback.expect("callback required for bidirectional protocol");
217 bidirectional_protocol::find_proc_macros(self, dylib_path, cb)
219 bidirectional_protocol::find_proc_macros(self, dylib_path, &|_| {
220 Ok(SubResponse::Cancel {
221 reason: String::from(
222 "Server should not do a sub request when loading proc-macros",
223 ),
224 })
225 })
218226 }
219227 }
220228 }
src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs+30-58
......@@ -741,70 +741,42 @@ impl FlycheckActor {
741741 flycheck_id = self.id,
742742 message = diagnostic.message,
743743 package_id = package_id.as_ref().map(|it| it.as_str()),
744 scope = ?self.scope,
745744 "diagnostic received"
746745 );
747
748 match &self.scope {
749 FlycheckScope::Workspace => {
750 if self.diagnostics_received == DiagnosticsReceived::NotYet {
751 self.send(FlycheckMessage::ClearDiagnostics {
752 id: self.id,
753 kind: ClearDiagnosticsKind::All(ClearScope::Workspace),
754 });
755
756 self.diagnostics_received =
757 DiagnosticsReceived::AtLeastOneAndClearedWorkspace;
758 }
759
760 if let Some(package_id) = package_id {
761 tracing::warn!(
762 "Ignoring package label {:?} and applying diagnostics to the whole workspace",
763 package_id
764 );
765 }
766
767 self.send(FlycheckMessage::AddDiagnostic {
768 id: self.id,
769 generation: self.generation,
770 package_id: None,
771 workspace_root: self.root.clone(),
772 diagnostic,
773 });
774 }
775 FlycheckScope::Package { package: flycheck_package, .. } => {
776 if self.diagnostics_received == DiagnosticsReceived::NotYet {
777 self.diagnostics_received = DiagnosticsReceived::AtLeastOne;
778 }
779
780 // If the package has been set in the diagnostic JSON, respect that. Otherwise, use the
781 // package that the current flycheck is scoped to. This is useful when a project is
782 // directly using rustc for its checks (e.g. custom check commands in rust-project.json).
783 let package_id = package_id.unwrap_or(flycheck_package.clone());
784
785 if self.diagnostics_cleared_for.insert(package_id.clone()) {
786 tracing::trace!(
787 flycheck_id = self.id,
788 package_id = package_id.as_str(),
789 "clearing diagnostics"
790 );
791 self.send(FlycheckMessage::ClearDiagnostics {
792 id: self.id,
793 kind: ClearDiagnosticsKind::All(ClearScope::Package(
794 package_id.clone(),
795 )),
796 });
797 }
798
799 self.send(FlycheckMessage::AddDiagnostic {
746 if self.diagnostics_received == DiagnosticsReceived::NotYet {
747 self.diagnostics_received = DiagnosticsReceived::AtLeastOne;
748 }
749 if let Some(package_id) = &package_id {
750 if self.diagnostics_cleared_for.insert(package_id.clone()) {
751 tracing::trace!(
752 flycheck_id = self.id,
753 package_id = package_id.as_str(),
754 "clearing diagnostics"
755 );
756 self.send(FlycheckMessage::ClearDiagnostics {
800757 id: self.id,
801 generation: self.generation,
802 package_id: Some(package_id),
803 workspace_root: self.root.clone(),
804 diagnostic,
758 kind: ClearDiagnosticsKind::All(ClearScope::Package(
759 package_id.clone(),
760 )),
805761 });
806762 }
763 } else if self.diagnostics_received
764 != DiagnosticsReceived::AtLeastOneAndClearedWorkspace
765 {
766 self.diagnostics_received =
767 DiagnosticsReceived::AtLeastOneAndClearedWorkspace;
768 self.send(FlycheckMessage::ClearDiagnostics {
769 id: self.id,
770 kind: ClearDiagnosticsKind::All(ClearScope::Workspace),
771 });
807772 }
773 self.send(FlycheckMessage::AddDiagnostic {
774 id: self.id,
775 generation: self.generation,
776 package_id,
777 workspace_root: self.root.clone(),
778 diagnostic,
779 });
808780 }
809781 },
810782 }
src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs+1-7
......@@ -14,7 +14,7 @@ use hir::ChangeWithProcMacros;
1414use ide::{Analysis, AnalysisHost, Cancellable, FileId, SourceRootId};
1515use ide_db::{
1616 MiniCore,
17 base_db::{Crate, ProcMacroPaths, SourceDatabase, salsa::CancellationToken, salsa::Revision},
17 base_db::{Crate, ProcMacroPaths, SourceDatabase, salsa::Revision},
1818};
1919use itertools::Itertools;
2020use load_cargo::SourceRootConfig;
......@@ -88,7 +88,6 @@ pub(crate) struct GlobalState {
8888 pub(crate) task_pool: Handle<TaskPool<Task>, Receiver<Task>>,
8989 pub(crate) fmt_pool: Handle<TaskPool<Task>, Receiver<Task>>,
9090 pub(crate) cancellation_pool: thread::Pool,
91 pub(crate) cancellation_tokens: FxHashMap<lsp_server::RequestId, CancellationToken>,
9291
9392 pub(crate) config: Arc<Config>,
9493 pub(crate) config_errors: Option<ConfigErrors>,
......@@ -266,7 +265,6 @@ impl GlobalState {
266265 task_pool,
267266 fmt_pool,
268267 cancellation_pool,
269 cancellation_tokens: Default::default(),
270268 loader,
271269 config: Arc::new(config.clone()),
272270 analysis_host,
......@@ -619,7 +617,6 @@ impl GlobalState {
619617 }
620618
621619 pub(crate) fn respond(&mut self, response: lsp_server::Response) {
622 self.cancellation_tokens.remove(&response.id);
623620 if let Some((method, start)) = self.req_queue.incoming.complete(&response.id) {
624621 if let Some(err) = &response.error
625622 && err.message.starts_with("server panicked")
......@@ -634,9 +631,6 @@ impl GlobalState {
634631 }
635632
636633 pub(crate) fn cancel(&mut self, request_id: lsp_server::RequestId) {
637 if let Some(token) = self.cancellation_tokens.remove(&request_id) {
638 token.cancel();
639 }
640634 if let Some(response) = self.req_queue.incoming.cancel(request_id) {
641635 self.send(response.into());
642636 }
src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/dispatch.rs+1-16
......@@ -253,9 +253,6 @@ impl RequestDispatcher<'_> {
253253 tracing::debug!(?params);
254254
255255 let world = self.global_state.snapshot();
256 self.global_state
257 .cancellation_tokens
258 .insert(req.id.clone(), world.analysis.cancellation_token());
259256 if RUSTFMT {
260257 &mut self.global_state.fmt_pool.handle
261258 } else {
......@@ -268,19 +265,7 @@ impl RequestDispatcher<'_> {
268265 });
269266 match thread_result_to_response::<R>(req.id.clone(), result) {
270267 Ok(response) => Task::Response(response),
271 Err(HandlerCancelledError::Inner(
272 Cancelled::PendingWrite | Cancelled::PropagatedPanic,
273 )) if ALLOW_RETRYING => Task::Retry(req),
274 // Note: Technically the return value here does not matter as we have already responded to the client with this error.
275 Err(HandlerCancelledError::Inner(Cancelled::Local)) => Task::Response(Response {
276 id: req.id,
277 result: None,
278 error: Some(ResponseError {
279 code: lsp_server::ErrorCode::RequestCanceled as i32,
280 message: "canceled by client".to_owned(),
281 data: None,
282 }),
283 }),
268 Err(_cancelled) if ALLOW_RETRYING => Task::Retry(req),
284269 Err(_cancelled) => {
285270 let error = on_cancelled();
286271 Task::Response(Response { id: req.id, result: None, error: Some(error) })
src/tools/rust-analyzer/crates/span/src/ast_id.rs-2
......@@ -88,7 +88,6 @@ impl fmt::Debug for ErasedFileAstId {
8888 Module,
8989 Static,
9090 Trait,
91 TraitAlias,
9291 Variant,
9392 Const,
9493 Fn,
......@@ -129,7 +128,6 @@ enum ErasedFileAstIdKind {
129128 Module,
130129 Static,
131130 Trait,
132 TraitAlias,
133131 // Until here associated with `ErasedHasNameFileAstId`.
134132 // The following are associated with `ErasedAssocItemFileAstId`.
135133 Variant,
src/tools/rust-analyzer/crates/span/src/hygiene.rs+26-25
......@@ -81,24 +81,25 @@ const _: () = {
8181 #[derive(Hash)]
8282 struct StructKey<'db, T0, T1, T2, T3>(T0, T1, T2, T3, std::marker::PhantomData<&'db ()>);
8383
84 impl<'db, T0, T1, T2, T3> zalsa_::HashEqLike<StructKey<'db, T0, T1, T2, T3>> for SyntaxContextData
84 impl<'db, T0, T1, T2, T3> zalsa_::interned::HashEqLike<StructKey<'db, T0, T1, T2, T3>>
85 for SyntaxContextData
8586 where
86 Option<MacroCallId>: zalsa_::HashEqLike<T0>,
87 Transparency: zalsa_::HashEqLike<T1>,
88 Edition: zalsa_::HashEqLike<T2>,
89 SyntaxContext: zalsa_::HashEqLike<T3>,
87 Option<MacroCallId>: zalsa_::interned::HashEqLike<T0>,
88 Transparency: zalsa_::interned::HashEqLike<T1>,
89 Edition: zalsa_::interned::HashEqLike<T2>,
90 SyntaxContext: zalsa_::interned::HashEqLike<T3>,
9091 {
9192 fn hash<H: std::hash::Hasher>(&self, h: &mut H) {
92 zalsa_::HashEqLike::<T0>::hash(&self.outer_expn, &mut *h);
93 zalsa_::HashEqLike::<T1>::hash(&self.outer_transparency, &mut *h);
94 zalsa_::HashEqLike::<T2>::hash(&self.edition, &mut *h);
95 zalsa_::HashEqLike::<T3>::hash(&self.parent, &mut *h);
93 zalsa_::interned::HashEqLike::<T0>::hash(&self.outer_expn, &mut *h);
94 zalsa_::interned::HashEqLike::<T1>::hash(&self.outer_transparency, &mut *h);
95 zalsa_::interned::HashEqLike::<T2>::hash(&self.edition, &mut *h);
96 zalsa_::interned::HashEqLike::<T3>::hash(&self.parent, &mut *h);
9697 }
9798 fn eq(&self, data: &StructKey<'db, T0, T1, T2, T3>) -> bool {
98 zalsa_::HashEqLike::<T0>::eq(&self.outer_expn, &data.0)
99 && zalsa_::HashEqLike::<T1>::eq(&self.outer_transparency, &data.1)
100 && zalsa_::HashEqLike::<T2>::eq(&self.edition, &data.2)
101 && zalsa_::HashEqLike::<T3>::eq(&self.parent, &data.3)
99 zalsa_::interned::HashEqLike::<T0>::eq(&self.outer_expn, &data.0)
100 && zalsa_::interned::HashEqLike::<T1>::eq(&self.outer_transparency, &data.1)
101 && zalsa_::interned::HashEqLike::<T2>::eq(&self.edition, &data.2)
102 && zalsa_::interned::HashEqLike::<T3>::eq(&self.parent, &data.3)
102103 }
103104 }
104105 impl zalsa_struct_::Configuration for SyntaxContext {
......@@ -202,10 +203,10 @@ const _: () = {
202203 impl<'db> SyntaxContext {
203204 pub fn new<
204205 Db,
205 T0: zalsa_::Lookup<Option<MacroCallId>> + std::hash::Hash,
206 T1: zalsa_::Lookup<Transparency> + std::hash::Hash,
207 T2: zalsa_::Lookup<Edition> + std::hash::Hash,
208 T3: zalsa_::Lookup<SyntaxContext> + std::hash::Hash,
206 T0: zalsa_::interned::Lookup<Option<MacroCallId>> + std::hash::Hash,
207 T1: zalsa_::interned::Lookup<Transparency> + std::hash::Hash,
208 T2: zalsa_::interned::Lookup<Edition> + std::hash::Hash,
209 T3: zalsa_::interned::Lookup<SyntaxContext> + std::hash::Hash,
209210 >(
210211 db: &'db Db,
211212 outer_expn: T0,
......@@ -217,10 +218,10 @@ const _: () = {
217218 ) -> Self
218219 where
219220 Db: ?Sized + salsa::Database,
220 Option<MacroCallId>: zalsa_::HashEqLike<T0>,
221 Transparency: zalsa_::HashEqLike<T1>,
222 Edition: zalsa_::HashEqLike<T2>,
223 SyntaxContext: zalsa_::HashEqLike<T3>,
221 Option<MacroCallId>: zalsa_::interned::HashEqLike<T0>,
222 Transparency: zalsa_::interned::HashEqLike<T1>,
223 Edition: zalsa_::interned::HashEqLike<T2>,
224 SyntaxContext: zalsa_::interned::HashEqLike<T3>,
224225 {
225226 let (zalsa, zalsa_local) = db.zalsas();
226227
......@@ -235,10 +236,10 @@ const _: () = {
235236 std::marker::PhantomData,
236237 ),
237238 |id, data| SyntaxContextData {
238 outer_expn: zalsa_::Lookup::into_owned(data.0),
239 outer_transparency: zalsa_::Lookup::into_owned(data.1),
240 edition: zalsa_::Lookup::into_owned(data.2),
241 parent: zalsa_::Lookup::into_owned(data.3),
239 outer_expn: zalsa_::interned::Lookup::into_owned(data.0),
240 outer_transparency: zalsa_::interned::Lookup::into_owned(data.1),
241 edition: zalsa_::interned::Lookup::into_owned(data.2),
242 parent: zalsa_::interned::Lookup::into_owned(data.3),
242243 opaque: opaque(zalsa_::FromId::from_id(id)),
243244 opaque_and_semiopaque: opaque_and_semiopaque(zalsa_::FromId::from_id(id)),
244245 },
src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs+112-61
......@@ -9,8 +9,9 @@ use crate::{
99 SyntaxKind::{ATTR, COMMENT, WHITESPACE},
1010 SyntaxNode, SyntaxToken,
1111 algo::{self, neighbor},
12 ast::{self, HasGenericParams, edit::IndentLevel, make},
13 ted::{self, Position},
12 ast::{self, HasGenericParams, edit::IndentLevel, make, syntax_factory::SyntaxFactory},
13 syntax_editor::{Position, SyntaxEditor},
14 ted,
1415};
1516
1617use super::{GenericParam, HasName};
......@@ -26,13 +27,13 @@ impl GenericParamsOwnerEdit for ast::Fn {
2627 Some(it) => it,
2728 None => {
2829 let position = if let Some(name) = self.name() {
29 Position::after(name.syntax)
30 ted::Position::after(name.syntax)
3031 } else if let Some(fn_token) = self.fn_token() {
31 Position::after(fn_token)
32 ted::Position::after(fn_token)
3233 } else if let Some(param_list) = self.param_list() {
33 Position::before(param_list.syntax)
34 ted::Position::before(param_list.syntax)
3435 } else {
35 Position::last_child_of(self.syntax())
36 ted::Position::last_child_of(self.syntax())
3637 };
3738 create_generic_param_list(position)
3839 }
......@@ -42,11 +43,11 @@ impl GenericParamsOwnerEdit for ast::Fn {
4243 fn get_or_create_where_clause(&self) -> ast::WhereClause {
4344 if self.where_clause().is_none() {
4445 let position = if let Some(ty) = self.ret_type() {
45 Position::after(ty.syntax())
46 ted::Position::after(ty.syntax())
4647 } else if let Some(param_list) = self.param_list() {
47 Position::after(param_list.syntax())
48 ted::Position::after(param_list.syntax())
4849 } else {
49 Position::last_child_of(self.syntax())
50 ted::Position::last_child_of(self.syntax())
5051 };
5152 create_where_clause(position);
5253 }
......@@ -60,8 +61,8 @@ impl GenericParamsOwnerEdit for ast::Impl {
6061 Some(it) => it,
6162 None => {
6263 let position = match self.impl_token() {
63 Some(imp_token) => Position::after(imp_token),
64 None => Position::last_child_of(self.syntax()),
64 Some(imp_token) => ted::Position::after(imp_token),
65 None => ted::Position::last_child_of(self.syntax()),
6566 };
6667 create_generic_param_list(position)
6768 }
......@@ -71,8 +72,8 @@ impl GenericParamsOwnerEdit for ast::Impl {
7172 fn get_or_create_where_clause(&self) -> ast::WhereClause {
7273 if self.where_clause().is_none() {
7374 let position = match self.assoc_item_list() {
74 Some(items) => Position::before(items.syntax()),
75 None => Position::last_child_of(self.syntax()),
75 Some(items) => ted::Position::before(items.syntax()),
76 None => ted::Position::last_child_of(self.syntax()),
7677 };
7778 create_where_clause(position);
7879 }
......@@ -86,11 +87,11 @@ impl GenericParamsOwnerEdit for ast::Trait {
8687 Some(it) => it,
8788 None => {
8889 let position = if let Some(name) = self.name() {
89 Position::after(name.syntax)
90 ted::Position::after(name.syntax)
9091 } else if let Some(trait_token) = self.trait_token() {
91 Position::after(trait_token)
92 ted::Position::after(trait_token)
9293 } else {
93 Position::last_child_of(self.syntax())
94 ted::Position::last_child_of(self.syntax())
9495 };
9596 create_generic_param_list(position)
9697 }
......@@ -100,9 +101,9 @@ impl GenericParamsOwnerEdit for ast::Trait {
100101 fn get_or_create_where_clause(&self) -> ast::WhereClause {
101102 if self.where_clause().is_none() {
102103 let position = match (self.assoc_item_list(), self.semicolon_token()) {
103 (Some(items), _) => Position::before(items.syntax()),
104 (_, Some(tok)) => Position::before(tok),
105 (None, None) => Position::last_child_of(self.syntax()),
104 (Some(items), _) => ted::Position::before(items.syntax()),
105 (_, Some(tok)) => ted::Position::before(tok),
106 (None, None) => ted::Position::last_child_of(self.syntax()),
106107 };
107108 create_where_clause(position);
108109 }
......@@ -116,11 +117,11 @@ impl GenericParamsOwnerEdit for ast::TypeAlias {
116117 Some(it) => it,
117118 None => {
118119 let position = if let Some(name) = self.name() {
119 Position::after(name.syntax)
120 ted::Position::after(name.syntax)
120121 } else if let Some(trait_token) = self.type_token() {
121 Position::after(trait_token)
122 ted::Position::after(trait_token)
122123 } else {
123 Position::last_child_of(self.syntax())
124 ted::Position::last_child_of(self.syntax())
124125 };
125126 create_generic_param_list(position)
126127 }
......@@ -130,10 +131,10 @@ impl GenericParamsOwnerEdit for ast::TypeAlias {
130131 fn get_or_create_where_clause(&self) -> ast::WhereClause {
131132 if self.where_clause().is_none() {
132133 let position = match self.eq_token() {
133 Some(tok) => Position::before(tok),
134 Some(tok) => ted::Position::before(tok),
134135 None => match self.semicolon_token() {
135 Some(tok) => Position::before(tok),
136 None => Position::last_child_of(self.syntax()),
136 Some(tok) => ted::Position::before(tok),
137 None => ted::Position::last_child_of(self.syntax()),
137138 },
138139 };
139140 create_where_clause(position);
......@@ -148,11 +149,11 @@ impl GenericParamsOwnerEdit for ast::Struct {
148149 Some(it) => it,
149150 None => {
150151 let position = if let Some(name) = self.name() {
151 Position::after(name.syntax)
152 ted::Position::after(name.syntax)
152153 } else if let Some(struct_token) = self.struct_token() {
153 Position::after(struct_token)
154 ted::Position::after(struct_token)
154155 } else {
155 Position::last_child_of(self.syntax())
156 ted::Position::last_child_of(self.syntax())
156157 };
157158 create_generic_param_list(position)
158159 }
......@@ -166,13 +167,13 @@ impl GenericParamsOwnerEdit for ast::Struct {
166167 ast::FieldList::TupleFieldList(it) => Some(it),
167168 });
168169 let position = if let Some(tfl) = tfl {
169 Position::after(tfl.syntax())
170 ted::Position::after(tfl.syntax())
170171 } else if let Some(gpl) = self.generic_param_list() {
171 Position::after(gpl.syntax())
172 ted::Position::after(gpl.syntax())
172173 } else if let Some(name) = self.name() {
173 Position::after(name.syntax())
174 ted::Position::after(name.syntax())
174175 } else {
175 Position::last_child_of(self.syntax())
176 ted::Position::last_child_of(self.syntax())
176177 };
177178 create_where_clause(position);
178179 }
......@@ -186,11 +187,11 @@ impl GenericParamsOwnerEdit for ast::Enum {
186187 Some(it) => it,
187188 None => {
188189 let position = if let Some(name) = self.name() {
189 Position::after(name.syntax)
190 ted::Position::after(name.syntax)
190191 } else if let Some(enum_token) = self.enum_token() {
191 Position::after(enum_token)
192 ted::Position::after(enum_token)
192193 } else {
193 Position::last_child_of(self.syntax())
194 ted::Position::last_child_of(self.syntax())
194195 };
195196 create_generic_param_list(position)
196197 }
......@@ -200,11 +201,11 @@ impl GenericParamsOwnerEdit for ast::Enum {
200201 fn get_or_create_where_clause(&self) -> ast::WhereClause {
201202 if self.where_clause().is_none() {
202203 let position = if let Some(gpl) = self.generic_param_list() {
203 Position::after(gpl.syntax())
204 ted::Position::after(gpl.syntax())
204205 } else if let Some(name) = self.name() {
205 Position::after(name.syntax())
206 ted::Position::after(name.syntax())
206207 } else {
207 Position::last_child_of(self.syntax())
208 ted::Position::last_child_of(self.syntax())
208209 };
209210 create_where_clause(position);
210211 }
......@@ -212,12 +213,12 @@ impl GenericParamsOwnerEdit for ast::Enum {
212213 }
213214}
214215
215fn create_where_clause(position: Position) {
216fn create_where_clause(position: ted::Position) {
216217 let where_clause = make::where_clause(empty()).clone_for_update();
217218 ted::insert(position, where_clause.syntax());
218219}
219220
220fn create_generic_param_list(position: Position) -> ast::GenericParamList {
221fn create_generic_param_list(position: ted::Position) -> ast::GenericParamList {
221222 let gpl = make::generic_param_list(empty()).clone_for_update();
222223 ted::insert_raw(position, gpl.syntax());
223224 gpl
......@@ -253,7 +254,7 @@ impl ast::GenericParamList {
253254 pub fn add_generic_param(&self, generic_param: ast::GenericParam) {
254255 match self.generic_params().last() {
255256 Some(last_param) => {
256 let position = Position::after(last_param.syntax());
257 let position = ted::Position::after(last_param.syntax());
257258 let elements = vec![
258259 make::token(T![,]).into(),
259260 make::tokens::single_space().into(),
......@@ -262,7 +263,7 @@ impl ast::GenericParamList {
262263 ted::insert_all(position, elements);
263264 }
264265 None => {
265 let after_l_angle = Position::after(self.l_angle_token().unwrap());
266 let after_l_angle = ted::Position::after(self.l_angle_token().unwrap());
266267 ted::insert(after_l_angle, generic_param.syntax());
267268 }
268269 }
......@@ -412,7 +413,7 @@ impl ast::UseTree {
412413 match self.use_tree_list() {
413414 Some(it) => it,
414415 None => {
415 let position = Position::last_child_of(self.syntax());
416 let position = ted::Position::last_child_of(self.syntax());
416417 let use_tree_list = make::use_tree_list(empty()).clone_for_update();
417418 let mut elements = Vec::with_capacity(2);
418419 if self.coloncolon_token().is_none() {
......@@ -458,7 +459,7 @@ impl ast::UseTree {
458459 // Next, transform 'suffix' use tree into 'prefix::{suffix}'
459460 let subtree = self.clone_subtree().clone_for_update();
460461 ted::remove_all_iter(self.syntax().children_with_tokens());
461 ted::insert(Position::first_child_of(self.syntax()), prefix.syntax());
462 ted::insert(ted::Position::first_child_of(self.syntax()), prefix.syntax());
462463 self.get_or_create_use_tree_list().add_use_tree(subtree);
463464
464465 fn split_path_prefix(prefix: &ast::Path) -> Option<()> {
......@@ -507,7 +508,7 @@ impl ast::UseTreeList {
507508 pub fn add_use_tree(&self, use_tree: ast::UseTree) {
508509 let (position, elements) = match self.use_trees().last() {
509510 Some(last_tree) => (
510 Position::after(last_tree.syntax()),
511 ted::Position::after(last_tree.syntax()),
511512 vec![
512513 make::token(T![,]).into(),
513514 make::tokens::single_space().into(),
......@@ -516,8 +517,8 @@ impl ast::UseTreeList {
516517 ),
517518 None => {
518519 let position = match self.l_curly_token() {
519 Some(l_curly) => Position::after(l_curly),
520 None => Position::last_child_of(self.syntax()),
520 Some(l_curly) => ted::Position::after(l_curly),
521 None => ted::Position::last_child_of(self.syntax()),
521522 };
522523 (position, vec![use_tree.syntax.into()])
523524 }
......@@ -582,15 +583,15 @@ impl ast::AssocItemList {
582583 let (indent, position, whitespace) = match self.assoc_items().last() {
583584 Some(last_item) => (
584585 IndentLevel::from_node(last_item.syntax()),
585 Position::after(last_item.syntax()),
586 ted::Position::after(last_item.syntax()),
586587 "\n\n",
587588 ),
588589 None => match self.l_curly_token() {
589590 Some(l_curly) => {
590591 normalize_ws_between_braces(self.syntax());
591 (IndentLevel::from_token(&l_curly) + 1, Position::after(&l_curly), "\n")
592 (IndentLevel::from_token(&l_curly) + 1, ted::Position::after(&l_curly), "\n")
592593 }
593 None => (IndentLevel::single(), Position::last_child_of(self.syntax()), "\n"),
594 None => (IndentLevel::single(), ted::Position::last_child_of(self.syntax()), "\n"),
594595 },
595596 };
596597 let elements: Vec<SyntaxElement> = vec![
......@@ -618,17 +619,17 @@ impl ast::RecordExprFieldList {
618619 let position = match self.fields().last() {
619620 Some(last_field) => {
620621 let comma = get_or_insert_comma_after(last_field.syntax());
621 Position::after(comma)
622 ted::Position::after(comma)
622623 }
623624 None => match self.l_curly_token() {
624 Some(it) => Position::after(it),
625 None => Position::last_child_of(self.syntax()),
625 Some(it) => ted::Position::after(it),
626 None => ted::Position::last_child_of(self.syntax()),
626627 },
627628 };
628629
629630 ted::insert_all(position, vec![whitespace.into(), field.syntax().clone().into()]);
630631 if is_multiline {
631 ted::insert(Position::after(field.syntax()), ast::make::token(T![,]));
632 ted::insert(ted::Position::after(field.syntax()), ast::make::token(T![,]));
632633 }
633634 }
634635}
......@@ -656,7 +657,7 @@ impl ast::RecordExprField {
656657 ast::make::tokens::single_space().into(),
657658 expr.syntax().clone().into(),
658659 ];
659 ted::insert_all_raw(Position::last_child_of(self.syntax()), children);
660 ted::insert_all_raw(ted::Position::last_child_of(self.syntax()), children);
660661 }
661662 }
662663}
......@@ -679,17 +680,17 @@ impl ast::RecordPatFieldList {
679680 Some(last_field) => {
680681 let syntax = last_field.syntax();
681682 let comma = get_or_insert_comma_after(syntax);
682 Position::after(comma)
683 ted::Position::after(comma)
683684 }
684685 None => match self.l_curly_token() {
685 Some(it) => Position::after(it),
686 None => Position::last_child_of(self.syntax()),
686 Some(it) => ted::Position::after(it),
687 None => ted::Position::last_child_of(self.syntax()),
687688 },
688689 };
689690
690691 ted::insert_all(position, vec![whitespace.into(), field.syntax().clone().into()]);
691692 if is_multiline {
692 ted::insert(Position::after(field.syntax()), ast::make::token(T![,]));
693 ted::insert(ted::Position::after(field.syntax()), ast::make::token(T![,]));
693694 }
694695 }
695696}
......@@ -703,7 +704,7 @@ fn get_or_insert_comma_after(syntax: &SyntaxNode) -> SyntaxToken {
703704 Some(it) => it,
704705 None => {
705706 let comma = ast::make::token(T![,]);
706 ted::insert(Position::after(syntax), &comma);
707 ted::insert(ted::Position::after(syntax), &comma);
707708 comma
708709 }
709710 }
......@@ -728,7 +729,7 @@ fn normalize_ws_between_braces(node: &SyntaxNode) -> Option<()> {
728729 }
729730 }
730731 Some(ws) if ws.kind() == T!['}'] => {
731 ted::insert(Position::after(l), make::tokens::whitespace(&format!("\n{indent}")));
732 ted::insert(ted::Position::after(l), make::tokens::whitespace(&format!("\n{indent}")));
732733 }
733734 _ => (),
734735 }
......@@ -780,6 +781,56 @@ impl ast::IdentPat {
780781 }
781782 }
782783 }
784
785 pub fn set_pat_with_editor(
786 &self,
787 pat: Option<ast::Pat>,
788 syntax_editor: &mut SyntaxEditor,
789 syntax_factory: &SyntaxFactory,
790 ) {
791 match pat {
792 None => {
793 if let Some(at_token) = self.at_token() {
794 // Remove `@ Pat`
795 let start = at_token.clone().into();
796 let end = self
797 .pat()
798 .map(|it| it.syntax().clone().into())
799 .unwrap_or_else(|| at_token.into());
800 syntax_editor.delete_all(start..=end);
801
802 // Remove any trailing ws
803 if let Some(last) =
804 self.syntax().last_token().filter(|it| it.kind() == WHITESPACE)
805 {
806 last.detach();
807 }
808 }
809 }
810 Some(pat) => {
811 if let Some(old_pat) = self.pat() {
812 // Replace existing pattern
813 syntax_editor.replace(old_pat.syntax(), pat.syntax())
814 } else if let Some(at_token) = self.at_token() {
815 // Have an `@` token but not a pattern yet
816 syntax_editor.insert(Position::after(at_token), pat.syntax());
817 } else {
818 // Don't have an `@`, should have a name
819 let name = self.name().unwrap();
820
821 syntax_editor.insert_all(
822 Position::after(name.syntax()),
823 vec![
824 syntax_factory.whitespace(" ").into(),
825 syntax_factory.token(T![@]).into(),
826 syntax_factory.whitespace(" ").into(),
827 pat.syntax().clone().into(),
828 ],
829 )
830 }
831 }
832 }
833 }
783834}
784835
785836pub trait HasVisibilityEdit: ast::HasVisibility {
src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs+77
......@@ -75,6 +75,24 @@ impl SyntaxFactory {
7575 make::path_from_text(text).clone_for_update()
7676 }
7777
78 pub fn path_concat(&self, first: ast::Path, second: ast::Path) -> ast::Path {
79 make::path_concat(first, second).clone_for_update()
80 }
81
82 pub fn visibility_pub(&self) -> ast::Visibility {
83 make::visibility_pub()
84 }
85
86 pub fn struct_(
87 &self,
88 visibility: Option<ast::Visibility>,
89 strukt_name: ast::Name,
90 generic_param_list: Option<ast::GenericParamList>,
91 field_list: ast::FieldList,
92 ) -> ast::Struct {
93 make::struct_(visibility, strukt_name, generic_param_list, field_list).clone_for_update()
94 }
95
7896 pub fn expr_field(&self, receiver: ast::Expr, field: &str) -> ast::FieldExpr {
7997 let ast::Expr::FieldExpr(ast) =
8098 make::expr_field(receiver.clone(), field).clone_for_update()
......@@ -1590,6 +1608,65 @@ impl SyntaxFactory {
15901608 ast
15911609 }
15921610
1611 pub fn self_param(&self) -> ast::SelfParam {
1612 let ast = make::self_param().clone_for_update();
1613
1614 if let Some(mut mapping) = self.mappings() {
1615 let builder = SyntaxMappingBuilder::new(ast.syntax().clone());
1616 builder.finish(&mut mapping);
1617 }
1618
1619 ast
1620 }
1621
1622 pub fn impl_(
1623 &self,
1624 attrs: impl IntoIterator<Item = ast::Attr>,
1625 generic_params: Option<ast::GenericParamList>,
1626 generic_args: Option<ast::GenericArgList>,
1627 path_type: ast::Type,
1628 where_clause: Option<ast::WhereClause>,
1629 body: Option<ast::AssocItemList>,
1630 ) -> ast::Impl {
1631 let (attrs, attrs_input) = iterator_input(attrs);
1632 let ast = make::impl_(
1633 attrs,
1634 generic_params.clone(),
1635 generic_args.clone(),
1636 path_type.clone(),
1637 where_clause.clone(),
1638 body.clone(),
1639 )
1640 .clone_for_update();
1641
1642 if let Some(mut mapping) = self.mappings() {
1643 let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
1644 builder.map_children(attrs_input, ast.attrs().map(|attr| attr.syntax().clone()));
1645 if let Some(generic_params) = generic_params {
1646 builder.map_node(
1647 generic_params.syntax().clone(),
1648 ast.generic_param_list().unwrap().syntax().clone(),
1649 );
1650 }
1651 builder.map_node(path_type.syntax().clone(), ast.self_ty().unwrap().syntax().clone());
1652 if let Some(where_clause) = where_clause {
1653 builder.map_node(
1654 where_clause.syntax().clone(),
1655 ast.where_clause().unwrap().syntax().clone(),
1656 );
1657 }
1658 if let Some(body) = body {
1659 builder.map_node(
1660 body.syntax().clone(),
1661 ast.assoc_item_list().unwrap().syntax().clone(),
1662 );
1663 }
1664 builder.finish(&mut mapping);
1665 }
1666
1667 ast
1668 }
1669
15931670 pub fn ret_type(&self, ty: ast::Type) -> ast::RetType {
15941671 let ast = make::ret_type(ty.clone()).clone_for_update();
15951672
src/tools/rust-analyzer/crates/test-utils/src/minicore.rs+23-1
......@@ -1689,6 +1689,21 @@ pub mod iter {
16891689 }
16901690 }
16911691
1692 pub struct Filter<I, P> {
1693 iter: I,
1694 predicate: P,
1695 }
1696 impl<I: Iterator, P> Iterator for Filter<I, P>
1697 where
1698 P: FnMut(&I::Item) -> bool,
1699 {
1700 type Item = I::Item;
1701
1702 fn next(&mut self) -> Option<I::Item> {
1703 loop {}
1704 }
1705 }
1706
16921707 pub struct FilterMap<I, F> {
16931708 iter: I,
16941709 f: F,
......@@ -1705,7 +1720,7 @@ pub mod iter {
17051720 }
17061721 }
17071722 }
1708 pub use self::adapters::{FilterMap, Take};
1723 pub use self::adapters::{Filter, FilterMap, Take};
17091724
17101725 mod sources {
17111726 mod repeat {
......@@ -1756,6 +1771,13 @@ pub mod iter {
17561771 {
17571772 loop {}
17581773 }
1774 fn filter<P>(self, predicate: P) -> crate::iter::Filter<Self, P>
1775 where
1776 Self: Sized,
1777 P: FnMut(&Self::Item) -> bool,
1778 {
1779 loop {}
1780 }
17591781 fn filter_map<B, F>(self, _f: F) -> crate::iter::FilterMap<Self, F>
17601782 where
17611783 Self: Sized,
src/tools/rust-analyzer/crates/tt/src/storage.rs+1-1
......@@ -488,7 +488,7 @@ impl TopSubtree {
488488 unreachable!()
489489 };
490490 *open_span = S::new(span.open.range, 0);
491 *close_span = S::new(span.close.range, 0);
491 *close_span = S::new(span.close.range, 1);
492492 }
493493 dispatch! {
494494 match &mut self.repr => tt => do_it(tt, span)
src/tools/rust-analyzer/editors/code/package-lock.json+3-9
......@@ -1486,7 +1486,6 @@
14861486 "integrity": "sha512-4gbs64bnbSzu4FpgMiQ1A+D+urxkoJk/kqlDJ2W//5SygaEiAP2B4GoS7TEdxgwol2el03gckFV9lJ4QOMiiHg==",
14871487 "dev": true,
14881488 "license": "MIT",
1489 "peer": true,
14901489 "dependencies": {
14911490 "@typescript-eslint/scope-manager": "8.25.0",
14921491 "@typescript-eslint/types": "8.25.0",
......@@ -1870,7 +1869,6 @@
18701869 "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==",
18711870 "dev": true,
18721871 "license": "MIT",
1873 "peer": true,
18741872 "bin": {
18751873 "acorn": "bin/acorn"
18761874 },
......@@ -2840,7 +2838,6 @@
28402838 "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz",
28412839 "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==",
28422840 "license": "ISC",
2843 "peer": true,
28442841 "engines": {
28452842 "node": ">=12"
28462843 }
......@@ -3322,7 +3319,6 @@
33223319 "integrity": "sha512-KjeihdFqTPhOMXTt7StsDxriV4n66ueuF/jfPNC3j/lduHwr/ijDwJMsF+wyMJethgiKi5wniIE243vi07d3pg==",
33233320 "dev": true,
33243321 "license": "MIT",
3325 "peer": true,
33263322 "dependencies": {
33273323 "@eslint-community/eslint-utils": "^4.2.0",
33283324 "@eslint-community/regexpp": "^4.12.1",
......@@ -4410,7 +4406,6 @@
44104406 "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.4.2.tgz",
44114407 "integrity": "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==",
44124408 "license": "MIT",
4413 "peer": true,
44144409 "bin": {
44154410 "jiti": "lib/jiti-cli.mjs"
44164411 }
......@@ -5584,9 +5579,9 @@
55845579 }
55855580 },
55865581 "node_modules/qs": {
5587 "version": "6.14.1",
5588 "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.1.tgz",
5589 "integrity": "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==",
5582 "version": "6.14.2",
5583 "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.2.tgz",
5584 "integrity": "sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==",
55905585 "dev": true,
55915586 "license": "BSD-3-Clause",
55925587 "dependencies": {
......@@ -6678,7 +6673,6 @@
66786673 "integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==",
66796674 "dev": true,
66806675 "license": "Apache-2.0",
6681 "peer": true,
66826676 "bin": {
66836677 "tsc": "bin/tsc",
66846678 "tsserver": "bin/tsserver"
src/tools/rust-analyzer/lib/smol_str/src/borsh.rs+3-2
......@@ -29,8 +29,9 @@ impl BorshDeserialize for SmolStr {
2929 }))
3030 } else {
3131 // u8::vec_from_reader always returns Some on success in current implementation
32 let vec = u8::vec_from_reader(len, reader)?
33 .ok_or_else(|| Error::other("u8::vec_from_reader unexpectedly returned None"))?;
32 let vec = u8::vec_from_reader(len, reader)?.ok_or_else(|| {
33 Error::new(ErrorKind::Other, "u8::vec_from_reader unexpectedly returned None")
34 })?;
3435 Ok(SmolStr::from(String::from_utf8(vec).map_err(|err| {
3536 let msg = err.to_string();
3637 Error::new(ErrorKind::InvalidData, msg)
src/tools/rust-analyzer/lib/smol_str/tests/test.rs+1-1
......@@ -393,7 +393,7 @@ mod test_str_ext {
393393 }
394394}
395395
396#[cfg(feature = "borsh")]
396#[cfg(all(feature = "borsh", feature = "std"))]
397397mod borsh_tests {
398398 use borsh::BorshDeserialize;
399399 use smol_str::{SmolStr, ToSmolStr};
src/tools/rust-analyzer/rust-version+1-1
......@@ -1 +1 @@
1ba284f468cd2cda48420251efc991758ec13d450
1139651428df86cf88443295542c12ea617cbb587
src/tools/rustfmt/src/items.rs+6-6
......@@ -319,12 +319,13 @@ impl<'a> FnSig<'a> {
319319 method_sig: &'a ast::FnSig,
320320 generics: &'a ast::Generics,
321321 visibility: &'a ast::Visibility,
322 defaultness: ast::Defaultness,
322323 ) -> FnSig<'a> {
323324 FnSig {
324325 safety: method_sig.header.safety,
325326 coroutine_kind: Cow::Borrowed(&method_sig.header.coroutine_kind),
326327 constness: method_sig.header.constness,
327 defaultness: ast::Defaultness::Final,
328 defaultness,
328329 ext: method_sig.header.ext,
329330 decl: &*method_sig.decl,
330331 generics,
......@@ -339,9 +340,7 @@ impl<'a> FnSig<'a> {
339340 ) -> FnSig<'a> {
340341 match *fn_kind {
341342 visit::FnKind::Fn(visit::FnCtxt::Assoc(..), vis, ast::Fn { sig, generics, .. }) => {
342 let mut fn_sig = FnSig::from_method_sig(sig, generics, vis);
343 fn_sig.defaultness = defaultness;
344 fn_sig
343 FnSig::from_method_sig(sig, generics, vis, defaultness)
345344 }
346345 visit::FnKind::Fn(_, vis, ast::Fn { sig, generics, .. }) => FnSig {
347346 decl,
......@@ -459,6 +458,7 @@ impl<'a> FmtVisitor<'a> {
459458 sig: &ast::FnSig,
460459 vis: &ast::Visibility,
461460 generics: &ast::Generics,
461 defaultness: ast::Defaultness,
462462 span: Span,
463463 ) -> RewriteResult {
464464 // Drop semicolon or it will be interpreted as comment.
......@@ -469,7 +469,7 @@ impl<'a> FmtVisitor<'a> {
469469 &context,
470470 indent,
471471 ident,
472 &FnSig::from_method_sig(sig, generics, vis),
472 &FnSig::from_method_sig(sig, generics, vis, defaultness),
473473 span,
474474 FnBraceStyle::None,
475475 )?;
......@@ -3495,7 +3495,7 @@ impl Rewrite for ast::ForeignItem {
34953495 context,
34963496 shape.indent,
34973497 ident,
3498 &FnSig::from_method_sig(sig, generics, &self.vis),
3498 &FnSig::from_method_sig(sig, generics, &self.vis, defaultness),
34993499 span,
35003500 FnBraceStyle::None,
35013501 )
src/tools/rustfmt/src/utils.rs+2-1
......@@ -102,8 +102,9 @@ pub(crate) fn format_constness_right(constness: ast::Const) -> &'static str {
102102#[inline]
103103pub(crate) fn format_defaultness(defaultness: ast::Defaultness) -> &'static str {
104104 match defaultness {
105 ast::Defaultness::Implicit => "",
105106 ast::Defaultness::Default(..) => "default ",
106 ast::Defaultness::Final => "",
107 ast::Defaultness::Final(..) => "final ",
107108 }
108109}
109110
src/tools/rustfmt/src/visitor.rs+18-2
......@@ -583,7 +583,15 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
583583 } else {
584584 let indent = self.block_indent;
585585 let rewrite = self
586 .rewrite_required_fn(indent, ident, sig, &item.vis, generics, item.span)
586 .rewrite_required_fn(
587 indent,
588 ident,
589 sig,
590 &item.vis,
591 generics,
592 defaultness,
593 item.span,
594 )
587595 .ok();
588596 self.push_rewrite(item.span, rewrite);
589597 }
......@@ -686,7 +694,15 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
686694 } else {
687695 let indent = self.block_indent;
688696 let rewrite = self
689 .rewrite_required_fn(indent, fn_kind.ident, sig, &ai.vis, generics, ai.span)
697 .rewrite_required_fn(
698 indent,
699 fn_kind.ident,
700 sig,
701 &ai.vis,
702 generics,
703 defaultness,
704 ai.span,
705 )
690706 .ok();
691707 self.push_rewrite(ai.span, rewrite);
692708 }
src/tools/rustfmt/tests/target/final-kw.rs created+5
......@@ -0,0 +1,5 @@
1trait Foo {
2 final fn final_() {}
3
4 fn not_final() {}
5}
tests/run-make/short-ice/rmake.rs+3-3
......@@ -31,10 +31,10 @@ fn main() {
3131 let output_bt_full = &concat_stderr_stdout(&rustc_bt_full);
3232
3333 // Count how many lines of output mention symbols or paths in
34 // `rustc_query_system` or `rustc_query_impl`, which are the kinds of
34 // `rustc_query_impl`, which are the kinds of
3535 // stack frames we want to be omitting in short backtraces.
36 let rustc_query_count_short = count_lines_with(output_bt_short, "rustc_query_");
37 let rustc_query_count_full = count_lines_with(output_bt_full, "rustc_query_");
36 let rustc_query_count_short = count_lines_with(output_bt_short, "rustc_query_impl");
37 let rustc_query_count_full = count_lines_with(output_bt_full, "rustc_query_impl");
3838
3939 // Dump both outputs in full to make debugging easier, especially on CI.
4040 // Use `--no-capture --force-rerun` to view output even when the test is passing.
tests/rustdoc-html/final-trait-method.rs created+22
......@@ -0,0 +1,22 @@
1#![feature(final_associated_functions)]
2
3//@ has final_trait_method/trait.Item.html
4pub trait Item {
5 //@ has - '//*[@id="method.foo"]' 'final fn foo()'
6 //@ !has - '//*[@id="method.foo"]' 'default fn foo()'
7 final fn foo() {}
8
9 //@ has - '//*[@id="method.bar"]' 'fn bar()'
10 //@ !has - '//*[@id="method.bar"]' 'default fn bar()'
11 //@ !has - '//*[@id="method.bar"]' 'final fn bar()'
12 fn bar() {}
13}
14
15//@ has final_trait_method/struct.Foo.html
16pub struct Foo;
17impl Item for Foo {
18 //@ has - '//*[@id="method.bar"]' 'fn bar()'
19 //@ !has - '//*[@id="method.bar"]' 'final fn bar()'
20 //@ !has - '//*[@id="method.bar"]' 'default fn bar()'
21 fn bar() {}
22}
tests/ui-fulldeps/hash-stable-is-unstable.rs+1-1
......@@ -7,7 +7,7 @@ extern crate rustc_macros;
77//~^ ERROR use of unstable library feature `rustc_private`
88//~| NOTE: see issue #27812 <https://github.com/rust-lang/rust/issues/27812> for more information
99//~| NOTE: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
10extern crate rustc_query_system;
10extern crate rustc_middle;
1111//~^ ERROR use of unstable library feature `rustc_private`
1212//~| NOTE: see issue #27812 <https://github.com/rust-lang/rust/issues/27812> for more information
1313//~| NOTE: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
tests/ui-fulldeps/hash-stable-is-unstable.stderr+2-2
......@@ -21,8 +21,8 @@ LL | extern crate rustc_macros;
2121error[E0658]: use of unstable library feature `rustc_private`: 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?
2222 --> $DIR/hash-stable-is-unstable.rs:10:1
2323 |
24LL | extern crate rustc_query_system;
25 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
24LL | extern crate rustc_middle;
25 | ^^^^^^^^^^^^^^^^^^^^^^^^^^
2626 |
2727 = note: see issue #27812 <https://github.com/rust-lang/rust/issues/27812> for more information
2828 = help: add `#![feature(rustc_private)]` to the crate attributes to enable
tests/ui/coroutine/gen_fn.none.stderr+2-2
......@@ -1,8 +1,8 @@
1error: expected one of `#`, `async`, `const`, `default`, `extern`, `fn`, `pub`, `safe`, `unsafe`, or `use`, found `gen`
1error: expected one of `#`, `async`, `const`, `default`, `extern`, `final`, `fn`, `pub`, `safe`, `unsafe`, or `use`, found `gen`
22 --> $DIR/gen_fn.rs:4:1
33 |
44LL | gen fn foo() {}
5 | ^^^ expected one of 10 possible tokens
5 | ^^^ expected one of 11 possible tokens
66
77error: aborting due to 1 previous error
88
tests/ui/coroutine/gen_fn.rs+1-1
......@@ -2,7 +2,7 @@
22//@[e2024] edition: 2024
33
44gen fn foo() {}
5//[none]~^ ERROR: expected one of `#`, `async`, `const`, `default`, `extern`, `fn`, `pub`, `safe`, `unsafe`, or `use`, found `gen`
5//[none]~^ ERROR: expected one of `#`, `async`, `const`, `default`, `extern`, `final`, `fn`, `pub`, `safe`, `unsafe`, or `use`, found `gen`
66//[e2024]~^^ ERROR: gen blocks are experimental
77
88fn main() {}
tests/ui/feature-gates/feature-gate-final-associated-functions.rs created+6
......@@ -0,0 +1,6 @@
1trait Foo {
2 final fn bar() {}
3 //~^ ERROR `final` on trait functions is experimental
4}
5
6fn main() {}
tests/ui/feature-gates/feature-gate-final-associated-functions.stderr created+13
......@@ -0,0 +1,13 @@
1error[E0658]: `final` on trait functions is experimental
2 --> $DIR/feature-gate-final-associated-functions.rs:2:5
3 |
4LL | final fn bar() {}
5 | ^^^^^
6 |
7 = note: see issue #1 <https://github.com/rust-lang/rust/issues/1> for more information
8 = help: add `#![feature(final_associated_functions)]` to the crate attributes to enable
9 = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
10
11error: aborting due to 1 previous error
12
13For more information about this error, try `rustc --explain E0658`.
tests/ui/methods/call_method_unknown_pointee.rs+23-10
......@@ -3,26 +3,39 @@
33// tests that the pointee type of a raw pointer must be known to call methods on it
44// see also: `tests/ui/editions/edition-raw-pointer-method-2018.rs`
55
6fn main() {
7 let val = 1_u32;
8 let ptr = &val as *const u32;
6fn a() {
7 let ptr = &1u32 as *const u32;
98 unsafe {
109 let _a: i32 = (ptr as *const _).read();
1110 //~^ ERROR type annotations needed
11 }
12}
13
14fn b() {
15 let ptr = &1u32 as *const u32;
16 unsafe {
1217 let b = ptr as *const _;
1318 //~^ ERROR type annotations needed
1419 let _b: u8 = b.read();
15 let _c = (ptr as *const u8).read(); // we know the type here
1620 }
21}
22
1723
18 let mut val = 2_u32;
19 let ptr = &mut val as *mut u32;
24fn c() {
25 let ptr = &mut 2u32 as *mut u32;
2026 unsafe {
21 let _a: i32 = (ptr as *mut _).read();
27 let _c: i32 = (ptr as *mut _).read();
2228 //~^ ERROR type annotations needed
23 let b = ptr as *mut _;
29 }
30}
31
32fn d() {
33 let ptr = &mut 2u32 as *mut u32;
34 unsafe {
35 let d = ptr as *mut _;
2436 //~^ ERROR type annotations needed
25 b.write(10);
26 (ptr as *mut i32).write(1000); // we know the type here
37 let _d: u8 = d.read();
2738 }
2839}
40
41fn main() {}
tests/ui/methods/call_method_unknown_pointee.stderr+10-10
......@@ -1,5 +1,5 @@
11error[E0282]: type annotations needed
2 --> $DIR/call_method_unknown_pointee.rs:10:23
2 --> $DIR/call_method_unknown_pointee.rs:9:23
33 |
44LL | let _a: i32 = (ptr as *const _).read();
55 | ^^^^^^^^^^^^^^^^^ ---- cannot call a method on a raw pointer with an unknown pointee type
......@@ -7,7 +7,7 @@ LL | let _a: i32 = (ptr as *const _).read();
77 | cannot infer type
88
99error[E0282]: type annotations needed for `*const _`
10 --> $DIR/call_method_unknown_pointee.rs:12:13
10 --> $DIR/call_method_unknown_pointee.rs:17:13
1111 |
1212LL | let b = ptr as *const _;
1313 | ^
......@@ -21,25 +21,25 @@ LL | let b: *const _ = ptr as *const _;
2121 | ++++++++++
2222
2323error[E0282]: type annotations needed
24 --> $DIR/call_method_unknown_pointee.rs:21:23
24 --> $DIR/call_method_unknown_pointee.rs:27:23
2525 |
26LL | let _a: i32 = (ptr as *mut _).read();
26LL | let _c: i32 = (ptr as *mut _).read();
2727 | ^^^^^^^^^^^^^^^ ---- cannot call a method on a raw pointer with an unknown pointee type
2828 | |
2929 | cannot infer type
3030
3131error[E0282]: type annotations needed for `*mut _`
32 --> $DIR/call_method_unknown_pointee.rs:23:13
32 --> $DIR/call_method_unknown_pointee.rs:35:13
3333 |
34LL | let b = ptr as *mut _;
34LL | let d = ptr as *mut _;
3535 | ^
3636LL |
37LL | b.write(10);
38 | ----- cannot call a method on a raw pointer with an unknown pointee type
37LL | let _d: u8 = d.read();
38 | ---- cannot call a method on a raw pointer with an unknown pointee type
3939 |
40help: consider giving `b` an explicit type, where the placeholders `_` are specified
40help: consider giving `d` an explicit type, where the placeholders `_` are specified
4141 |
42LL | let b: *mut _ = ptr as *mut _;
42LL | let d: *mut _ = ptr as *mut _;
4343 | ++++++++
4444
4545error: aborting due to 4 previous errors
tests/ui/methods/call_method_unknown_referent.rs+10-6
......@@ -14,20 +14,22 @@ impl<T> SmartPtr<T> {
1414 fn foo(&self) {}
1515}
1616
17fn main() {
18 let val = 1_u32;
19 let ptr = &val;
17fn a() {
18 let ptr = &1u32;
2019 let _a: i32 = (ptr as &_).read();
2120 //~^ ERROR type annotations needed
21}
2222
23fn b() {
2324 // Same again, but with a smart pointer type
24 let val2 = 1_u32;
25 let rc = std::rc::Rc::new(val2);
25 let rc = std::rc::Rc::new(1u32);
2626 let _b = (rc as std::rc::Rc<_>).read();
2727 //~^ ERROR type annotations needed
28}
2829
30fn c() {
2931 // Same again, but with a smart pointer type
30 let ptr = SmartPtr(val);
32 let ptr = SmartPtr(1u32);
3133
3234 // We can call unambiguous outer-type methods on this
3335 (ptr as SmartPtr<_>).foo();
......@@ -46,3 +48,5 @@ fn main() {
4648 let _c = (ptr as SmartPtr<_>).read();
4749 //~^ ERROR no method named `read` found for struct `SmartPtr<T>`
4850}
51
52fn main() {}
tests/ui/methods/call_method_unknown_referent.stderr+2-2
......@@ -1,5 +1,5 @@
11error[E0282]: type annotations needed
2 --> $DIR/call_method_unknown_referent.rs:20:19
2 --> $DIR/call_method_unknown_referent.rs:19:19
33 |
44LL | let _a: i32 = (ptr as &_).read();
55 | ^^^^^^^^^^^ cannot infer type
......@@ -11,7 +11,7 @@ LL | let _b = (rc as std::rc::Rc<_>).read();
1111 | ^^^^^^^^^^^^^^^^^^^^^^ cannot infer type
1212
1313error[E0599]: no method named `read` found for struct `SmartPtr<T>` in the current scope
14 --> $DIR/call_method_unknown_referent.rs:46:35
14 --> $DIR/call_method_unknown_referent.rs:48:35
1515 |
1616LL | struct SmartPtr<T>(T);
1717 | ------------------ method `read` not found for this struct
tests/ui/parser/duplicate-visibility.rs+2-2
......@@ -2,8 +2,8 @@ fn main() {}
22
33extern "C" { //~ NOTE while parsing this item list starting here
44 pub pub fn foo();
5 //~^ ERROR expected one of `(`, `async`, `const`, `default`, `extern`, `fn`, `safe`, `unsafe`, or `use`, found keyword `pub`
6 //~| NOTE expected one of 9 possible tokens
5 //~^ ERROR expected one of `(`, `async`, `const`, `default`, `extern`, `final`, `fn`, `safe`, `unsafe`, or `use`, found keyword `pub`
6 //~| NOTE expected one of 10 possible tokens
77 //~| HELP there is already a visibility modifier, remove one
88 //~| NOTE explicit visibility first seen here
99} //~ NOTE the item list ends here
tests/ui/parser/duplicate-visibility.stderr+2-2
......@@ -1,4 +1,4 @@
1error: expected one of `(`, `async`, `const`, `default`, `extern`, `fn`, `safe`, `unsafe`, or `use`, found keyword `pub`
1error: expected one of `(`, `async`, `const`, `default`, `extern`, `final`, `fn`, `safe`, `unsafe`, or `use`, found keyword `pub`
22 --> $DIR/duplicate-visibility.rs:4:9
33 |
44LL | extern "C" {
......@@ -6,7 +6,7 @@ LL | extern "C" {
66LL | pub pub fn foo();
77 | ^^^
88 | |
9 | expected one of 9 possible tokens
9 | expected one of 10 possible tokens
1010 | help: there is already a visibility modifier, remove one
1111...
1212LL | }
tests/ui/parser/misspelled-keywords/pub-fn.stderr+2-2
......@@ -1,8 +1,8 @@
1error: expected one of `#`, `async`, `auto`, `const`, `default`, `enum`, `extern`, `fn`, `gen`, `impl`, `macro_rules`, `macro`, `mod`, `pub`, `safe`, `static`, `struct`, `trait`, `type`, `unsafe`, or `use`, found `puB`
1error: expected one of `#`, `async`, `auto`, `const`, `default`, `enum`, `extern`, `final`, `fn`, `gen`, `impl`, `macro_rules`, `macro`, `mod`, `pub`, `safe`, `static`, `struct`, `trait`, `type`, `unsafe`, or `use`, found `puB`
22 --> $DIR/pub-fn.rs:1:1
33 |
44LL | puB fn code() {}
5 | ^^^ expected one of 21 possible tokens
5 | ^^^ expected one of 22 possible tokens
66 |
77help: write keyword `pub` in lowercase
88 |
tests/ui/proc-macro/quote/not-repeatable.rs-1
......@@ -10,5 +10,4 @@ fn main() {
1010 let ip = Ipv4Addr;
1111 let _ = quote! { $($ip)* };
1212 //~^ ERROR the method `quote_into_iter` exists for struct `Ipv4Addr`, but its trait bounds were not satisfied
13 //~| ERROR type annotations needed
1413}
tests/ui/proc-macro/quote/not-repeatable.stderr+2-9
......@@ -20,13 +20,6 @@ note: the traits `Iterator` and `ToTokens` must be implemented
2020 --> $SRC_DIR/proc_macro/src/to_tokens.rs:LL:COL
2121 --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
2222
23error[E0282]: type annotations needed
24 --> $DIR/not-repeatable.rs:11:25
25 |
26LL | let _ = quote! { $($ip)* };
27 | ^^ cannot infer type
28
29error: aborting due to 2 previous errors
23error: aborting due to 1 previous error
3024
31Some errors have detailed explanations: E0282, E0599.
32For more information about an error, try `rustc --explain E0282`.
25For more information about this error, try `rustc --explain E0599`.
tests/ui/traits/auxiliary/force_unstable.rs created+7
......@@ -0,0 +1,7 @@
1//@ edition: 2024
2//@ compile-flags: -Zforce-unstable-if-unmarked
3
4// Auxiliary crate that uses `-Zforce-unstable-if-unmarked` to export an
5// "unstable" trait.
6
7pub trait ForeignTrait {}
tests/ui/traits/final/dyn-compat.rs created+40
......@@ -0,0 +1,40 @@
1//@ run-pass
2
3#![feature(final_associated_functions)]
4
5trait FinalNoReceiver {
6 final fn no_receiver() {}
7}
8
9trait FinalGeneric {
10 final fn generic<T>(&self, _value: T) {}
11}
12
13trait FinalSelfParam {
14 final fn self_param(&self, _other: &Self) {}
15}
16
17trait FinalSelfReturn {
18 final fn self_return(&self) -> &Self {
19 self
20 }
21}
22
23struct S;
24
25impl FinalNoReceiver for S {}
26impl FinalGeneric for S {}
27impl FinalSelfParam for S {}
28impl FinalSelfReturn for S {}
29
30fn main() {
31 let s = S;
32 <S as FinalNoReceiver>::no_receiver();
33 let obj_generic: &dyn FinalGeneric = &s;
34 let obj_param: &dyn FinalSelfParam = &s;
35 let obj_return: &dyn FinalSelfReturn = &s;
36 obj_generic.generic(1u8);
37 obj_param.self_param(obj_param);
38 let _ = obj_return.self_return();
39 let _: &dyn FinalNoReceiver = &s;
40}
tests/ui/traits/final/final-kw.gated.stderr created+13
......@@ -0,0 +1,13 @@
1error[E0658]: `final` on trait functions is experimental
2 --> $DIR/final-kw.rs:5:5
3 |
4LL | final fn foo() {}
5 | ^^^^^
6 |
7 = note: see issue #1 <https://github.com/rust-lang/rust/issues/1> for more information
8 = help: add `#![feature(final_associated_functions)]` to the crate attributes to enable
9 = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
10
11error: aborting due to 1 previous error
12
13For more information about this error, try `rustc --explain E0658`.
tests/ui/traits/final/final-kw.rs created+9
......@@ -0,0 +1,9 @@
1//@ revisions: ungated gated
2
3#[cfg(ungated)]
4trait Trait {
5 final fn foo() {}
6 //~^ ERROR `final` on trait functions is experimental
7}
8
9fn main() {}
tests/ui/traits/final/final-kw.ungated.stderr created+13
......@@ -0,0 +1,13 @@
1error[E0658]: `final` on trait functions is experimental
2 --> $DIR/final-kw.rs:5:5
3 |
4LL | final fn foo() {}
5 | ^^^^^
6 |
7 = note: see issue #1 <https://github.com/rust-lang/rust/issues/1> for more information
8 = help: add `#![feature(final_associated_functions)]` to the crate attributes to enable
9 = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
10
11error: aborting due to 1 previous error
12
13For more information about this error, try `rustc --explain E0658`.
tests/ui/traits/final/final-must-have-body.rs created+8
......@@ -0,0 +1,8 @@
1#![feature(final_associated_functions)]
2
3trait Foo {
4 final fn method();
5 //~^ ERROR `final` is only allowed on associated functions if they have a body
6}
7
8fn main() {}
tests/ui/traits/final/final-must-have-body.stderr created+10
......@@ -0,0 +1,10 @@
1error: `final` is only allowed on associated functions if they have a body
2 --> $DIR/final-must-have-body.rs:4:5
3 |
4LL | final fn method();
5 | -----^^^^^^^^^^^^^
6 | |
7 | `final` because of this
8
9error: aborting due to 1 previous error
10
tests/ui/traits/final/overriding.rs created+12
......@@ -0,0 +1,12 @@
1#![feature(final_associated_functions)]
2
3trait Foo {
4 final fn method() {}
5}
6
7impl Foo for () {
8 fn method() {}
9 //~^ ERROR cannot override `method` because it already has a `final` definition in the trait
10}
11
12fn main() {}
tests/ui/traits/final/overriding.stderr created+14
......@@ -0,0 +1,14 @@
1error: cannot override `method` because it already has a `final` definition in the trait
2 --> $DIR/overriding.rs:8:5
3 |
4LL | fn method() {}
5 | ^^^^^^^^^^^
6 |
7note: `method` is marked final here
8 --> $DIR/overriding.rs:4:5
9 |
10LL | final fn method() {}
11 | ^^^^^^^^^^^^^^^^^
12
13error: aborting due to 1 previous error
14
tests/ui/traits/final/positions.rs created+72
......@@ -0,0 +1,72 @@
1#![feature(final_associated_functions)]
2
3// Just for exercising the syntax positions
4#![feature(associated_type_defaults, extern_types, inherent_associated_types)]
5#![allow(incomplete_features)]
6
7final struct Foo {}
8//~^ ERROR a struct cannot be `final`
9
10final trait Trait {
11//~^ ERROR a trait cannot be `final`
12
13 final fn method() {}
14 // OK!
15
16 final type Foo = ();
17 //~^ ERROR `final` is only allowed on associated functions in traits
18
19 final const FOO: usize = 1;
20 //~^ ERROR `final` is only allowed on associated functions in traits
21}
22
23final impl Foo {
24 final fn method() {}
25 //~^ ERROR `final` is only allowed on associated functions in traits
26
27 final type Foo = ();
28 //~^ ERROR `final` is only allowed on associated functions in traits
29
30 final const FOO: usize = 1;
31 //~^ ERROR `final` is only allowed on associated functions in traits
32}
33
34final impl Trait for Foo {
35 final fn method() {}
36 //~^ ERROR `final` is only allowed on associated functions in traits
37 //~^^ ERROR cannot override `method` because it already has a `final` definition in the trait
38
39 final type Foo = ();
40 //~^ ERROR `final` is only allowed on associated functions in traits
41 //~^^ ERROR cannot override `Foo` because it already has a `final` definition in the trait
42
43 final const FOO: usize = 1;
44 //~^ ERROR `final` is only allowed on associated functions in traits
45 //~^^ ERROR cannot override `FOO` because it already has a `final` definition in the trait
46}
47
48
49final fn foo() {}
50//~^ ERROR `final` is only allowed on associated functions in traits
51
52final type FooTy = ();
53//~^ ERROR `final` is only allowed on associated functions in traits
54
55final const FOO: usize = 0;
56//~^ ERROR `final` is only allowed on associated functions in traits
57
58final unsafe extern "C" {
59//~^ ERROR an extern block cannot be `final`
60
61 final fn foo_extern();
62 //~^ ERROR `final` is only allowed on associated functions in traits
63
64 final type FooExtern;
65 //~^ ERROR `final` is only allowed on associated functions in traits
66
67 final static FOO_EXTERN: usize = 0;
68 //~^ ERROR a static item cannot be `final`
69 //~| ERROR incorrect `static` inside `extern` block
70}
71
72fn main() {}
tests/ui/traits/final/positions.stderr created+187
......@@ -0,0 +1,187 @@
1error: a struct cannot be `final`
2 --> $DIR/positions.rs:7:1
3 |
4LL | final struct Foo {}
5 | ^^^^^ `final` because of this
6 |
7 = note: only associated functions in traits can be `final`
8
9error: a trait cannot be `final`
10 --> $DIR/positions.rs:10:1
11 |
12LL | final trait Trait {
13 | ^^^^^ `final` because of this
14 |
15 = note: only associated functions in traits can be `final`
16
17error: a static item cannot be `final`
18 --> $DIR/positions.rs:67:5
19 |
20LL | final static FOO_EXTERN: usize = 0;
21 | ^^^^^ `final` because of this
22 |
23 = note: only associated functions in traits can be `final`
24
25error: an extern block cannot be `final`
26 --> $DIR/positions.rs:58:1
27 |
28LL | final unsafe extern "C" {
29 | ^^^^^ `final` because of this
30 |
31 = note: only associated functions in traits can be `final`
32
33error: `final` is only allowed on associated functions in traits
34 --> $DIR/positions.rs:16:5
35 |
36LL | final type Foo = ();
37 | -----^^^^^^^^^^^^^^^
38 | |
39 | `final` because of this
40
41error: `final` is only allowed on associated functions in traits
42 --> $DIR/positions.rs:19:5
43 |
44LL | final const FOO: usize = 1;
45 | -----^^^^^^^^^^^^^^^^^^^^^^
46 | |
47 | `final` because of this
48
49error: `final` is only allowed on associated functions in traits
50 --> $DIR/positions.rs:24:5
51 |
52LL | final fn method() {}
53 | -----^^^^^^^^^^^^
54 | |
55 | `final` because of this
56
57error: `final` is only allowed on associated functions in traits
58 --> $DIR/positions.rs:27:5
59 |
60LL | final type Foo = ();
61 | -----^^^^^^^^^^^^^^^
62 | |
63 | `final` because of this
64
65error: `final` is only allowed on associated functions in traits
66 --> $DIR/positions.rs:30:5
67 |
68LL | final const FOO: usize = 1;
69 | -----^^^^^^^^^^^^^^^^^^^^^^
70 | |
71 | `final` because of this
72
73error: `final` is only allowed on associated functions in traits
74 --> $DIR/positions.rs:35:5
75 |
76LL | final fn method() {}
77 | -----^^^^^^^^^^^^
78 | |
79 | `final` because of this
80
81error: `final` is only allowed on associated functions in traits
82 --> $DIR/positions.rs:39:5
83 |
84LL | final type Foo = ();
85 | -----^^^^^^^^^^^^^^^
86 | |
87 | `final` because of this
88
89error: `final` is only allowed on associated functions in traits
90 --> $DIR/positions.rs:43:5
91 |
92LL | final const FOO: usize = 1;
93 | -----^^^^^^^^^^^^^^^^^^^^^^
94 | |
95 | `final` because of this
96
97error: `final` is only allowed on associated functions in traits
98 --> $DIR/positions.rs:49:1
99 |
100LL | final fn foo() {}
101 | -----^^^^^^^^^
102 | |
103 | `final` because of this
104
105error: `final` is only allowed on associated functions in traits
106 --> $DIR/positions.rs:52:1
107 |
108LL | final type FooTy = ();
109 | -----^^^^^^^^^^^^^^^^^
110 | |
111 | `final` because of this
112
113error: `final` is only allowed on associated functions in traits
114 --> $DIR/positions.rs:55:1
115 |
116LL | final const FOO: usize = 0;
117 | -----^^^^^^^^^^^^^^^^^^^^^^
118 | |
119 | `final` because of this
120
121error: `final` is only allowed on associated functions in traits
122 --> $DIR/positions.rs:61:5
123 |
124LL | final fn foo_extern();
125 | -----^^^^^^^^^^^^^^^^^
126 | |
127 | `final` because of this
128
129error: `final` is only allowed on associated functions in traits
130 --> $DIR/positions.rs:64:5
131 |
132LL | final type FooExtern;
133 | -----^^^^^^^^^^^^^^^^
134 | |
135 | `final` because of this
136
137error: incorrect `static` inside `extern` block
138 --> $DIR/positions.rs:67:18
139 |
140LL | final unsafe extern "C" {
141 | ----------------------- `extern` blocks define existing foreign statics and statics inside of them cannot have a body
142...
143LL | final static FOO_EXTERN: usize = 0;
144 | ^^^^^^^^^^ - the invalid body
145 | |
146 | cannot have a body
147 |
148 = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html
149
150error: cannot override `method` because it already has a `final` definition in the trait
151 --> $DIR/positions.rs:35:5
152 |
153LL | final fn method() {}
154 | ^^^^^^^^^^^^^^^^^
155 |
156note: `method` is marked final here
157 --> $DIR/positions.rs:13:5
158 |
159LL | final fn method() {}
160 | ^^^^^^^^^^^^^^^^^
161
162error: cannot override `Foo` because it already has a `final` definition in the trait
163 --> $DIR/positions.rs:39:5
164 |
165LL | final type Foo = ();
166 | ^^^^^^^^^^^^^^
167 |
168note: `Foo` is marked final here
169 --> $DIR/positions.rs:16:5
170 |
171LL | final type Foo = ();
172 | ^^^^^^^^^^^^^^
173
174error: cannot override `FOO` because it already has a `final` definition in the trait
175 --> $DIR/positions.rs:43:5
176 |
177LL | final const FOO: usize = 1;
178 | ^^^^^^^^^^^^^^^^^^^^^^
179 |
180note: `FOO` is marked final here
181 --> $DIR/positions.rs:19:5
182 |
183LL | final const FOO: usize = 1;
184 | ^^^^^^^^^^^^^^^^^^^^^^
185
186error: aborting due to 21 previous errors
187
tests/ui/traits/final/works.rs created+13
......@@ -0,0 +1,13 @@
1//@ check-pass
2
3#![feature(final_associated_functions)]
4
5trait Foo {
6 final fn bar(&self) {}
7}
8
9impl Foo for () {}
10
11fn main() {
12 ().bar();
13}
tests/ui/traits/next-solver-ice.rs created+9
......@@ -0,0 +1,9 @@
1//@compile-flags: -Znext-solver=globally
2//@check-fail
3
4fn check<T: Iterator>() {
5 <f32 as From<<T as Iterator>::Item>>::from;
6 //~^ ERROR the trait bound `f32: From<<T as Iterator>::Item>` is not satisfied
7}
8
9fn main() {}
tests/ui/traits/next-solver-ice.stderr created+21
......@@ -0,0 +1,21 @@
1error[E0277]: the trait bound `f32: From<<T as Iterator>::Item>` is not satisfied
2 --> $DIR/next-solver-ice.rs:5:6
3 |
4LL | <f32 as From<<T as Iterator>::Item>>::from;
5 | ^^^ the nightly-only, unstable trait `ZeroablePrimitive` is not implemented for `f32`
6 |
7 = help: the following other types implement trait `ZeroablePrimitive`:
8 i128
9 i16
10 i32
11 i64
12 i8
13 isize
14 u128
15 u16
16 and 4 others
17 = note: required for `f32` to implement `From<<T as Iterator>::Item>`
18
19error: aborting due to 1 previous error
20
21For more information about this error, try `rustc --explain E0277`.
tests/ui/traits/nightly-only-unstable.force.stderr created+36
......@@ -0,0 +1,36 @@
1error[E0277]: the trait bound `(): LocalTrait` is not satisfied
2 --> $DIR/nightly-only-unstable.rs:25:21
3 |
4LL | use_local_trait(());
5 | --------------- ^^ the trait `LocalTrait` is not implemented for `()`
6 | |
7 | required by a bound introduced by this call
8 |
9help: this trait has no implementations, consider adding one
10 --> $DIR/nightly-only-unstable.rs:14:1
11 |
12LL | trait LocalTrait {}
13 | ^^^^^^^^^^^^^^^^
14note: required by a bound in `use_local_trait`
15 --> $DIR/nightly-only-unstable.rs:16:28
16 |
17LL | fn use_local_trait(_: impl LocalTrait) {}
18 | ^^^^^^^^^^ required by this bound in `use_local_trait`
19
20error[E0277]: the trait bound `(): ForeignTrait` is not satisfied
21 --> $DIR/nightly-only-unstable.rs:31:23
22 |
23LL | use_foreign_trait(());
24 | ----------------- ^^ the trait `ForeignTrait` is not implemented for `()`
25 | |
26 | required by a bound introduced by this call
27 |
28note: required by a bound in `use_foreign_trait`
29 --> $DIR/nightly-only-unstable.rs:20:30
30 |
31LL | fn use_foreign_trait(_: impl force_unstable::ForeignTrait) {}
32 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `use_foreign_trait`
33
34error: aborting due to 2 previous errors
35
36For more information about this error, try `rustc --explain E0277`.
tests/ui/traits/nightly-only-unstable.normal.stderr created+36
......@@ -0,0 +1,36 @@
1error[E0277]: the trait bound `(): LocalTrait` is not satisfied
2 --> $DIR/nightly-only-unstable.rs:25:21
3 |
4LL | use_local_trait(());
5 | --------------- ^^ the trait `LocalTrait` is not implemented for `()`
6 | |
7 | required by a bound introduced by this call
8 |
9help: this trait has no implementations, consider adding one
10 --> $DIR/nightly-only-unstable.rs:14:1
11 |
12LL | trait LocalTrait {}
13 | ^^^^^^^^^^^^^^^^
14note: required by a bound in `use_local_trait`
15 --> $DIR/nightly-only-unstable.rs:16:28
16 |
17LL | fn use_local_trait(_: impl LocalTrait) {}
18 | ^^^^^^^^^^ required by this bound in `use_local_trait`
19
20error[E0277]: the trait bound `(): ForeignTrait` is not satisfied
21 --> $DIR/nightly-only-unstable.rs:31:23
22 |
23LL | use_foreign_trait(());
24 | ----------------- ^^ the nightly-only, unstable trait `ForeignTrait` is not implemented for `()`
25 | |
26 | required by a bound introduced by this call
27 |
28note: required by a bound in `use_foreign_trait`
29 --> $DIR/nightly-only-unstable.rs:20:30
30 |
31LL | fn use_foreign_trait(_: impl force_unstable::ForeignTrait) {}
32 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `use_foreign_trait`
33
34error: aborting due to 2 previous errors
35
36For more information about this error, try `rustc --explain E0277`.
tests/ui/traits/nightly-only-unstable.rs created+36
......@@ -0,0 +1,36 @@
1//@ revisions: normal force
2//@ edition: 2024
3//@ aux-crate: force_unstable=force_unstable.rs
4//@[force] compile-flags: -Zforce-unstable-if-unmarked
5
6#![feature(rustc_private)]
7
8// Regression test for <https://github.com/rust-lang/rust/issues/152692>.
9//
10// When building a crate with `-Zforce-unstable-if-unmarked` (e.g. the compiler or stdlib),
11// it's unhelpful to mention that a not-implemented trait is unstable, because that will
12// be true of every local and foreign trait that isn't explicitly marked stable.
13
14trait LocalTrait {}
15
16fn use_local_trait(_: impl LocalTrait) {}
17//~^ NOTE required by a bound in `use_local_trait`
18//~| NOTE required by this bound in `use_local_trait`
19
20fn use_foreign_trait(_: impl force_unstable::ForeignTrait) {}
21//~^ NOTE required by a bound in `use_foreign_trait`
22//~| NOTE required by this bound in `use_foreign_trait`
23
24fn main() {
25 use_local_trait(());
26 //~^ ERROR the trait bound `(): LocalTrait` is not satisfied
27 //[normal]~| NOTE the trait `LocalTrait` is not implemented for `()`
28 //[force]~| NOTE the trait `LocalTrait` is not implemented for `()`
29 //~| NOTE required by a bound introduced by this call
30
31 use_foreign_trait(());
32 //~^ ERROR the trait bound `(): ForeignTrait` is not satisfied
33 //[normal]~| NOTE the nightly-only, unstable trait `ForeignTrait` is not implemented for `()`
34 //[force]~| NOTE the trait `ForeignTrait` is not implemented for `()`
35 //~| NOTE required by a bound introduced by this call
36}
tests/ui/typeck/issue-13853.rs+1-1
......@@ -25,7 +25,7 @@ impl Node for Stuff {
2525
2626fn iterate<N: Node, G: Graph<N>>(graph: &G) {
2727 for node in graph.iter() { //~ ERROR no method named `iter` found
28 node.zomg(); //~ ERROR type annotations needed
28 node.zomg();
2929 }
3030}
3131
tests/ui/typeck/issue-13853.stderr+3-9
......@@ -17,12 +17,6 @@ error[E0599]: no method named `iter` found for reference `&G` in the current sco
1717LL | for node in graph.iter() {
1818 | ^^^^ method not found in `&G`
1919
20error[E0282]: type annotations needed
21 --> $DIR/issue-13853.rs:28:9
22 |
23LL | node.zomg();
24 | ^^^^ cannot infer type
25
2620error[E0308]: mismatched types
2721 --> $DIR/issue-13853.rs:37:13
2822 |
......@@ -43,7 +37,7 @@ help: consider borrowing here
4337LL | iterate(&graph);
4438 | +
4539
46error: aborting due to 4 previous errors
40error: aborting due to 3 previous errors
4741
48Some errors have detailed explanations: E0282, E0308, E0599.
49For more information about an error, try `rustc --explain E0282`.
42Some errors have detailed explanations: E0308, E0599.
43For more information about an error, try `rustc --explain E0308`.
triagebot.toml+2-3
......@@ -540,7 +540,6 @@ trigger_files = [
540540
541541[autolabel."A-query-system"]
542542trigger_files = [
543 "compiler/rustc_query_system",
544543 "compiler/rustc_query_impl",
545544 "compiler/rustc_macros/src/query.rs"
546545]
......@@ -1557,8 +1556,10 @@ dep-bumps = [
15571556"/compiler/rustc_codegen_llvm/src/debuginfo" = ["compiler", "debuginfo"]
15581557"/compiler/rustc_codegen_ssa" = ["compiler", "codegen"]
15591558"/compiler/rustc_middle/src/dep_graph" = ["compiler", "incremental", "query-system"]
1559"/compiler/rustc_middle/src/ich" = ["compiler", "incremental", "query-system"]
15601560"/compiler/rustc_middle/src/mir" = ["compiler", "mir"]
15611561"/compiler/rustc_middle/src/traits" = ["compiler", "types"]
1562"/compiler/rustc_middle/src/query" = ["compiler", "query-system"]
15621563"/compiler/rustc_middle/src/ty" = ["compiler", "types"]
15631564"/compiler/rustc_const_eval/src/interpret" = ["compiler", "mir"]
15641565"/compiler/rustc_mir_build/src/builder" = ["compiler", "mir"]
......@@ -1567,8 +1568,6 @@ dep-bumps = [
15671568"/compiler/rustc_parse" = ["compiler", "parser"]
15681569"/compiler/rustc_parse/src/lexer" = ["compiler", "lexer"]
15691570"/compiler/rustc_query_impl" = ["compiler", "query-system"]
1570"/compiler/rustc_query_system" = ["compiler", "query-system"]
1571"/compiler/rustc_query_system/src/ich" = ["compiler", "incremental", "query-system"]
15721571"/compiler/rustc_trait_selection" = ["compiler", "types"]
15731572"/compiler/rustc_traits" = ["compiler", "types"]
15741573"/compiler/rustc_type_ir" = ["compiler", "types"]