Skip to content

Commit af14861

Browse files
committed
Auto merge of rust-lang#120835 - oli-obk:no_hir_coherence, r=<try>
Avoid accessing the HIR in the happy path of `coherent_trait` This may resolve part of the performance issue of rust-lang#120558
2 parents f4cfd87 + 614ff0f commit af14861

File tree

4 files changed

+109
-111
lines changed

4 files changed

+109
-111
lines changed

compiler/rustc_hir_analysis/src/coherence/builtin.rs

+21-21
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,13 @@ use rustc_trait_selection::traits::ObligationCtxt;
2525
use rustc_trait_selection::traits::{self, ObligationCause};
2626
use std::collections::BTreeMap;
2727

28-
pub fn check_trait(tcx: TyCtxt<'_>, trait_def_id: DefId) -> Result<(), ErrorGuaranteed> {
28+
pub fn check_trait(
29+
tcx: TyCtxt<'_>,
30+
trait_def_id: DefId,
31+
impl_def_id: LocalDefId,
32+
) -> Result<(), ErrorGuaranteed> {
2933
let lang_items = tcx.lang_items();
30-
let checker = Checker { tcx, trait_def_id };
34+
let checker = Checker { tcx, trait_def_id, impl_def_id };
3135
let mut res = checker.check(lang_items.drop_trait(), visit_implementation_of_drop);
3236
res = res.and(checker.check(lang_items.copy_trait(), visit_implementation_of_copy));
3337
res = res.and(
@@ -45,20 +49,16 @@ pub fn check_trait(tcx: TyCtxt<'_>, trait_def_id: DefId) -> Result<(), ErrorGuar
4549
struct Checker<'tcx> {
4650
tcx: TyCtxt<'tcx>,
4751
trait_def_id: DefId,
52+
impl_def_id: LocalDefId,
4853
}
4954

5055
impl<'tcx> Checker<'tcx> {
51-
fn check<F>(&self, trait_def_id: Option<DefId>, mut f: F) -> Result<(), ErrorGuaranteed>
52-
where
53-
F: FnMut(TyCtxt<'tcx>, LocalDefId) -> Result<(), ErrorGuaranteed>,
54-
{
55-
let mut res = Ok(());
56-
if Some(self.trait_def_id) == trait_def_id {
57-
for &impl_def_id in self.tcx.hir().trait_impls(self.trait_def_id) {
58-
res = res.and(f(self.tcx, impl_def_id));
59-
}
60-
}
61-
res
56+
fn check(
57+
&self,
58+
trait_def_id: Option<DefId>,
59+
f: impl FnOnce(TyCtxt<'tcx>, LocalDefId) -> Result<(), ErrorGuaranteed>,
60+
) -> Result<(), ErrorGuaranteed> {
61+
if Some(self.trait_def_id) == trait_def_id { f(self.tcx, self.impl_def_id) } else { Ok(()) }
6262
}
6363
}
6464

@@ -92,10 +92,10 @@ fn visit_implementation_of_copy(
9292

9393
debug!("visit_implementation_of_copy: self_type={:?} (free)", self_type);
9494

95-
let span = match tcx.hir().expect_item(impl_did).expect_impl() {
96-
hir::Impl { polarity: hir::ImplPolarity::Negative(_), .. } => return Ok(()),
97-
hir::Impl { self_ty, .. } => self_ty.span,
98-
};
95+
if let ty::ImplPolarity::Negative = tcx.impl_polarity(impl_did) {
96+
return Ok(());
97+
}
98+
let span = tcx.hir().expect_item(impl_did).expect_impl().self_ty.span;
9999

100100
let cause = traits::ObligationCause::misc(span, impl_did);
101101
match type_allowed_to_implement_copy(tcx, param_env, self_type, cause) {
@@ -121,10 +121,10 @@ fn visit_implementation_of_const_param_ty(
121121

122122
let param_env = tcx.param_env(impl_did);
123123

124-
let span = match tcx.hir().expect_item(impl_did).expect_impl() {
125-
hir::Impl { polarity: hir::ImplPolarity::Negative(_), .. } => return Ok(()),
126-
impl_ => impl_.self_ty.span,
127-
};
124+
if let ty::ImplPolarity::Negative = tcx.impl_polarity(impl_did) {
125+
return Ok(());
126+
}
127+
let span = tcx.hir().expect_item(impl_did).expect_impl().self_ty.span;
128128

129129
let cause = traits::ObligationCause::misc(span, impl_did);
130130
match type_allowed_to_implement_const_param_ty(tcx, param_env, self_type, cause) {

compiler/rustc_hir_analysis/src/coherence/mod.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -131,11 +131,12 @@ fn coherent_trait(tcx: TyCtxt<'_>, def_id: DefId) -> Result<(), ErrorGuaranteed>
131131
res = res.and(check_impl(tcx, impl_def_id, trait_ref));
132132
res = res.and(check_object_overlap(tcx, impl_def_id, trait_ref));
133133

134-
res = res.and(unsafety::check_item(tcx, impl_def_id));
134+
res = res.and(unsafety::check_item(tcx, impl_def_id, trait_ref));
135135
res = res.and(tcx.ensure().orphan_check_impl(impl_def_id));
136+
res = res.and(builtin::check_trait(tcx, def_id, impl_def_id));
136137
}
137138

138-
res.and(builtin::check_trait(tcx, def_id))
139+
res
139140
}
140141

141142
/// Checks whether an impl overlaps with the automatic `impl Trait for dyn Trait`.

compiler/rustc_hir_analysis/src/coherence/unsafety.rs

+73-76
Original file line numberDiff line numberDiff line change
@@ -4,94 +4,91 @@
44
use rustc_errors::{codes::*, struct_span_code_err};
55
use rustc_hir as hir;
66
use rustc_hir::Unsafety;
7-
use rustc_middle::ty::TyCtxt;
7+
use rustc_middle::ty::{TraitRef, TyCtxt};
88
use rustc_span::def_id::LocalDefId;
99
use rustc_span::ErrorGuaranteed;
1010

11-
pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), ErrorGuaranteed> {
11+
pub(super) fn check_item(
12+
tcx: TyCtxt<'_>,
13+
def_id: LocalDefId,
14+
trait_ref: TraitRef<'_>,
15+
) -> Result<(), ErrorGuaranteed> {
1216
let item = tcx.hir().expect_item(def_id);
1317
let impl_ = item.expect_impl();
18+
let trait_def = tcx.trait_def(trait_ref.def_id);
19+
let unsafe_attr = impl_.generics.params.iter().find(|p| p.pure_wrt_drop).map(|_| "may_dangle");
20+
match (trait_def.unsafety, unsafe_attr, impl_.unsafety, impl_.polarity) {
21+
(Unsafety::Normal, None, Unsafety::Unsafe, hir::ImplPolarity::Positive) => {
22+
return Err(struct_span_code_err!(
23+
tcx.dcx(),
24+
tcx.def_span(def_id),
25+
E0199,
26+
"implementing the trait `{}` is not unsafe",
27+
trait_ref.print_trait_sugared()
28+
)
29+
.with_span_suggestion_verbose(
30+
item.span.with_hi(item.span.lo() + rustc_span::BytePos(7)),
31+
"remove `unsafe` from this trait implementation",
32+
"",
33+
rustc_errors::Applicability::MachineApplicable,
34+
)
35+
.emit());
36+
}
1437

15-
if let Some(trait_ref) = tcx.impl_trait_ref(item.owner_id) {
16-
let trait_ref = trait_ref.instantiate_identity();
17-
let trait_def = tcx.trait_def(trait_ref.def_id);
18-
let unsafe_attr =
19-
impl_.generics.params.iter().find(|p| p.pure_wrt_drop).map(|_| "may_dangle");
20-
match (trait_def.unsafety, unsafe_attr, impl_.unsafety, impl_.polarity) {
21-
(Unsafety::Normal, None, Unsafety::Unsafe, hir::ImplPolarity::Positive) => {
22-
return Err(struct_span_code_err!(
23-
tcx.dcx(),
24-
tcx.def_span(def_id),
25-
E0199,
26-
"implementing the trait `{}` is not unsafe",
27-
trait_ref.print_trait_sugared()
28-
)
29-
.with_span_suggestion_verbose(
30-
item.span.with_hi(item.span.lo() + rustc_span::BytePos(7)),
31-
"remove `unsafe` from this trait implementation",
32-
"",
33-
rustc_errors::Applicability::MachineApplicable,
34-
)
35-
.emit());
36-
}
37-
38-
(Unsafety::Unsafe, _, Unsafety::Normal, hir::ImplPolarity::Positive) => {
39-
return Err(struct_span_code_err!(
40-
tcx.dcx(),
41-
tcx.def_span(def_id),
42-
E0200,
43-
"the trait `{}` requires an `unsafe impl` declaration",
44-
trait_ref.print_trait_sugared()
45-
)
46-
.with_note(format!(
47-
"the trait `{}` enforces invariants that the compiler can't check. \
38+
(Unsafety::Unsafe, _, Unsafety::Normal, hir::ImplPolarity::Positive) => {
39+
return Err(struct_span_code_err!(
40+
tcx.dcx(),
41+
tcx.def_span(def_id),
42+
E0200,
43+
"the trait `{}` requires an `unsafe impl` declaration",
44+
trait_ref.print_trait_sugared()
45+
)
46+
.with_note(format!(
47+
"the trait `{}` enforces invariants that the compiler can't check. \
4848
Review the trait documentation and make sure this implementation \
4949
upholds those invariants before adding the `unsafe` keyword",
50-
trait_ref.print_trait_sugared()
51-
))
52-
.with_span_suggestion_verbose(
53-
item.span.shrink_to_lo(),
54-
"add `unsafe` to this trait implementation",
55-
"unsafe ",
56-
rustc_errors::Applicability::MaybeIncorrect,
57-
)
58-
.emit());
59-
}
50+
trait_ref.print_trait_sugared()
51+
))
52+
.with_span_suggestion_verbose(
53+
item.span.shrink_to_lo(),
54+
"add `unsafe` to this trait implementation",
55+
"unsafe ",
56+
rustc_errors::Applicability::MaybeIncorrect,
57+
)
58+
.emit());
59+
}
6060

61-
(Unsafety::Normal, Some(attr_name), Unsafety::Normal, hir::ImplPolarity::Positive) => {
62-
return Err(struct_span_code_err!(
63-
tcx.dcx(),
64-
tcx.def_span(def_id),
65-
E0569,
66-
"requires an `unsafe impl` declaration due to `#[{}]` attribute",
67-
attr_name
68-
)
69-
.with_note(format!(
70-
"the trait `{}` enforces invariants that the compiler can't check. \
61+
(Unsafety::Normal, Some(attr_name), Unsafety::Normal, hir::ImplPolarity::Positive) => {
62+
return Err(struct_span_code_err!(
63+
tcx.dcx(),
64+
tcx.def_span(def_id),
65+
E0569,
66+
"requires an `unsafe impl` declaration due to `#[{}]` attribute",
67+
attr_name
68+
)
69+
.with_note(format!(
70+
"the trait `{}` enforces invariants that the compiler can't check. \
7171
Review the trait documentation and make sure this implementation \
7272
upholds those invariants before adding the `unsafe` keyword",
73-
trait_ref.print_trait_sugared()
74-
))
75-
.with_span_suggestion_verbose(
76-
item.span.shrink_to_lo(),
77-
"add `unsafe` to this trait implementation",
78-
"unsafe ",
79-
rustc_errors::Applicability::MaybeIncorrect,
80-
)
81-
.emit());
82-
}
73+
trait_ref.print_trait_sugared()
74+
))
75+
.with_span_suggestion_verbose(
76+
item.span.shrink_to_lo(),
77+
"add `unsafe` to this trait implementation",
78+
"unsafe ",
79+
rustc_errors::Applicability::MaybeIncorrect,
80+
)
81+
.emit());
82+
}
8383

84-
(_, _, Unsafety::Unsafe, hir::ImplPolarity::Negative(_)) => {
85-
// Reported in AST validation
86-
tcx.dcx().span_delayed_bug(item.span, "unsafe negative impl");
87-
}
88-
(_, _, Unsafety::Normal, hir::ImplPolarity::Negative(_))
89-
| (Unsafety::Unsafe, _, Unsafety::Unsafe, hir::ImplPolarity::Positive)
90-
| (Unsafety::Normal, Some(_), Unsafety::Unsafe, hir::ImplPolarity::Positive)
91-
| (Unsafety::Normal, None, Unsafety::Normal, _) => {
92-
// OK
93-
}
84+
(_, _, Unsafety::Unsafe, hir::ImplPolarity::Negative(_)) => {
85+
// Reported in AST validation
86+
tcx.dcx().span_delayed_bug(item.span, "unsafe negative impl");
87+
Ok(())
9488
}
89+
(_, _, Unsafety::Normal, hir::ImplPolarity::Negative(_))
90+
| (Unsafety::Unsafe, _, Unsafety::Unsafe, hir::ImplPolarity::Positive)
91+
| (Unsafety::Normal, Some(_), Unsafety::Unsafe, hir::ImplPolarity::Positive)
92+
| (Unsafety::Normal, None, Unsafety::Normal, _) => Ok(()),
9593
}
96-
Ok(())
9794
}

tests/ui/coherence/coherence-impls-copy.stderr

+12-12
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,12 @@ LL | impl Copy for &'static [NotSync] {}
3030
|
3131
= note: define and implement a trait or new type instead
3232

33+
error[E0206]: the trait `Copy` cannot be implemented for this type
34+
--> $DIR/coherence-impls-copy.rs:21:15
35+
|
36+
LL | impl Copy for &'static mut MyType {}
37+
| ^^^^^^^^^^^^^^^^^^^ type is not a structure or enumeration
38+
3339
error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
3440
--> $DIR/coherence-impls-copy.rs:25:1
3541
|
@@ -41,6 +47,12 @@ LL | impl Copy for (MyType, MyType) {}
4147
|
4248
= note: define and implement a trait or new type instead
4349

50+
error[E0206]: the trait `Copy` cannot be implemented for this type
51+
--> $DIR/coherence-impls-copy.rs:25:15
52+
|
53+
LL | impl Copy for (MyType, MyType) {}
54+
| ^^^^^^^^^^^^^^^^ type is not a structure or enumeration
55+
4456
error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
4557
--> $DIR/coherence-impls-copy.rs:30:1
4658
|
@@ -52,18 +64,6 @@ LL | impl Copy for [MyType] {}
5264
|
5365
= note: define and implement a trait or new type instead
5466

55-
error[E0206]: the trait `Copy` cannot be implemented for this type
56-
--> $DIR/coherence-impls-copy.rs:21:15
57-
|
58-
LL | impl Copy for &'static mut MyType {}
59-
| ^^^^^^^^^^^^^^^^^^^ type is not a structure or enumeration
60-
61-
error[E0206]: the trait `Copy` cannot be implemented for this type
62-
--> $DIR/coherence-impls-copy.rs:25:15
63-
|
64-
LL | impl Copy for (MyType, MyType) {}
65-
| ^^^^^^^^^^^^^^^^ type is not a structure or enumeration
66-
6767
error[E0206]: the trait `Copy` cannot be implemented for this type
6868
--> $DIR/coherence-impls-copy.rs:30:15
6969
|

0 commit comments

Comments
 (0)