Rollup merge of #118089 - lcnr:intercrate-ambig-msg, r=compiler-errors
intercrate_ambiguity_causes: handle self ty infer + reservation impls r? `@compiler-errors`
This commit is contained in:
commit
6c62b42347
11 changed files with 104 additions and 43 deletions
|
@ -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) => (),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
14
tests/ui/never_type/never-from-impl-is-reserved.next.stderr
Normal file
14
tests/ui/never_type/never-from-impl-is-reserved.next.stderr
Normal file
|
@ -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`.
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue