about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2023-11-20 20:56:43 +0100
committerGitHub <noreply@github.com>2023-11-20 20:56:43 +0100
commit6c62b42347cbbe4aec3d09491591b7ecb30546e6 (patch)
tree16ff1064f54212480d88d67e03eda5d3bd9b8e4d
parentca246d32e6c8b195ccfa40709b6c3d88f4c3a253 (diff)
parent35c8a37a6fce74100f54221ccc17783bad489436 (diff)
downloadrust-6c62b42347cbbe4aec3d09491591b7ecb30546e6.tar.gz
rust-6c62b42347cbbe4aec3d09491591b7ecb30546e6.zip
Rollup merge of #118089 - lcnr:intercrate-ambig-msg, r=compiler-errors
intercrate_ambiguity_causes: handle self ty infer + reservation impls

r? `@compiler-errors`
-rw-r--r--compiler/rustc_trait_selection/src/solve/assembly/mod.rs35
-rw-r--r--compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs48
-rw-r--r--compiler/rustc_trait_selection/src/solve/project_goals/mod.rs4
-rw-r--r--compiler/rustc_trait_selection/src/solve/trait_goals.rs10
-rw-r--r--compiler/rustc_trait_selection/src/traits/coherence.rs24
-rw-r--r--tests/ui/impl-trait/auto-trait-coherence.next.stderr2
-rw-r--r--tests/ui/never_type/never-from-impl-is-reserved.current.stderr (renamed from tests/ui/never_type/never-from-impl-is-reserved.stderr)2
-rw-r--r--tests/ui/never_type/never-from-impl-is-reserved.next.stderr14
-rw-r--r--tests/ui/never_type/never-from-impl-is-reserved.rs3
-rw-r--r--tests/ui/traits/new-solver/coherence/trait_ref_is_knowable-norm-overflow.stderr3
-rw-r--r--tests/ui/traits/reservation-impl/coherence-conflict.next.stderr2
11 files changed, 104 insertions, 43 deletions
diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
index 13d7ebe1db0..b6d2228d4b8 100644
--- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
@@ -110,7 +110,7 @@ pub(super) trait GoalKind<'tcx>:
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
         impl_def_id: DefId,
-    ) -> QueryResult<'tcx>;
+    ) -> Result<Candidate<'tcx>, NoSolution>;
 
     /// If the predicate contained an error, we want to avoid emitting unnecessary trait
     /// errors but still want to emit errors for other trait goals. We have some special
@@ -263,7 +263,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
     ) -> Vec<Candidate<'tcx>> {
         debug_assert_eq!(goal, self.resolve_vars_if_possible(goal));
         if let Some(ambig) = self.assemble_self_ty_infer_ambiguity_response(goal) {
-            return ambig;
+            return vec![ambig];
         }
 
         let mut candidates = self.assemble_candidates_via_self_ty(goal, 0);
@@ -288,15 +288,20 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
     fn assemble_self_ty_infer_ambiguity_response<G: GoalKind<'tcx>>(
         &mut self,
         goal: Goal<'tcx, G>,
-    ) -> Option<Vec<Candidate<'tcx>>> {
-        goal.predicate.self_ty().is_ty_var().then(|| {
-            vec![Candidate {
-                source: CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
-                result: self
-                    .evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
-                    .unwrap(),
-            }]
-        })
+    ) -> Option<Candidate<'tcx>> {
+        if goal.predicate.self_ty().is_ty_var() {
+            debug!("adding self_ty_infer_ambiguity_response");
+            let source = CandidateSource::BuiltinImpl(BuiltinImplSource::Misc);
+            let result = self
+                .evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
+                .unwrap();
+            let mut dummy_probe = self.inspect.new_probe();
+            dummy_probe.probe_kind(ProbeKind::TraitCandidate { source, result: Ok(result) });
+            self.inspect.finish_probe(dummy_probe);
+            Some(Candidate { source, result })
+        } else {
+            None
+        }
     }
 
     /// Assemble candidates which apply to the self type. This only looks at candidate which
@@ -310,7 +315,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
     ) -> Vec<Candidate<'tcx>> {
         debug_assert_eq!(goal, self.resolve_vars_if_possible(goal));
         if let Some(ambig) = self.assemble_self_ty_infer_ambiguity_response(goal) {
-            return ambig;
+            return vec![ambig];
         }
 
         let mut candidates = Vec::new();
