summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_trait_selection/src/traits/specialize
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:18:25 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:18:25 +0000
commit5363f350887b1e5b5dd21a86f88c8af9d7fea6da (patch)
tree35ca005eb6e0e9a1ba3bb5dbc033209ad445dc17 /compiler/rustc_trait_selection/src/traits/specialize
parentAdding debian version 1.66.0+dfsg1-1. (diff)
downloadrustc-5363f350887b1e5b5dd21a86f88c8af9d7fea6da.tar.xz
rustc-5363f350887b1e5b5dd21a86f88c8af9d7fea6da.zip
Merging upstream version 1.67.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_trait_selection/src/traits/specialize')
-rw-r--r--compiler/rustc_trait_selection/src/traits/specialize/mod.rs137
-rw-r--r--compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs68
2 files changed, 101 insertions, 104 deletions
diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
index c89165858..a251a508b 100644
--- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
@@ -15,11 +15,13 @@ use specialization_graph::GraphExt;
use crate::errors::NegativePositiveConflict;
use crate::infer::{InferCtxt, InferOk, TyCtxtInferExt};
use crate::traits::select::IntercrateAmbiguityCause;
-use crate::traits::{self, coherence, FutureCompatOverlapErrorKind, ObligationCause};
-use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
-use rustc_errors::{struct_span_err, DiagnosticBuilder, EmissionGuarantee};
+use crate::traits::{
+ self, coherence, FutureCompatOverlapErrorKind, ObligationCause, ObligationCtxt,
+};
+use rustc_data_structures::fx::FxIndexSet;
+use rustc_errors::{error_code, DelayDm, Diagnostic};
use rustc_hir::def_id::{DefId, LocalDefId};
-use rustc_middle::ty::{self, ImplSubject, TyCtxt};
+use rustc_middle::ty::{self, ImplSubject, Ty, TyCtxt};
use rustc_middle::ty::{InternalSubsts, SubstsRef};
use rustc_session::lint::builtin::COHERENCE_LEAK_CHECK;
use rustc_session::lint::builtin::ORDER_DEPENDENT_TRAIT_OBJECTS;
@@ -30,10 +32,10 @@ use super::SelectionContext;
/// Information pertinent to an overlapping impl error.
#[derive(Debug)]
-pub struct OverlapError {
+pub struct OverlapError<'tcx> {
pub with_impl: DefId,
- pub trait_desc: String,
- pub self_desc: Option<String>,
+ pub trait_ref: ty::TraitRef<'tcx>,
+ pub self_ty: Option<Ty<'tcx>>,
pub intercrate_ambiguity_causes: FxIndexSet<IntercrateAmbiguityCause>,
pub involves_placeholder: bool,
}
@@ -200,39 +202,35 @@ fn fulfill_implication<'tcx>(
return Err(());
};
+ // Needs to be `in_snapshot` because this function is used to rebase
+ // substitutions, which may happen inside of a select within a probe.
+ let ocx = ObligationCtxt::new_in_snapshot(infcx);
// attempt to prove all of the predicates for impl2 given those for impl1
// (which are packed up in penv)
+ ocx.register_obligations(obligations.chain(more_obligations));
- infcx.save_and_restore_in_snapshot_flag(|infcx| {
- let errors = traits::fully_solve_obligations(&infcx, obligations.chain(more_obligations));
- match &errors[..] {
- [] => {
- debug!(
- "fulfill_implication: an impl for {:?} specializes {:?}",
- source_trait, target_trait
- );
+ let errors = ocx.select_all_or_error();
+ if !errors.is_empty() {
+ // no dice!
+ debug!(
+ "fulfill_implication: for impls on {:?} and {:?}, \
+ could not fulfill: {:?} given {:?}",
+ source_trait,
+ target_trait,
+ errors,
+ param_env.caller_bounds()
+ );
+ return Err(());
+ }
- // Now resolve the *substitution* we built for the target earlier, replacing
- // the inference variables inside with whatever we got from fulfillment.
- Ok(infcx.resolve_vars_if_possible(target_substs))
- }
- errors => {
- // no dice!
- debug!(
- "fulfill_implication: for impls on {:?} and {:?}, \
- could not fulfill: {:?} given {:?}",
- source_trait,
- target_trait,
- errors,
- param_env.caller_bounds()
- );
- Err(())
- }
- }
- })
+ debug!("fulfill_implication: an impl for {:?} specializes {:?}", source_trait, target_trait);
+
+ // Now resolve the *substitution* we built for the target earlier, replacing
+ // the inference variables inside with whatever we got from fulfillment.
+ Ok(infcx.resolve_vars_if_possible(target_substs))
}
-// Query provider for `specialization_graph_of`.
+/// Query provider for `specialization_graph_of`.
pub(super) fn specialization_graph_provider(
tcx: TyCtxt<'_>,
trait_id: DefId,
@@ -277,9 +275,9 @@ pub(super) fn specialization_graph_provider(
// it negatively impacts perf.
#[cold]
#[inline(never)]
-fn report_overlap_conflict(
- tcx: TyCtxt<'_>,
- overlap: OverlapError,
+fn report_overlap_conflict<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ overlap: OverlapError<'tcx>,
impl_def_id: LocalDefId,
used_to_be_allowed: Option<FutureCompatOverlapErrorKind>,
sg: &mut specialization_graph::Graph,
@@ -315,9 +313,9 @@ fn report_overlap_conflict(
}
}
-fn report_negative_positive_conflict(
- tcx: TyCtxt<'_>,
- overlap: &OverlapError,
+fn report_negative_positive_conflict<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ overlap: &OverlapError<'tcx>,
local_impl_def_id: LocalDefId,
negative_impl_def_id: DefId,
positive_impl_def_id: DefId,
@@ -325,17 +323,17 @@ fn report_negative_positive_conflict(
) {
let mut err = tcx.sess.create_err(NegativePositiveConflict {
impl_span: tcx.def_span(local_impl_def_id),
- trait_desc: &overlap.trait_desc,
- self_desc: &overlap.self_desc,
+ trait_desc: overlap.trait_ref,
+ self_ty: overlap.self_ty,
negative_impl_span: tcx.span_of_impl(negative_impl_def_id),
positive_impl_span: tcx.span_of_impl(positive_impl_def_id),
});
sg.has_errored = Some(err.emit());
}
-fn report_conflicting_impls(
- tcx: TyCtxt<'_>,
- overlap: OverlapError,
+fn report_conflicting_impls<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ overlap: OverlapError<'tcx>,
impl_def_id: LocalDefId,
used_to_be_allowed: Option<FutureCompatOverlapErrorKind>,
sg: &mut specialization_graph::Graph,
@@ -345,12 +343,12 @@ fn report_conflicting_impls(
// Work to be done after we've built the DiagnosticBuilder. We have to define it
// now because the struct_lint methods don't return back the DiagnosticBuilder
// that's passed in.
- fn decorate<'a, 'b, G: EmissionGuarantee>(
- tcx: TyCtxt<'_>,
- overlap: OverlapError,
+ fn decorate<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ overlap: &OverlapError<'tcx>,
impl_span: Span,
- err: &'b mut DiagnosticBuilder<'a, G>,
- ) -> &'b mut DiagnosticBuilder<'a, G> {
+ err: &mut Diagnostic,
+ ) {
match tcx.span_of_impl(overlap.with_impl) {
Ok(span) => {
err.span_label(span, "first implementation here");
@@ -359,7 +357,7 @@ fn report_conflicting_impls(
impl_span,
format!(
"conflicting implementation{}",
- overlap.self_desc.map_or_else(String::new, |ty| format!(" for `{}`", ty))
+ overlap.self_ty.map_or_else(String::new, |ty| format!(" for `{}`", ty))
),
);
}
@@ -381,26 +379,28 @@ fn report_conflicting_impls(
if overlap.involves_placeholder {
coherence::add_placeholder_note(err);
}
- err
}
- let msg = format!(
- "conflicting implementations of trait `{}`{}{}",
- overlap.trait_desc,
- overlap.self_desc.as_deref().map_or_else(String::new, |ty| format!(" for type `{ty}`")),
- match used_to_be_allowed {
- Some(FutureCompatOverlapErrorKind::Issue33140) => ": (E0119)",
- _ => "",
- }
- );
+ let msg = DelayDm(|| {
+ format!(
+ "conflicting implementations of trait `{}`{}{}",
+ overlap.trait_ref.print_only_trait_path(),
+ overlap.self_ty.map_or_else(String::new, |ty| format!(" for type `{ty}`")),
+ match used_to_be_allowed {
+ Some(FutureCompatOverlapErrorKind::Issue33140) => ": (E0119)",
+ _ => "",
+ }
+ )
+ });
match used_to_be_allowed {
None => {
let reported = if overlap.with_impl.is_local()
|| tcx.orphan_check_impl(impl_def_id).is_ok()
{
- let mut err = struct_span_err!(tcx.sess, impl_span, E0119, "{msg}",);
- decorate(tcx, overlap, impl_span, &mut err);
+ let mut err = tcx.sess.struct_span_err(impl_span, msg);
+ err.code(error_code!(E0119));
+ decorate(tcx, &overlap, impl_span, &mut err);
Some(err.emit())
} else {
Some(tcx.sess.delay_span_bug(impl_span, "impl should have failed the orphan check"))
@@ -417,7 +417,10 @@ fn report_conflicting_impls(
tcx.hir().local_def_id_to_hir_id(impl_def_id),
impl_span,
msg,
- |err| decorate(tcx, overlap, impl_span, err),
+ |err| {
+ decorate(tcx, &overlap, impl_span, err);
+ err
+ },
);
}
};
@@ -435,7 +438,7 @@ pub(crate) fn to_pretty_impl_header(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Opti
// FIXME: Currently only handles ?Sized.
// Needs to support ?Move and ?DynSized when they are implemented.
- let mut types_without_default_bounds = FxHashSet::default();
+ let mut types_without_default_bounds = FxIndexSet::default();
let sized_trait = tcx.lang_items().sized_trait();
if !substs.is_empty() {
@@ -473,7 +476,9 @@ pub(crate) fn to_pretty_impl_header(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Opti
trait_pred
});
- p = tcx.mk_predicate(new_trait_pred.map_bound(ty::PredicateKind::Trait))
+ p = tcx.mk_predicate(
+ new_trait_pred.map_bound(|p| ty::PredicateKind::Clause(ty::Clause::Trait(p))),
+ )
}
}
pretty_predicates.push(p.to_string());
diff --git a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
index 63f89a33e..4546c9533 100644
--- a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
+++ b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
@@ -3,7 +3,6 @@ use super::OverlapError;
use crate::traits;
use rustc_hir::def_id::DefId;
use rustc_middle::ty::fast_reject::{self, SimplifiedType, TreatParams};
-use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::{self, TyCtxt, TypeVisitable};
pub use rustc_middle::traits::specialization_graph::*;
@@ -15,15 +14,15 @@ pub enum FutureCompatOverlapErrorKind {
}
#[derive(Debug)]
-pub struct FutureCompatOverlapError {
- pub error: OverlapError,
+pub struct FutureCompatOverlapError<'tcx> {
+ pub error: OverlapError<'tcx>,
pub kind: FutureCompatOverlapErrorKind,
}
/// The result of attempting to insert an impl into a group of children.
-enum Inserted {
+enum Inserted<'tcx> {
/// The impl was inserted as a new child in this group of children.
- BecameNewSibling(Option<FutureCompatOverlapError>),
+ BecameNewSibling(Option<FutureCompatOverlapError<'tcx>>),
/// The impl should replace existing impls [X1, ..], because the impl specializes X1, X2, etc.
ReplaceChildren(Vec<DefId>),
@@ -42,12 +41,12 @@ trait ChildrenExt<'tcx> {
impl_def_id: DefId,
simplified_self: Option<SimplifiedType>,
overlap_mode: OverlapMode,
- ) -> Result<Inserted, OverlapError>;
+ ) -> Result<Inserted<'tcx>, OverlapError<'tcx>>;
}
-impl ChildrenExt<'_> for Children {
+impl<'tcx> ChildrenExt<'tcx> for Children {
/// Insert an impl into this set of children without comparing to any existing impls.
- fn insert_blindly(&mut self, tcx: TyCtxt<'_>, impl_def_id: DefId) {
+ fn insert_blindly(&mut self, tcx: TyCtxt<'tcx>, impl_def_id: DefId) {
let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
if let Some(st) = fast_reject::simplify_type(tcx, trait_ref.self_ty(), TreatParams::AsInfer)
{
@@ -62,7 +61,7 @@ impl ChildrenExt<'_> for Children {
/// Removes an impl from this set of children. Used when replacing
/// an impl with a parent. The impl must be present in the list of
/// children already.
- fn remove_existing(&mut self, tcx: TyCtxt<'_>, impl_def_id: DefId) {
+ fn remove_existing(&mut self, tcx: TyCtxt<'tcx>, impl_def_id: DefId) {
let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
let vec: &mut Vec<DefId>;
if let Some(st) = fast_reject::simplify_type(tcx, trait_ref.self_ty(), TreatParams::AsInfer)
@@ -82,11 +81,11 @@ impl ChildrenExt<'_> for Children {
/// specialization relationships.
fn insert(
&mut self,
- tcx: TyCtxt<'_>,
+ tcx: TyCtxt<'tcx>,
impl_def_id: DefId,
simplified_self: Option<SimplifiedType>,
overlap_mode: OverlapMode,
- ) -> Result<Inserted, OverlapError> {
+ ) -> Result<Inserted<'tcx>, OverlapError<'tcx>> {
let mut last_lint = None;
let mut replace_children = Vec::new();
@@ -103,30 +102,23 @@ impl ChildrenExt<'_> for Children {
impl_def_id, simplified_self, possible_sibling,
);
- let create_overlap_error = |overlap: traits::coherence::OverlapResult<'_>| {
+ let create_overlap_error = |overlap: traits::coherence::OverlapResult<'tcx>| {
let trait_ref = overlap.impl_header.trait_ref.unwrap();
let self_ty = trait_ref.self_ty();
- // FIXME: should postpone string formatting until we decide to actually emit.
- with_no_trimmed_paths!({
- OverlapError {
- with_impl: possible_sibling,
- trait_desc: trait_ref.print_only_trait_path().to_string(),
- // Only report the `Self` type if it has at least
- // some outer concrete shell; otherwise, it's
- // not adding much information.
- self_desc: if self_ty.has_concrete_skeleton() {
- Some(self_ty.to_string())
- } else {
- None
- },
- intercrate_ambiguity_causes: overlap.intercrate_ambiguity_causes,
- involves_placeholder: overlap.involves_placeholder,
- }
- })
+ OverlapError {
+ with_impl: possible_sibling,
+ trait_ref,
+ // Only report the `Self` type if it has at least
+ // some outer concrete shell; otherwise, it's
+ // not adding much information.
+ self_ty: if self_ty.has_concrete_skeleton() { Some(self_ty) } else { None },
+ intercrate_ambiguity_causes: overlap.intercrate_ambiguity_causes,
+ involves_placeholder: overlap.involves_placeholder,
+ }
};
- let report_overlap_error = |overlap: traits::coherence::OverlapResult<'_>,
+ let report_overlap_error = |overlap: traits::coherence::OverlapResult<'tcx>,
last_lint: &mut _| {
// Found overlap, but no specialization; error out or report future-compat warning.
@@ -255,31 +247,31 @@ where
}
}
-pub trait GraphExt {
+pub trait GraphExt<'tcx> {
/// Insert a local impl into the specialization graph. If an existing impl
/// conflicts with it (has overlap, but neither specializes the other),
/// information about the area of overlap is returned in the `Err`.
fn insert(
&mut self,
- tcx: TyCtxt<'_>,
+ tcx: TyCtxt<'tcx>,
impl_def_id: DefId,
overlap_mode: OverlapMode,
- ) -> Result<Option<FutureCompatOverlapError>, OverlapError>;
+ ) -> Result<Option<FutureCompatOverlapError<'tcx>>, OverlapError<'tcx>>;
/// Insert cached metadata mapping from a child impl back to its parent.
- fn record_impl_from_cstore(&mut self, tcx: TyCtxt<'_>, parent: DefId, child: DefId);
+ fn record_impl_from_cstore(&mut self, tcx: TyCtxt<'tcx>, parent: DefId, child: DefId);
}
-impl GraphExt for Graph {
+impl<'tcx> GraphExt<'tcx> for Graph {
/// Insert a local impl into the specialization graph. If an existing impl
/// conflicts with it (has overlap, but neither specializes the other),
/// information about the area of overlap is returned in the `Err`.
fn insert(
&mut self,
- tcx: TyCtxt<'_>,
+ tcx: TyCtxt<'tcx>,
impl_def_id: DefId,
overlap_mode: OverlapMode,
- ) -> Result<Option<FutureCompatOverlapError>, OverlapError> {
+ ) -> Result<Option<FutureCompatOverlapError<'tcx>>, OverlapError<'tcx>> {
assert!(impl_def_id.is_local());
let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
@@ -376,7 +368,7 @@ impl GraphExt for Graph {
}
/// Insert cached metadata mapping from a child impl back to its parent.
- fn record_impl_from_cstore(&mut self, tcx: TyCtxt<'_>, parent: DefId, child: DefId) {
+ fn record_impl_from_cstore(&mut self, tcx: TyCtxt<'tcx>, parent: DefId, child: DefId) {
if self.parent.insert(child, parent).is_some() {
bug!(
"When recording an impl from the crate store, information about its parent \