Skip to content

Commit bef6f3e

Browse files
committed
rework implementation for inherent impls for builtin types
1 parent 4558a12 commit bef6f3e

File tree

21 files changed

+365
-414
lines changed

21 files changed

+365
-414
lines changed

compiler/rustc_feature/src/builtin_attrs.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -636,6 +636,14 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
636636
template!(Word), ErrorFollowing,
637637
"#[rustc_pass_by_value] is used to mark types that must be passed by value instead of reference."
638638
),
639+
rustc_attr!(
640+
rustc_coherence_is_core, AttributeType::CrateLevel, template!(Word), ErrorFollowing,
641+
"#![rustc_coherence_is_core] allows inherent methods on builtin types, only intended to be used in `core`."
642+
),
643+
rustc_attr!(
644+
rustc_allow_incoherent_impl, AttributeType::Normal, template!(Word), ErrorFollowing,
645+
"#[rustc_allow_incoherent_impl] has to be added to all impl items of an incoherent inherent impl."
646+
),
639647
BuiltinAttribute {
640648
name: sym::rustc_diagnostic_item,
641649
type_: Normal,

compiler/rustc_metadata/src/rmeta/decoder.rs

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,11 @@ crate struct CrateMetadata {
9595
/// FIXME: Used only from queries and can use query cache,
9696
/// so pre-decoding can probably be avoided.
9797
trait_impls: FxHashMap<(u32, DefIndex), Lazy<[(DefIndex, Option<SimplifiedType>)]>>,
98+
/// Inherent impls which do not follow the normal coherence rules.
99+
///
100+
/// These can be introduces using either `#![rustc_coherence_is_core]`
101+
/// or `#[rustc_allow_incoherent_impl]`.
102+
incoherent_impls: FxHashMap<SimplifiedType, Lazy<[DefIndex]>>,
98103
/// Proc macro descriptions for this crate, if it's a proc macro crate.
99104
raw_proc_macros: Option<&'static [ProcMacro]>,
100105
/// Source maps for code from the crate.
@@ -1327,17 +1332,25 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
13271332

13281333
/// Decodes all trait impls in the crate (for rustdoc).
13291334
fn get_trait_impls(self) -> impl Iterator<Item = (DefId, DefId, Option<SimplifiedType>)> + 'a {
1330-
self.cdata.trait_impls.iter().flat_map(move |((trait_cnum_raw, trait_index), impls)| {
1335+
self.cdata.trait_impls.iter().flat_map(move |(&(trait_cnum_raw, trait_index), impls)| {
13311336
let trait_def_id = DefId {
1332-
krate: self.cnum_map[CrateNum::from_u32(*trait_cnum_raw)],
1333-
index: *trait_index,
1337+
krate: self.cnum_map[CrateNum::from_u32(trait_cnum_raw)],
1338+
index: trait_index,
13341339
};
13351340
impls.decode(self).map(move |(impl_index, simplified_self_ty)| {
13361341
(trait_def_id, self.local_def_id(impl_index), simplified_self_ty)
13371342
})
13381343
})
13391344
}
13401345

1346+
fn get_incoherent_impls(self, tcx: TyCtxt<'tcx>, simp: SimplifiedType) -> &'tcx [DefId] {
1347+
if let Some(impls) = self.cdata.incoherent_impls.get(&simp) {
1348+
tcx.arena.alloc_from_iter(impls.decode(self).map(|idx| self.local_def_id(idx)))
1349+
} else {
1350+
&[]
1351+
}
1352+
}
1353+
13411354
fn get_implementations_of_trait(
13421355
self,
13431356
tcx: TyCtxt<'tcx>,
@@ -1754,6 +1767,11 @@ impl CrateMetadata {
17541767
.decode((&blob, sess))
17551768
.map(|trait_impls| (trait_impls.trait_id, trait_impls.impls))
17561769
.collect();
1770+
let incoherent_impls = root
1771+
.incoherent_impls
1772+
.decode((&blob, sess))
1773+
.map(|incoherent_impls| (incoherent_impls.self_ty, incoherent_impls.impls))
1774+
.collect();
17571775
let alloc_decoding_state =
17581776
AllocDecodingState::new(root.interpret_alloc_index.decode(&blob).collect());
17591777
let dependencies = Lock::new(cnum_map.iter().cloned().collect());
@@ -1766,6 +1784,7 @@ impl CrateMetadata {
17661784
blob,
17671785
root,
17681786
trait_impls,
1787+
incoherent_impls,
17691788
raw_proc_macros,
17701789
source_map_import_info: OnceCell::new(),
17711790
def_path_hash_map,

compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -81,30 +81,42 @@ macro_rules! provide {
8181
// small trait to work around different signature queries all being defined via
8282
// the macro above.
8383
trait IntoArgs {
84-
fn into_args(self) -> (DefId, DefId);
84+
type Other;
85+
fn into_args(self) -> (DefId, Self::Other);
8586
}
8687

8788
impl IntoArgs for DefId {
88-
fn into_args(self) -> (DefId, DefId) {
89-
(self, self)
89+
type Other = ();
90+
fn into_args(self) -> (DefId, ()) {
91+
(self, ())
9092
}
9193
}
9294

9395
impl IntoArgs for CrateNum {
94-
fn into_args(self) -> (DefId, DefId) {
95-
(self.as_def_id(), self.as_def_id())
96+
type Other = ();
97+
fn into_args(self) -> (DefId, ()) {
98+
(self.as_def_id(), ())
9699
}
97100
}
98101

99102
impl IntoArgs for (CrateNum, DefId) {
103+
type Other = DefId;
100104
fn into_args(self) -> (DefId, DefId) {
101105
(self.0.as_def_id(), self.1)
102106
}
103107
}
104108

105109
impl<'tcx> IntoArgs for ty::InstanceDef<'tcx> {
106-
fn into_args(self) -> (DefId, DefId) {
107-
(self.def_id(), self.def_id())
110+
type Other = ();
111+
fn into_args(self) -> (DefId, ()) {
112+
(self.def_id(), ())
113+
}
114+
}
115+
116+
impl IntoArgs for (CrateNum, SimplifiedType) {
117+
type Other = SimplifiedType;
118+
fn into_args(self) -> (DefId, SimplifiedType) {
119+
(self.0.as_def_id(), self.1)
108120
}
109121
}
110122

@@ -199,6 +211,7 @@ provide! { <'tcx> tcx, def_id, other, cdata,
199211

200212
traits_in_crate => { tcx.arena.alloc_from_iter(cdata.get_traits()) }
201213
implementations_of_trait => { cdata.get_implementations_of_trait(tcx, other) }
214+
crate_incoherent_impls => { cdata.get_incoherent_impls(tcx, other) }
202215

203216
dep_kind => {
204217
let r = *cdata.dep_kind.lock();
@@ -371,7 +384,6 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) {
371384
.alloc_slice(&CStore::from_tcx(tcx).crate_dependencies_in_postorder(LOCAL_CRATE))
372385
},
373386
crates: |tcx, ()| tcx.arena.alloc_from_iter(CStore::from_tcx(tcx).crates_untracked()),
374-
375387
..*providers
376388
};
377389
}

compiler/rustc_metadata/src/rmeta/encoder.rs

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@ use crate::rmeta::def_path_hash_map::DefPathHashMapRef;
22
use crate::rmeta::table::{FixedSizeEncoding, TableBuilder};
33
use crate::rmeta::*;
44

5+
use rustc_data_structures::fingerprint::Fingerprint;
56
use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
6-
use rustc_data_structures::stable_hasher::StableHasher;
7+
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
78
use rustc_data_structures::sync::{join, par_iter, Lrc, ParallelIterator};
89
use rustc_hir as hir;
910
use rustc_hir::def::DefKind;
@@ -578,6 +579,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
578579
}
579580

580581
fn encode_crate_root(&mut self) -> Lazy<CrateRoot<'tcx>> {
582+
let tcx = self.tcx;
581583
let mut i = self.position();
582584

583585
// Encode the crate deps
@@ -623,8 +625,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
623625
let impls = self.encode_impls();
624626
let impls_bytes = self.position() - i;
625627

626-
let tcx = self.tcx;
627-
628+
i = self.position();
629+
let incoherent_impls = self.encode_incoherent_impls();
630+
let incoherent_impls_bytes = self.position() - i;
628631
// Encode MIR.
629632
i = self.position();
630633
self.encode_mir();
@@ -734,6 +737,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
734737
source_map,
735738
traits,
736739
impls,
740+
incoherent_impls,
737741
exported_symbols,
738742
interpret_alloc_index,
739743
tables,
@@ -762,6 +766,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
762766
eprintln!(" source_map bytes: {}", source_map_bytes);
763767
eprintln!(" traits bytes: {}", traits_bytes);
764768
eprintln!(" impls bytes: {}", impls_bytes);
769+
eprintln!("incoherent_impls bytes: {}", incoherent_impls_bytes);
765770
eprintln!(" exp. symbols bytes: {}", exported_symbols_bytes);
766771
eprintln!(" def-path table bytes: {}", def_path_table_bytes);
767772
eprintln!(" def-path hashes bytes: {}", def_path_hash_map_bytes);
@@ -1813,6 +1818,33 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
18131818
self.lazy(&all_impls)
18141819
}
18151820

1821+
fn encode_incoherent_impls(&mut self) -> Lazy<[IncoherentImpls]> {
1822+
debug!("EncodeContext::encode_traits_and_impls()");
1823+
empty_proc_macro!(self);
1824+
let tcx = self.tcx;
1825+
let mut ctx = tcx.create_stable_hashing_context();
1826+
let mut all_impls: Vec<_> = tcx.crate_inherent_impls(()).incoherent_impls.iter().collect();
1827+
all_impls.sort_by_cached_key(|&(&simp, _)| {
1828+
let mut hasher = StableHasher::new();
1829+
simp.hash_stable(&mut ctx, &mut hasher);
1830+
hasher.finish::<Fingerprint>();
1831+
});
1832+
let all_impls: Vec<_> = all_impls
1833+
.into_iter()
1834+
.map(|(&simp, impls)| {
1835+
let mut impls: Vec<_> =
1836+
impls.into_iter().map(|def_id| def_id.local_def_index).collect();
1837+
impls.sort_by_cached_key(|&local_def_index| {
1838+
tcx.hir().def_path_hash(LocalDefId { local_def_index })
1839+
});
1840+
1841+
IncoherentImpls { self_ty: simp, impls: self.lazy(impls) }
1842+
})
1843+
.collect();
1844+
1845+
self.lazy(&all_impls)
1846+
}
1847+
18161848
// Encodes all symbols exported from this crate into the metadata.
18171849
//
18181850
// This pass is seeded off the reachability list calculated in the

compiler/rustc_metadata/src/rmeta/mod.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,7 @@ crate struct CrateRoot<'tcx> {
212212
foreign_modules: Lazy<[ForeignModule]>,
213213
traits: Lazy<[DefIndex]>,
214214
impls: Lazy<[TraitImpls]>,
215+
incoherent_impls: Lazy<[IncoherentImpls]>,
215216
interpret_alloc_index: Lazy<[u32]>,
216217
proc_macro_data: Option<ProcMacroData>,
217218

@@ -251,6 +252,12 @@ crate struct TraitImpls {
251252
impls: Lazy<[(DefIndex, Option<SimplifiedType>)]>,
252253
}
253254

255+
#[derive(MetadataEncodable, MetadataDecodable)]
256+
crate struct IncoherentImpls {
257+
self_ty: SimplifiedType,
258+
impls: Lazy<[DefIndex]>,
259+
}
260+
254261
/// Define `LazyTables` and `TableBuilders` at the same time.
255262
macro_rules! define_tables {
256263
($($name:ident: Table<$IDX:ty, $T:ty>),+ $(,)?) => {

compiler/rustc_middle/src/hir/map/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -579,6 +579,10 @@ impl<'hir> Map<'hir> {
579579
self.attrs(CRATE_HIR_ID)
580580
}
581581

582+
pub fn rustc_coherence_is_core(self) -> bool {
583+
self.krate_attrs().iter().any(|attr| attr.has_name(sym::rustc_coherence_is_core))
584+
}
585+
582586
pub fn get_module(self, module: LocalDefId) -> (&'hir Mod<'hir>, Span, HirId) {
583587
let hir_id = HirId::make_owner(module);
584588
match self.tcx.hir_owner(module).map(|o| o.node) {

compiler/rustc_middle/src/query/mod.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -684,6 +684,10 @@ rustc_queries! {
684684
separate_provide_extern
685685
}
686686

687+
query incoherent_impls(key: SimplifiedType) -> &'tcx [DefId] {
688+
desc { |tcx| "collecting all inherent impls for `{:?}`", key }
689+
}
690+
687691
/// The result of unsafety-checking this `LocalDefId`.
688692
query unsafety_check_result(key: LocalDefId) -> &'tcx mir::UnsafetyCheckResult {
689693
desc { |tcx| "unsafety-checking `{}`", tcx.def_path_str(key.to_def_id()) }
@@ -1469,6 +1473,15 @@ rustc_queries! {
14691473
separate_provide_extern
14701474
}
14711475

1476+
/// Collects all incoherent impls for the given crate and type.
1477+
///
1478+
/// Do not call this directly, but instead use the `incoherent_impls` query.
1479+
/// This query is only used to get the data necessary for that query.
1480+
query crate_incoherent_impls(key: (CrateNum, SimplifiedType)) -> &'tcx [DefId] {
1481+
desc { |tcx| "collecting all impls for a type in a crate" }
1482+
separate_provide_extern
1483+
}
1484+
14721485
query is_dllimport_foreign_item(def_id: DefId) -> bool {
14731486
desc { |tcx| "is_dllimport_foreign_item({})", tcx.def_path_str(def_id) }
14741487
}

compiler/rustc_middle/src/ty/impls_ty.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
use crate::middle::region;
55
use crate::mir;
66
use crate::ty;
7+
use crate::ty::fast_reject::SimplifiedType;
78
use rustc_data_structures::fingerprint::Fingerprint;
89
use rustc_data_structures::fx::FxHashMap;
910
use rustc_data_structures::stable_hasher::HashingControls;
@@ -55,6 +56,18 @@ where
5556
}
5657
}
5758

59+
impl<'a> ToStableHashKey<StableHashingContext<'a>> for SimplifiedType {
60+
type KeyType = Fingerprint;
61+
62+
#[inline]
63+
fn to_stable_hash_key(&self, hcx: &StableHashingContext<'a>) -> Fingerprint {
64+
let mut hasher = StableHasher::new();
65+
let mut hcx: StableHashingContext<'a> = hcx.clone();
66+
self.hash_stable(&mut hcx, &mut hasher);
67+
hasher.finish()
68+
}
69+
}
70+
5871
impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for ty::subst::GenericArg<'tcx> {
5972
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
6073
self.unpack().hash_stable(hcx, hasher);

compiler/rustc_middle/src/ty/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ use crate::middle::privacy::AccessLevels;
2525
use crate::mir::{Body, GeneratorLayout};
2626
use crate::traits::{self, Reveal};
2727
use crate::ty;
28+
use crate::ty::fast_reject::SimplifiedType;
2829
use crate::ty::subst::{GenericArg, InternalSubsts, Subst, SubstsRef};
2930
use crate::ty::util::Discr;
3031
use rustc_ast as ast;
@@ -2335,6 +2336,7 @@ pub fn provide(providers: &mut ty::query::Providers) {
23352336
super::middle::provide(providers);
23362337
*providers = ty::query::Providers {
23372338
trait_impls_of: trait_def::trait_impls_of_provider,
2339+
incoherent_impls: trait_def::incoherent_impls_provider,
23382340
type_uninhabited_from: inhabitedness::type_uninhabited_from,
23392341
const_param_default: consts::const_param_default,
23402342
vtable_allocation: vtable::vtable_allocation_provider,
@@ -2350,6 +2352,7 @@ pub fn provide(providers: &mut ty::query::Providers) {
23502352
#[derive(Clone, Debug, Default, HashStable)]
23512353
pub struct CrateInherentImpls {
23522354
pub inherent_impls: LocalDefIdMap<Vec<DefId>>,
2355+
pub incoherent_impls: FxHashMap<SimplifiedType, Vec<LocalDefId>>,
23532356
}
23542357

23552358
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, HashStable)]

compiler/rustc_middle/src/ty/trait_def.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@ use crate::traits::specialization_graph;
22
use crate::ty::fast_reject::{self, SimplifiedType, TreatParams};
33
use crate::ty::fold::TypeFoldable;
44
use crate::ty::{Ident, Ty, TyCtxt};
5+
use hir::def_id::LOCAL_CRATE;
56
use rustc_hir as hir;
67
use rustc_hir::def_id::DefId;
78
use rustc_hir::definitions::DefPathHash;
9+
use std::iter;
810

911
use rustc_data_structures::fx::FxIndexMap;
1012
use rustc_errors::ErrorGuaranteed;
@@ -257,3 +259,19 @@ pub(super) fn trait_impls_of_provider(tcx: TyCtxt<'_>, trait_id: DefId) -> Trait
257259

258260
impls
259261
}
262+
263+
// Query provider for `incoherent_impls`.
264+
#[instrument(level = "debug", skip(tcx))]
265+
pub(super) fn incoherent_impls_provider(tcx: TyCtxt<'_>, simp: SimplifiedType) -> &[DefId] {
266+
let mut impls = Vec::new();
267+
268+
for cnum in iter::once(LOCAL_CRATE).chain(tcx.crates(()).iter().copied()) {
269+
for &impl_def_id in tcx.crate_incoherent_impls((cnum, simp)) {
270+
impls.push(impl_def_id)
271+
}
272+
}
273+
274+
debug!(?impls);
275+
276+
tcx.arena.alloc_slice(&impls)
277+
}

0 commit comments

Comments
 (0)