@@ -395,8 +400,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
             if let Some(impls_for_type) = trait_impls.non_blanket_impls().get(&simp) {
                 for &impl_def_id in impls_for_type {
                     match G::consider_impl_candidate(self, goal, impl_def_id) {
-                        Ok(result) => candidates
-                            .push(Candidate { source: CandidateSource::Impl(impl_def_id), result }),
+                        Ok(candidate) => candidates.push(candidate),
                         Err(NoSolution) => (),
                     }
                 }
@@ -514,8 +518,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
         let trait_impls = tcx.trait_impls_of(goal.predicate.trait_def_id(tcx));
         for &impl_def_id in trait_impls.blanket_impls() {
             match G::consider_impl_candidate(self, goal, impl_def_id) {
-                Ok(result) => candidates
-                    .push(Candidate { source: CandidateSource::Impl(impl_def_id), result }),
+                Ok(candidate) => candidates.push(candidate),
                 Err(NoSolution) => (),
             }
         }
diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs
index 6087b916790..91fd48807a4 100644
--- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs
+++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs
@@ -1,5 +1,10 @@
+use crate::solve::assembly::Candidate;
+
 use super::EvalCtxt;
-use rustc_middle::traits::solve::{inspect, CandidateSource, QueryResult};
+use rustc_middle::traits::{
+    query::NoSolution,
+    solve::{inspect, CandidateSource, QueryResult},
+};
 use std::marker::PhantomData;
 
 pub(in crate::solve) struct ProbeCtxt<'me, 'a, 'tcx, F, T> {
@@ -36,6 +41,23 @@ where
     }
 }
 
+pub(in crate::solve) struct TraitProbeCtxt<'me, 'a, 'tcx, F> {
+    cx: ProbeCtxt<'me, 'a, 'tcx, F, QueryResult<'tcx>>,
+    source: CandidateSource,
+}
+
+impl<'tcx, F> TraitProbeCtxt<'_, '_, 'tcx, F>
+where
+    F: FnOnce(&QueryResult<'tcx>) -> inspect::ProbeKind<'tcx>,
+{
+    pub(in crate::solve) fn enter(
+        self,
+        f: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> QueryResult<'tcx>,
+    ) -> Result<Candidate<'tcx>, NoSolution> {
+        self.cx.enter(|ecx| f(ecx)).map(|result| Candidate { source: self.source, result })
+    }
+}
+
 impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
     /// `probe_kind` is only called when proof tree building is enabled so it can be
     /// as expensive as necessary to output the desired information.
@@ -69,20 +91,18 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
     pub(in crate::solve) fn probe_trait_candidate(
         &mut self,
         source: CandidateSource,
-    ) -> ProbeCtxt<
-        '_,
-        'a,
-        'tcx,
-        impl FnOnce(&QueryResult<'tcx>) -> inspect::ProbeKind<'tcx>,
-        QueryResult<'tcx>,
-    > {
-        ProbeCtxt {
-            ecx: self,
-            probe_kind: move |result: &QueryResult<'tcx>| inspect::ProbeKind::TraitCandidate {
-                source,
-                result: *result,
+    ) -> TraitProbeCtxt<'_, 'a, 'tcx, impl FnOnce(&QueryResult<'tcx>) -> inspect::ProbeKind<'tcx>>
+    {
+        TraitProbeCtxt {
+            cx: ProbeCtxt {
+                ecx: self,
+                probe_kind: move |result: &QueryResult<'tcx>| inspect::ProbeKind::TraitCandidate {
+                    source,
+                    result: *result,
+                },
+                _result: PhantomData,
             },
-            _result: PhantomData,
+            source,
         }
     }
 }
diff --git a/compiler/rustc_trait_selection/src/solve/project_goals/mod.rs b/compiler/rustc_trait_selection/src/solve/project_goals/mod.rs
index 7fb550aa3e0..6c29ce492df 100644
--- a/compiler/rustc_trait_selection/src/solve/project_goals/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/project_goals/mod.rs
@@ -1,6 +1,6 @@
 use crate::traits::{check_args_compatible, specialization_graph};
 
-use super::assembly::{self, structural_traits};
+use super::assembly::{self, structural_traits, Candidate};
 use super::EvalCtxt;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::DefId;
@@ -154,7 +154,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, ProjectionPredicate<'tcx>>,
         impl_def_id: DefId,
-    ) -> QueryResult<'tcx> {
+    ) -> Result<Candidate<'tcx>, NoSolution> {
         let tcx = ecx.tcx();
 
         let goal_trait_ref = goal.predicate.projection_ty.trait_ref(tcx);
diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
index 0f30b49314b..a0c065dfa03 100644
--- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs
+++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
@@ -1,12 +1,14 @@
 //! Dealing with trait goals, i.e. `T: Trait<'a, U>`.
 
-use super::assembly::{self, structural_traits};
+use super::assembly::{self, structural_traits, Candidate};
 use super::{EvalCtxt, SolverMode};
 use rustc_hir::def_id::DefId;
 use rustc_hir::{LangItem, Movability};
 use rustc_infer::traits::query::NoSolution;
 use rustc_middle::traits::solve::inspect::ProbeKind;
-use rustc_middle::traits::solve::{CanonicalResponse, Certainty, Goal, QueryResult};
+use rustc_middle::traits::solve::{
+    CandidateSource, CanonicalResponse, Certainty, Goal, QueryResult,
+};
 use rustc_middle::traits::{BuiltinImplSource, Reveal};
 use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams, TreatProjections};
 use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt};
@@ -38,7 +40,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, TraitPredicate<'tcx>>,
         impl_def_id: DefId,
-    ) -> QueryResult<'tcx> {
+    ) -> Result<Candidate<'tcx>, NoSolution> {
         let tcx = ecx.tcx();
 
         let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
@@ -63,7 +65,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
             },
         };
 
-        ecx.probe_misc_candidate("impl").enter(|ecx| {
+        ecx.probe_trait_candidate(CandidateSource::Impl(impl_def_id)).enter(|ecx| {
             let impl_args = ecx.fresh_args_for_item(impl_def_id);
             let impl_trait_ref = impl_trait_ref.instantiate(tcx, impl_args);
 
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index c4c0428dcc1..e6e05d0adc6 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -25,7 +25,7 @@ use rustc_hir::def_id::{DefId, LOCAL_CRATE};
 use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, TyCtxtInferExt};
 use rustc_infer::traits::{util, TraitEngine};
 use rustc_middle::traits::query::NoSolution;
-use rustc_middle::traits::solve::{Certainty, Goal};
+use rustc_middle::traits::solve::{CandidateSource, Certainty, Goal};
 use rustc_middle::traits::specialization_graph::OverlapMode;
 use rustc_middle::traits::DefiningAnchor;
 use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
@@ -1025,6 +1025,28 @@ impl<'a, 'tcx> ProofTreeVisitor<'tcx> for AmbiguityCausesVisitor<'a> {
             _ => return ControlFlow::Continue(()),
         };
 
+        // Add ambiguity causes for reservation impls.
+        for cand in goal.candidates() {
+            if let inspect::ProbeKind::TraitCandidate {
+                source: CandidateSource::Impl(def_id),
+                result: Ok(_),
+            } = cand.kind()
+            {
+                if let ty::ImplPolarity::Reservation = infcx.tcx.impl_polarity(def_id) {
+                    let value = infcx
+                        .tcx
+                        .get_attr(def_id, sym::rustc_reservation_impl)
+                        .and_then(|a| a.value_str());
+                    if let Some(value) = value {
+                        self.causes.insert(IntercrateAmbiguityCause::ReservationImpl {
+                            message: value.to_string(),
+                        });
+                    }
+                }
+            }
+        }
+
+        // Add ambiguity causes for unknowable goals.
         let mut ambiguity_cause = None;
         for cand in goal.candidates() {
             // FIXME: boiiii, using string comparisions here sure is scuffed.
diff --git a/tests/ui/impl-trait/auto-trait-coherence.next.stderr b/tests/ui/impl-trait/auto-trait-coherence.next.stderr
index cee359997b4..7833ac688ba 100644
--- a/tests/ui/impl-trait/auto-trait-coherence.next.stderr
+++ b/tests/ui/impl-trait/auto-trait-coherence.next.stderr
@@ -6,8 +6,6 @@ LL | impl<T: Send> AnotherTrait for T {}
 ...
 LL | impl AnotherTrait for D<OpaqueType> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `D<OpaqueType>`
-   |
-   = note: upstream crates may add a new impl of trait `std::marker::Send` for type `OpaqueType` in future versions
 
 error: aborting due to previous error
 
diff --git a/tests/ui/never_type/never-from-impl-is-reserved.stderr b/tests/ui/never_type/never-from-impl-is-reserved.current.stderr
index 871c5120528..6c71785de28 100644
--- a/tests/ui/never_type/never-from-impl-is-reserved.stderr
+++ b/tests/ui/never_type/never-from-impl-is-reserved.current.stderr
@@ -1,5 +1,5 @@
 error[E0119]: conflicting implementations of trait `MyTrait` for type `MyFoo`
-  --> $DIR/never-from-impl-is-reserved.rs:10:1
+  --> $DIR/never-from-impl-is-reserved.rs:13:1
    |
 LL | impl MyTrait for MyFoo {}
    | ---------------------- first implementation here
diff --git a/tests/ui/never_type/never-from-impl-is-reserved.next.stderr b/tests/ui/never_type/never-from-impl-is-reserved.next.stderr
new file mode 100644
index 00000000000..6c71785de28
--- /dev/null
+++ b/tests/ui/never_type/never-from-impl-is-reserved.next.stderr
@@ -0,0 +1,14 @@
+error[E0119]: conflicting implementations of trait `MyTrait` for type `MyFoo`
+  --> $DIR/never-from-impl-is-reserved.rs:13:1
+   |
+LL | impl MyTrait for MyFoo {}
+   | ---------------------- first implementation here
+LL | // This will conflict with the first impl if we impl `for<T> T: From<!>`.
+LL | impl<T> MyTrait for T where T: From<!> {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `MyFoo`
+   |
+   = note: permitting this impl would forbid us from adding `impl<T> From<!> for T` later; see rust-lang/rust#64715 for details
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0119`.
diff --git a/tests/ui/never_type/never-from-impl-is-reserved.rs b/tests/ui/never_type/never-from-impl-is-reserved.rs
index 9d16015bdc1..f358e045cf0 100644
--- a/tests/ui/never_type/never-from-impl-is-reserved.rs
+++ b/tests/ui/never_type/never-from-impl-is-reserved.rs
@@ -1,5 +1,8 @@
 // check that the `for<T> T: From<!>` impl is reserved
 
+// revisions: current next
+//[next] compile-flags: -Ztrait-solver=next-coherence
+
 #![feature(never_type)]
 
 pub struct MyFoo;
diff --git a/tests/ui/traits/new-solver/coherence/trait_ref_is_knowable-norm-overflow.stderr b/tests/ui/traits/new-solver/coherence/trait_ref_is_knowable-norm-overflow.stderr
index 4207c2f80b8..5d5f325e4b4 100644
--- a/tests/ui/traits/new-solver/coherence/trait_ref_is_knowable-norm-overflow.stderr
+++ b/tests/ui/traits/new-solver/coherence/trait_ref_is_knowable-norm-overflow.stderr
@@ -6,9 +6,6 @@ LL | impl<T: Copy> Trait for T {}
 LL | struct LocalTy;
 LL | impl Trait for <LocalTy as Overflow>::Assoc {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `<LocalTy as Overflow>::Assoc`
-   |
-   = note: downstream crates may implement trait `std::marker::Sized` for type `<LocalTy as Overflow>::Assoc`
-   = note: downstream crates may implement trait `std::marker::Copy` for type `<LocalTy as Overflow>::Assoc`
 
 error: aborting due to previous error
 
diff --git a/tests/ui/traits/reservation-impl/coherence-conflict.next.stderr b/tests/ui/traits/reservation-impl/coherence-conflict.next.stderr
index e5a3c3f5cc4..393350ea3f1 100644
--- a/tests/ui/traits/reservation-impl/coherence-conflict.next.stderr
+++ b/tests/ui/traits/reservation-impl/coherence-conflict.next.stderr
@@ -5,6 +5,8 @@ LL | impl OtherTrait for () {}
    | ---------------------- first implementation here
 LL | impl<T: MyTrait> OtherTrait for T {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `()`
+   |
+   = note: this impl is reserved
 
 error: aborting due to previous error