]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_trait_selection/src/traits/specialize/mod.rs
New upstream version 1.58.1+dfsg1
[rustc.git] / compiler / rustc_trait_selection / src / traits / specialize / mod.rs
CommitLineData
0531ce1d
XL
1//! Logic and data structures related to impl specialization, explained in
2//! greater detail below.
3//!
4//! At the moment, this implementation support only the simple "chain" rule:
5//! If any two impls overlap, one must be a strict subset of the other.
6//!
ba9703b0 7//! See the [rustc dev guide] for a bit more detail on how specialization
0531ce1d
XL
8//! fits together with the rest of the trait machinery.
9//!
ba9703b0 10//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/specialization.html
54a0048b 11
0731742a 12pub mod specialization_graph;
74b04a01 13use specialization_graph::GraphExt;
54a0048b 14
74b04a01 15use crate::infer::{InferCtxt, InferOk, TyCtxtInferExt};
9fa01778 16use crate::traits::select::IntercrateAmbiguityCause;
dfeec247 17use crate::traits::{self, coherence, FutureCompatOverlapErrorKind, ObligationCause, TraitEngine};
dfeec247
XL
18use rustc_data_structures::fx::FxHashSet;
19use rustc_errors::struct_span_err;
f9f354fc 20use rustc_hir::def_id::{DefId, LocalDefId};
ba9703b0
XL
21use rustc_middle::lint::LintDiagnosticBuilder;
22use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef};
23use rustc_middle::ty::{self, TyCtxt};
74b04a01 24use rustc_session::lint::builtin::COHERENCE_LEAK_CHECK;
dfeec247
XL
25use rustc_session::lint::builtin::ORDER_DEPENDENT_TRAIT_OBJECTS;
26use rustc_span::DUMMY_SP;
ff7c6d11 27
0731742a 28use super::util::impl_trait_ref_and_oblig;
dfeec247 29use super::{FulfillmentContext, SelectionContext};
60c5eb7d 30
54a0048b 31/// Information pertinent to an overlapping impl error.
0731742a 32#[derive(Debug)]
a7813a04 33pub struct OverlapError {
54a0048b 34 pub with_impl: DefId,
a7813a04 35 pub trait_desc: String,
cc61c64b 36 pub self_desc: Option<String>,
ea8adc8c 37 pub intercrate_ambiguity_causes: Vec<IntercrateAmbiguityCause>,
0731742a 38 pub involves_placeholder: bool,
54a0048b
SL
39}
40
41/// Given a subst for the requested impl, translate it to a subst
42/// appropriate for the actual item definition (whether it be in that impl,
43/// a parent impl, or the trait).
7cac9316 44///
54a0048b
SL
45/// When we have selected one impl, but are actually using item definitions from
46/// a parent impl providing a default, we need a way to translate between the
47/// type parameters of the two impls. Here the `source_impl` is the one we've
9e0c209e
SL
48/// selected, and `source_substs` is a substitution of its generics.
49/// And `target_node` is the impl/trait we're actually going to get the
50/// definition from. The resulting substitution will map from `target_node`'s
51/// generics to `source_impl`'s generics as instantiated by `source_subst`.
54a0048b
SL
52///
53/// For example, consider the following scenario:
54///
55/// ```rust
56/// trait Foo { ... }
57/// impl<T, U> Foo for (T, U) { ... } // target impl
58/// impl<V> Foo for (V, V) { ... } // source impl
59/// ```
60///
61/// Suppose we have selected "source impl" with `V` instantiated with `u32`.
62/// This function will produce a substitution with `T` and `U` both mapping to `u32`.
63///
9fa01778 64/// where-clauses add some trickiness here, because they can be used to "define"
54a0048b
SL
65/// an argument indirectly:
66///
67/// ```rust
68/// impl<'a, I, T: 'a> Iterator for Cloned<I>
9fa01778 69/// where I: Iterator<Item = &'a T>, T: Clone
54a0048b
SL
70/// ```
71///
72/// In a case like this, the substitution for `T` is determined indirectly,
73/// through associated type projection. We deal with such cases by using
74/// *fulfillment* to relate the two impls, requiring that all projections are
75/// resolved.
dc9dc135
XL
76pub fn translate_substs<'a, 'tcx>(
77 infcx: &InferCtxt<'a, 'tcx>,
78 param_env: ty::ParamEnv<'tcx>,
79 source_impl: DefId,
80 source_substs: SubstsRef<'tcx>,
81 target_node: specialization_graph::Node,
82) -> SubstsRef<'tcx> {
dfeec247
XL
83 debug!(
84 "translate_substs({:?}, {:?}, {:?}, {:?})",
85 param_env, source_impl, source_substs, target_node
86 );
87 let source_trait_ref =
88 infcx.tcx.impl_trait_ref(source_impl).unwrap().subst(infcx.tcx, &source_substs);
54a0048b 89
b7449926 90 // translate the Self and Param parts of the substitution, since those
54a0048b
SL
91 // vary across impls
92 let target_substs = match target_node {
93 specialization_graph::Node::Impl(target_impl) => {
3b2f2976 94 // no need to translate if we're targeting the impl we started with
54a0048b
SL
95 if source_impl == target_impl {
96 return source_substs;
97 }
98
dfeec247
XL
99 fulfill_implication(infcx, param_env, source_trait_ref, target_impl).unwrap_or_else(
100 |_| {
101 bug!(
102 "When translating substitutions for specialization, the expected \
74b04a01 103 specialization failed to hold"
dfeec247
XL
104 )
105 },
106 )
54a0048b 107 }
a7813a04 108 specialization_graph::Node::Trait(..) => source_trait_ref.substs,
54a0048b
SL
109 };
110
111 // directly inherent the method generics, since those do not vary across impls
9e0c209e
SL
112 source_substs.rebase_onto(infcx.tcx, source_impl, target_substs)
113}
114
9fa01778 115/// Is `impl1` a specialization of `impl2`?
54a0048b
SL
116///
117/// Specialization is determined by the sets of types to which the impls apply;
9fa01778 118/// `impl1` specializes `impl2` if it applies to a subset of the types `impl2` applies
54a0048b 119/// to.
dfeec247 120pub(super) fn specializes(tcx: TyCtxt<'_>, (impl1_def_id, impl2_def_id): (DefId, DefId)) -> bool {
9e0c209e
SL
121 debug!("specializes({:?}, {:?})", impl1_def_id, impl2_def_id);
122
54a0048b
SL
123 // The feature gate should prevent introducing new specializations, but not
124 // taking advantage of upstream ones.
ba9703b0
XL
125 let features = tcx.features();
126 let specialization_enabled = features.specialization || features.min_specialization;
127 if !specialization_enabled && (impl1_def_id.is_local() || impl2_def_id.is_local()) {
54a0048b
SL
128 return false;
129 }
130
131 // We determine whether there's a subset relationship by:
132 //
f035d41b 133 // - replacing bound vars with placeholders in impl1,
54a0048b
SL
134 // - assuming the where clauses for impl1,
135 // - instantiating impl2 with fresh inference variables,
136 // - unifying,
137 // - attempting to prove the where clauses for impl2
138 //
139 // The last three steps are encapsulated in `fulfill_implication`.
140 //
141 // See RFC 1210 for more details and justification.
142
0731742a 143 // Currently we do not allow e.g., a negative impl to specialize a positive one
7cac9316 144 if tcx.impl_polarity(impl1_def_id) != tcx.impl_polarity(impl2_def_id) {
54a0048b
SL
145 return false;
146 }
147
0bf4aa26 148 // create a parameter environment corresponding to a (placeholder) instantiation of impl1
7cac9316
XL
149 let penv = tcx.param_env(impl1_def_id);
150 let impl1_trait_ref = tcx.impl_trait_ref(impl1_def_id).unwrap();
54a0048b 151
94222f64 152 // Create an infcx, taking the predicates of impl1 as assumptions:
ea8adc8c 153 tcx.infer_ctxt().enter(|infcx| {
c30ab7b3
SL
154 // Normalize the trait reference. The WF rules ought to ensure
155 // that this always succeeds.
dfeec247
XL
156 let impl1_trait_ref = match traits::fully_normalize(
157 &infcx,
158 FulfillmentContext::new(),
159 ObligationCause::dummy(),
160 penv,
fc512014 161 impl1_trait_ref,
dfeec247
XL
162 ) {
163 Ok(impl1_trait_ref) => impl1_trait_ref,
164 Err(err) => {
165 bug!("failed to fully normalize {:?}: {:?}", impl1_trait_ref, err);
166 }
167 };
a7813a04 168
a7813a04 169 // Attempt to prove that impl2 applies, given all of the above.
7cac9316 170 fulfill_implication(&infcx, penv, impl1_trait_ref, impl2_def_id).is_ok()
ea8adc8c 171 })
54a0048b
SL
172}
173
174/// Attempt to fulfill all obligations of `target_impl` after unification with
175/// `source_trait_ref`. If successful, returns a substitution for *all* the
176/// generics of `target_impl`, including both those needed to unify with
177/// `source_trait_ref` and those whose identity is determined via a where
178/// clause in the impl.
dc9dc135
XL
179fn fulfill_implication<'a, 'tcx>(
180 infcx: &InferCtxt<'a, 'tcx>,
181 param_env: ty::ParamEnv<'tcx>,
182 source_trait_ref: ty::TraitRef<'tcx>,
183 target_impl: DefId,
184) -> Result<SubstsRef<'tcx>, ()> {
dfeec247
XL
185 debug!(
186 "fulfill_implication({:?}, trait_ref={:?} |- {:?} applies)",
187 param_env, source_trait_ref, target_impl
188 );
0731742a 189
3157f602 190 let selcx = &mut SelectionContext::new(&infcx);
9e0c209e 191 let target_substs = infcx.fresh_substs_for_item(DUMMY_SP, target_impl);
ba9703b0 192 let (target_trait_ref, obligations) =
dfeec247 193 impl_trait_ref_and_oblig(selcx, param_env, target_impl, target_substs);
3157f602
XL
194
195 // do the impls unify? If not, no specialization.
ba9703b0
XL
196 let more_obligations =
197 match infcx.at(&ObligationCause::dummy(), param_env).eq(source_trait_ref, target_trait_ref)
198 {
199 Ok(InferOk { obligations, .. }) => obligations,
200 Err(_) => {
201 debug!(
202 "fulfill_implication: {:?} does not unify with {:?}",
203 source_trait_ref, target_trait_ref
204 );
205 return Err(());
206 }
207 };
54a0048b 208
3157f602
XL
209 // attempt to prove all of the predicates for impl2 given those for impl1
210 // (which are packed up in penv)
54a0048b 211
cc61c64b 212 infcx.save_and_restore_in_snapshot_flag(|infcx| {
ff7c6d11
XL
213 // If we came from `translate_substs`, we already know that the
214 // predicates for our impl hold (after all, we know that a more
215 // specialized impl holds, so our impl must hold too), and
216 // we only want to process the projections to determine the
217 // the types in our substs using RFC 447, so we can safely
218 // ignore region obligations, which allows us to avoid threading
219 // a node-id to assign them with.
220 //
221 // If we came from specialization graph construction, then
222 // we already make a mockery out of the region system, so
223 // why not ignore them a bit earlier?
224 let mut fulfill_cx = FulfillmentContext::new_ignoring_regions();
ba9703b0 225 for oblig in obligations.chain(more_obligations) {
9e0c209e
SL
226 fulfill_cx.register_predicate_obligation(&infcx, oblig);
227 }
3c0e092e
XL
228 match fulfill_cx.select_all_or_error(infcx).as_slice() {
229 [] => {
230 debug!(
231 "fulfill_implication: an impl for {:?} specializes {:?}",
232 source_trait_ref, target_trait_ref
233 );
234
235 // Now resolve the *substitution* we built for the target earlier, replacing
236 // the inference variables inside with whatever we got from fulfillment.
237 Ok(infcx.resolve_vars_if_possible(target_substs))
238 }
239 errors => {
9e0c209e 240 // no dice!
dfeec247
XL
241 debug!(
242 "fulfill_implication: for impls on {:?} and {:?}, \
74b04a01 243 could not fulfill: {:?} given {:?}",
f035d41b
XL
244 source_trait_ref,
245 target_trait_ref,
246 errors,
247 param_env.caller_bounds()
dfeec247 248 );
9e0c209e
SL
249 Err(())
250 }
9e0c209e
SL
251 }
252 })
54a0048b 253}
a7813a04 254
7cac9316 255// Query provider for `specialization_graph_of`.
416331ca
XL
256pub(super) fn specialization_graph_provider(
257 tcx: TyCtxt<'_>,
0731742a 258 trait_id: DefId,
f9f354fc 259) -> specialization_graph::Graph {
7cac9316
XL
260 let mut sg = specialization_graph::Graph::new();
261
ba9703b0 262 let mut trait_impls: Vec<_> = tcx.all_impls(trait_id).collect();
7cac9316
XL
263
264 // The coherence checking implementation seems to rely on impls being
265 // iterated over (roughly) in definition order, so we are sorting by
0731742a
XL
266 // negated `CrateNum` (so remote definitions are visited first) and then
267 // by a flattened version of the `DefIndex`.
dfeec247
XL
268 trait_impls
269 .sort_unstable_by_key(|def_id| (-(def_id.krate.as_u32() as i64), def_id.index.index()));
7cac9316
XL
270
271 for impl_def_id in trait_impls {
f9f354fc 272 if let Some(impl_def_id) = impl_def_id.as_local() {
7cac9316 273 // This is where impl overlap checking happens:
f9f354fc 274 let insert_result = sg.insert(tcx, impl_def_id.to_def_id());
7cac9316 275 // Report error if there was one.
ff7c6d11 276 let (overlap, used_to_be_allowed) = match insert_result {
0731742a
XL
277 Err(overlap) => (Some(overlap), None),
278 Ok(Some(overlap)) => (Some(overlap.error), Some(overlap.kind)),
dfeec247 279 Ok(None) => (None, None),
ff7c6d11
XL
280 };
281
282 if let Some(overlap) = overlap {
ba9703b0 283 report_overlap_conflict(tcx, overlap, impl_def_id, used_to_be_allowed, &mut sg);
7cac9316
XL
284 }
285 } else {
286 let parent = tcx.impl_parent(impl_def_id).unwrap_or(trait_id);
287 sg.record_impl_from_cstore(tcx, parent, impl_def_id)
288 }
289 }
290
f9f354fc 291 sg
7cac9316 292}
abe05a73 293
3c0e092e
XL
294// This function is only used when
295// encountering errors and inlining
296// it negatively impacts perf.
297#[cold]
298#[inline(never)]
ba9703b0
XL
299fn report_overlap_conflict(
300 tcx: TyCtxt<'_>,
301 overlap: OverlapError,
f9f354fc 302 impl_def_id: LocalDefId,
ba9703b0
XL
303 used_to_be_allowed: Option<FutureCompatOverlapErrorKind>,
304 sg: &mut specialization_graph::Graph,
305) {
f9f354fc 306 let impl_polarity = tcx.impl_polarity(impl_def_id.to_def_id());
ba9703b0
XL
307 let other_polarity = tcx.impl_polarity(overlap.with_impl);
308 match (impl_polarity, other_polarity) {
309 (ty::ImplPolarity::Negative, ty::ImplPolarity::Positive) => {
310 report_negative_positive_conflict(
311 tcx,
312 &overlap,
313 impl_def_id,
f9f354fc 314 impl_def_id.to_def_id(),
ba9703b0
XL
315 overlap.with_impl,
316 sg,
317 );
318 }
319
320 (ty::ImplPolarity::Positive, ty::ImplPolarity::Negative) => {
321 report_negative_positive_conflict(
322 tcx,
323 &overlap,
324 impl_def_id,
325 overlap.with_impl,
f9f354fc 326 impl_def_id.to_def_id(),
ba9703b0
XL
327 sg,
328 );
329 }
330
331 _ => {
332 report_conflicting_impls(tcx, overlap, impl_def_id, used_to_be_allowed, sg);
333 }
334 }
335}
336
337fn report_negative_positive_conflict(
338 tcx: TyCtxt<'_>,
339 overlap: &OverlapError,
f9f354fc 340 local_impl_def_id: LocalDefId,
ba9703b0
XL
341 negative_impl_def_id: DefId,
342 positive_impl_def_id: DefId,
343 sg: &mut specialization_graph::Graph,
344) {
f9f354fc
XL
345 let impl_span = tcx
346 .sess
347 .source_map()
348 .guess_head_span(tcx.span_of_impl(local_impl_def_id.to_def_id()).unwrap());
ba9703b0
XL
349
350 let mut err = struct_span_err!(
351 tcx.sess,
352 impl_span,
353 E0751,
354 "found both positive and negative implementation of trait `{}`{}:",
355 overlap.trait_desc,
6a06907d 356 overlap.self_desc.clone().map_or_else(String::new, |ty| format!(" for type `{}`", ty))
ba9703b0
XL
357 );
358
359 match tcx.span_of_impl(negative_impl_def_id) {
360 Ok(span) => {
361 err.span_label(
362 tcx.sess.source_map().guess_head_span(span),
363 "negative implementation here".to_string(),
364 );
365 }
366 Err(cname) => {
367 err.note(&format!("negative implementation in crate `{}`", cname));
368 }
369 }
370
371 match tcx.span_of_impl(positive_impl_def_id) {
372 Ok(span) => {
373 err.span_label(
374 tcx.sess.source_map().guess_head_span(span),
375 "positive implementation here".to_string(),
376 );
377 }
378 Err(cname) => {
379 err.note(&format!("positive implementation in crate `{}`", cname));
380 }
381 }
382
383 sg.has_errored = true;
384 err.emit();
385}
386
387fn report_conflicting_impls(
388 tcx: TyCtxt<'_>,
389 overlap: OverlapError,
f9f354fc 390 impl_def_id: LocalDefId,
ba9703b0
XL
391 used_to_be_allowed: Option<FutureCompatOverlapErrorKind>,
392 sg: &mut specialization_graph::Graph,
393) {
f9f354fc
XL
394 let impl_span =
395 tcx.sess.source_map().guess_head_span(tcx.span_of_impl(impl_def_id.to_def_id()).unwrap());
ba9703b0
XL
396
397 // Work to be done after we've built the DiagnosticBuilder. We have to define it
398 // now because the struct_lint methods don't return back the DiagnosticBuilder
399 // that's passed in.
400 let decorate = |err: LintDiagnosticBuilder<'_>| {
401 let msg = format!(
cdc7bbd5 402 "conflicting implementations of trait `{}`{}{}",
ba9703b0 403 overlap.trait_desc,
6a06907d
XL
404 overlap
405 .self_desc
406 .clone()
407 .map_or_else(String::new, |ty| { format!(" for type `{}`", ty) }),
ba9703b0 408 match used_to_be_allowed {
cdc7bbd5 409 Some(FutureCompatOverlapErrorKind::Issue33140) => ": (E0119)",
ba9703b0
XL
410 _ => "",
411 }
412 );
413 let mut err = err.build(&msg);
414 match tcx.span_of_impl(overlap.with_impl) {
415 Ok(span) => {
416 err.span_label(
417 tcx.sess.source_map().guess_head_span(span),
418 "first implementation here".to_string(),
419 );
420
421 err.span_label(
422 impl_span,
423 format!(
424 "conflicting implementation{}",
6a06907d 425 overlap.self_desc.map_or_else(String::new, |ty| format!(" for `{}`", ty))
ba9703b0
XL
426 ),
427 );
428 }
429 Err(cname) => {
430 let msg = match to_pretty_impl_header(tcx, overlap.with_impl) {
431 Some(s) => format!("conflicting implementation in crate `{}`:\n- {}", cname, s),
432 None => format!("conflicting implementation in crate `{}`", cname),
433 };
434 err.note(&msg);
435 }
436 }
437
438 for cause in &overlap.intercrate_ambiguity_causes {
439 cause.add_intercrate_ambiguity_hint(&mut err);
440 }
441
442 if overlap.involves_placeholder {
443 coherence::add_placeholder_note(&mut err);
444 }
445 err.emit()
446 };
447
448 match used_to_be_allowed {
449 None => {
450 sg.has_errored = true;
3c0e092e
XL
451 if overlap.with_impl.is_local() || !tcx.orphan_check_crate(()).contains(&impl_def_id) {
452 let err = struct_span_err!(tcx.sess, impl_span, E0119, "");
453 decorate(LintDiagnosticBuilder::new(err));
454 } else {
455 tcx.sess.delay_span_bug(impl_span, "impl should have failed the orphan check");
456 }
ba9703b0
XL
457 }
458 Some(kind) => {
459 let lint = match kind {
460 FutureCompatOverlapErrorKind::Issue33140 => ORDER_DEPENDENT_TRAIT_OBJECTS,
461 FutureCompatOverlapErrorKind::LeakCheck => COHERENCE_LEAK_CHECK,
462 };
463 tcx.struct_span_lint_hir(
464 lint,
3dfed10e 465 tcx.hir().local_def_id_to_hir_id(impl_def_id),
ba9703b0
XL
466 impl_span,
467 decorate,
468 )
469 }
470 };
471}
472
abe05a73
XL
473/// Recovers the "impl X for Y" signature from `impl_def_id` and returns it as a
474/// string.
3c0e092e 475crate fn to_pretty_impl_header(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Option<String> {
abe05a73
XL
476 use std::fmt::Write;
477
ba9703b0 478 let trait_ref = tcx.impl_trait_ref(impl_def_id)?;
abe05a73
XL
479 let mut w = "impl".to_owned();
480
532ac7d7 481 let substs = InternalSubsts::identity_for_item(tcx, impl_def_id);
abe05a73
XL
482
483 // FIXME: Currently only handles ?Sized.
484 // Needs to support ?Move and ?DynSized when they are implemented.
485 let mut types_without_default_bounds = FxHashSet::default();
486 let sized_trait = tcx.lang_items().sized_trait();
487
488 if !substs.is_noop() {
489 types_without_default_bounds.extend(substs.types());
490 w.push('<');
dfeec247
XL
491 w.push_str(
492 &substs
493 .iter()
494 .map(|k| k.to_string())
495 .filter(|k| k != "'_")
496 .collect::<Vec<_>>()
497 .join(", "),
498 );
abe05a73
XL
499 w.push('>');
500 }
501
60c5eb7d 502 write!(w, " {} for {}", trait_ref.print_only_trait_path(), tcx.type_of(impl_def_id)).unwrap();
abe05a73
XL
503
504 // The predicates will contain default bounds like `T: Sized`. We need to
505 // remove these bounds, and add `T: ?Sized` to any untouched type parameters.
e74abb32 506 let predicates = tcx.predicates_of(impl_def_id).predicates;
dfeec247
XL
507 let mut pretty_predicates =
508 Vec::with_capacity(predicates.len() + types_without_default_bounds.len());
0bf4aa26
XL
509
510 for (p, _) in predicates {
abe05a73 511 if let Some(poly_trait_ref) = p.to_opt_poly_trait_ref() {
fc512014
XL
512 if Some(poly_trait_ref.value.def_id()) == sized_trait {
513 types_without_default_bounds.remove(poly_trait_ref.value.self_ty().skip_binder());
abe05a73
XL
514 continue;
515 }
516 }
517 pretty_predicates.push(p.to_string());
518 }
0bf4aa26 519
dfeec247
XL
520 pretty_predicates
521 .extend(types_without_default_bounds.iter().map(|ty| format!("{}: ?Sized", ty)));
0bf4aa26 522
abe05a73
XL
523 if !pretty_predicates.is_empty() {
524 write!(w, "\n where {}", pretty_predicates.join(", ")).unwrap();
525 }
526
527 w.push(';');
528 Some(w)
529}