Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

intercrate_ambiguity_causes: handle self ty infer + reservation impls #118089

Merged
merged 2 commits into from
Nov 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 19 additions & 16 deletions compiler/rustc_trait_selection/src/solve/assembly/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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);
Expand All @@ -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
Expand All @@ -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();
Expand Down Expand Up @@ -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) => (),
}
}
Expand Down Expand Up @@ -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) => (),
}
}
Expand Down
48 changes: 34 additions & 14 deletions compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs
Original file line number Diff line number Diff line change
@@ -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> {
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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,
}
}
}
4 changes: 2 additions & 2 deletions compiler/rustc_trait_selection/src/solve/project_goals/mod.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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);
Expand Down
10 changes: 6 additions & 4 deletions compiler/rustc_trait_selection/src/solve/trait_goals.rs
Original file line number Diff line number Diff line change
@@ -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};
Expand Down Expand Up @@ -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();
Expand All @@ -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);

Expand Down
24 changes: 23 additions & 1 deletion compiler/rustc_trait_selection/src/traits/coherence.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -1019,6 +1019,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.
Expand Down
2 changes: 0 additions & 2 deletions tests/ui/impl-trait/auto-trait-coherence.next.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand Down
14 changes: 14 additions & 0 deletions tests/ui/never_type/never-from-impl-is-reserved.next.stderr
Original file line number Diff line number Diff line change
@@ -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`.
3 changes: 3 additions & 0 deletions tests/ui/never_type/never-from-impl-is-reserved.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
Loading