]> git.proxmox.com Git - rustc.git/blob - compiler/rustc_middle/src/ty/trait_def.rs
New upstream version 1.63.0+dfsg1
[rustc.git] / compiler / rustc_middle / src / ty / trait_def.rs
1 use crate::traits::specialization_graph;
2 use crate::ty::fast_reject::{self, SimplifiedType, TreatParams};
3 use crate::ty::fold::TypeFoldable;
4 use crate::ty::{Ident, Ty, TyCtxt};
5 use hir::def_id::LOCAL_CRATE;
6 use rustc_hir as hir;
7 use rustc_hir::def_id::DefId;
8 use std::iter;
9
10 use rustc_data_structures::fx::FxIndexMap;
11 use rustc_errors::ErrorGuaranteed;
12 use rustc_macros::HashStable;
13
14 /// A trait's definition with type information.
15 #[derive(HashStable, Encodable, Decodable)]
16 pub struct TraitDef {
17 pub def_id: DefId,
18
19 pub unsafety: hir::Unsafety,
20
21 /// If `true`, then this trait had the `#[rustc_paren_sugar]`
22 /// attribute, indicating that it should be used with `Foo()`
23 /// sugar. This is a temporary thing -- eventually any trait will
24 /// be usable with the sugar (or without it).
25 pub paren_sugar: bool,
26
27 pub has_auto_impl: bool,
28
29 /// If `true`, then this trait has the `#[marker]` attribute, indicating
30 /// that all its associated items have defaults that cannot be overridden,
31 /// and thus `impl`s of it are allowed to overlap.
32 pub is_marker: bool,
33
34 /// If `true`, then this trait has the `#[rustc_skip_array_during_method_dispatch]`
35 /// attribute, indicating that editions before 2021 should not consider this trait
36 /// during method dispatch if the receiver is an array.
37 pub skip_array_during_method_dispatch: bool,
38
39 /// Used to determine whether the standard library is allowed to specialize
40 /// on this trait.
41 pub specialization_kind: TraitSpecializationKind,
42
43 /// List of functions from `#[rustc_must_implement_one_of]` attribute one of which
44 /// must be implemented.
45 pub must_implement_one_of: Option<Box<[Ident]>>,
46 }
47
48 /// Whether this trait is treated specially by the standard library
49 /// specialization lint.
50 #[derive(HashStable, PartialEq, Clone, Copy, Encodable, Decodable)]
51 pub enum TraitSpecializationKind {
52 /// The default. Specializing on this trait is not allowed.
53 None,
54 /// Specializing on this trait is allowed because it doesn't have any
55 /// methods. For example `Sized` or `FusedIterator`.
56 /// Applies to traits with the `rustc_unsafe_specialization_marker`
57 /// attribute.
58 Marker,
59 /// Specializing on this trait is allowed because all of the impls of this
60 /// trait are "always applicable". Always applicable means that if
61 /// `X<'x>: T<'y>` for any lifetimes, then `for<'a, 'b> X<'a>: T<'b>`.
62 /// Applies to traits with the `rustc_specialization_trait` attribute.
63 AlwaysApplicable,
64 }
65
66 #[derive(Default, Debug, HashStable)]
67 pub struct TraitImpls {
68 blanket_impls: Vec<DefId>,
69 /// Impls indexed by their simplified self type, for fast lookup.
70 non_blanket_impls: FxIndexMap<SimplifiedType, Vec<DefId>>,
71 }
72
73 impl TraitImpls {
74 pub fn blanket_impls(&self) -> &[DefId] {
75 self.blanket_impls.as_slice()
76 }
77 }
78
79 impl<'tcx> TraitDef {
80 pub fn new(
81 def_id: DefId,
82 unsafety: hir::Unsafety,
83 paren_sugar: bool,
84 has_auto_impl: bool,
85 is_marker: bool,
86 skip_array_during_method_dispatch: bool,
87 specialization_kind: TraitSpecializationKind,
88 must_implement_one_of: Option<Box<[Ident]>>,
89 ) -> TraitDef {
90 TraitDef {
91 def_id,
92 unsafety,
93 paren_sugar,
94 has_auto_impl,
95 is_marker,
96 skip_array_during_method_dispatch,
97 specialization_kind,
98 must_implement_one_of,
99 }
100 }
101
102 pub fn ancestors(
103 &self,
104 tcx: TyCtxt<'tcx>,
105 of_impl: DefId,
106 ) -> Result<specialization_graph::Ancestors<'tcx>, ErrorGuaranteed> {
107 specialization_graph::ancestors(tcx, self.def_id, of_impl)
108 }
109 }
110
111 impl<'tcx> TyCtxt<'tcx> {
112 pub fn for_each_impl<F: FnMut(DefId)>(self, def_id: DefId, mut f: F) {
113 let impls = self.trait_impls_of(def_id);
114
115 for &impl_def_id in impls.blanket_impls.iter() {
116 f(impl_def_id);
117 }
118
119 for v in impls.non_blanket_impls.values() {
120 for &impl_def_id in v {
121 f(impl_def_id);
122 }
123 }
124 }
125
126 /// Iterate over every impl that could possibly match the
127 /// self type `self_ty`.
128 pub fn for_each_relevant_impl<F: FnMut(DefId)>(
129 self,
130 def_id: DefId,
131 self_ty: Ty<'tcx>,
132 mut f: F,
133 ) {
134 let _: Option<()> = self.find_map_relevant_impl(def_id, self_ty, |did| {
135 f(did);
136 None
137 });
138 }
139
140 pub fn non_blanket_impls_for_ty(
141 self,
142 def_id: DefId,
143 self_ty: Ty<'tcx>,
144 ) -> impl Iterator<Item = DefId> + 'tcx {
145 let impls = self.trait_impls_of(def_id);
146 if let Some(simp) = fast_reject::simplify_type(self, self_ty, TreatParams::AsInfer) {
147 if let Some(impls) = impls.non_blanket_impls.get(&simp) {
148 return impls.iter().copied();
149 }
150 }
151
152 [].iter().copied()
153 }
154
155 /// Applies function to every impl that could possibly match the self type `self_ty` and returns
156 /// the first non-none value.
157 pub fn find_map_relevant_impl<T, F: FnMut(DefId) -> Option<T>>(
158 self,
159 def_id: DefId,
160 self_ty: Ty<'tcx>,
161 mut f: F,
162 ) -> Option<T> {
163 // FIXME: This depends on the set of all impls for the trait. That is
164 // unfortunate wrt. incremental compilation.
165 //
166 // If we want to be faster, we could have separate queries for
167 // blanket and non-blanket impls, and compare them separately.
168 let impls = self.trait_impls_of(def_id);
169
170 for &impl_def_id in impls.blanket_impls.iter() {
171 if let result @ Some(_) = f(impl_def_id) {
172 return result;
173 }
174 }
175
176 // Note that we're using `TreatParams::AsPlaceholder` to query `non_blanket_impls` while using
177 // `TreatParams::AsInfer` while actually adding them.
178 //
179 // This way, when searching for some impl for `T: Trait`, we do not look at any impls
180 // whose outer level is not a parameter or projection. Especially for things like
181 // `T: Clone` this is incredibly useful as we would otherwise look at all the impls
182 // of `Clone` for `Option<T>`, `Vec<T>`, `ConcreteType` and so on.
183 if let Some(simp) = fast_reject::simplify_type(self, self_ty, TreatParams::AsPlaceholder) {
184 if let Some(impls) = impls.non_blanket_impls.get(&simp) {
185 for &impl_def_id in impls {
186 if let result @ Some(_) = f(impl_def_id) {
187 return result;
188 }
189 }
190 }
191 } else {
192 for &impl_def_id in impls.non_blanket_impls.values().flatten() {
193 if let result @ Some(_) = f(impl_def_id) {
194 return result;
195 }
196 }
197 }
198
199 None
200 }
201
202 /// Returns an iterator containing all impls
203 pub fn all_impls(self, def_id: DefId) -> impl Iterator<Item = DefId> + 'tcx {
204 let TraitImpls { blanket_impls, non_blanket_impls } = self.trait_impls_of(def_id);
205
206 blanket_impls.iter().chain(non_blanket_impls.iter().flat_map(|(_, v)| v)).cloned()
207 }
208 }
209
210 // Query provider for `trait_impls_of`.
211 pub(super) fn trait_impls_of_provider(tcx: TyCtxt<'_>, trait_id: DefId) -> TraitImpls {
212 let mut impls = TraitImpls::default();
213
214 // Traits defined in the current crate can't have impls in upstream
215 // crates, so we don't bother querying the cstore.
216 if !trait_id.is_local() {
217 for &cnum in tcx.crates(()).iter() {
218 for &(impl_def_id, simplified_self_ty) in
219 tcx.implementations_of_trait((cnum, trait_id)).iter()
220 {
221 if let Some(simplified_self_ty) = simplified_self_ty {
222 impls
223 .non_blanket_impls
224 .entry(simplified_self_ty)
225 .or_default()
226 .push(impl_def_id);
227 } else {
228 impls.blanket_impls.push(impl_def_id);
229 }
230 }
231 }
232 }
233
234 for &impl_def_id in tcx.hir().trait_impls(trait_id) {
235 let impl_def_id = impl_def_id.to_def_id();
236
237 let impl_self_ty = tcx.type_of(impl_def_id);
238 if impl_self_ty.references_error() {
239 continue;
240 }
241
242 if let Some(simplified_self_ty) =
243 fast_reject::simplify_type(tcx, impl_self_ty, TreatParams::AsInfer)
244 {
245 impls.non_blanket_impls.entry(simplified_self_ty).or_default().push(impl_def_id);
246 } else {
247 impls.blanket_impls.push(impl_def_id);
248 }
249 }
250
251 impls
252 }
253
254 // Query provider for `incoherent_impls`.
255 #[instrument(level = "debug", skip(tcx))]
256 pub(super) fn incoherent_impls_provider(tcx: TyCtxt<'_>, simp: SimplifiedType) -> &[DefId] {
257 let mut impls = Vec::new();
258
259 for cnum in iter::once(LOCAL_CRATE).chain(tcx.crates(()).iter().copied()) {
260 for &impl_def_id in tcx.crate_incoherent_impls((cnum, simp)) {
261 impls.push(impl_def_id)
262 }
263 }
264
265 debug!(?impls);
266
267 tcx.arena.alloc_slice(&impls)
268 }