Rollup merge of #124623 - lcnr:coherence-uwu, r=compiler-errors
shallow resolve in orphan check r? ``@compiler-errors`` cc https://github.com/rust-lang/rust/pull/124588#pullrequestreview-2036012292
This commit is contained in:
commit
fe62bc5ea5
@ -330,6 +330,7 @@ fn orphan_check<'tcx>(
|
|||||||
};
|
};
|
||||||
|
|
||||||
let Ok(result) = traits::orphan_check_trait_ref::<!>(
|
let Ok(result) = traits::orphan_check_trait_ref::<!>(
|
||||||
|
&infcx,
|
||||||
trait_ref,
|
trait_ref,
|
||||||
traits::InCrate::Local { mode },
|
traits::InCrate::Local { mode },
|
||||||
lazily_normalize_ty,
|
lazily_normalize_ty,
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
use crate::solve::GoalSource;
|
use crate::solve::GoalSource;
|
||||||
use crate::solve::{inspect, EvalCtxt, SolverMode};
|
use crate::solve::{inspect, EvalCtxt, SolverMode};
|
||||||
use crate::traits::coherence;
|
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
use rustc_infer::traits::query::NoSolution;
|
use rustc_infer::traits::query::NoSolution;
|
||||||
use rustc_middle::traits::solve::inspect::ProbeKind;
|
use rustc_middle::traits::solve::inspect::ProbeKind;
|
||||||
@ -769,13 +768,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||||||
candidates.extend(self.probe_trait_candidate(CandidateSource::CoherenceUnknowable).enter(
|
candidates.extend(self.probe_trait_candidate(CandidateSource::CoherenceUnknowable).enter(
|
||||||
|ecx| {
|
|ecx| {
|
||||||
let trait_ref = goal.predicate.trait_ref(tcx);
|
let trait_ref = goal.predicate.trait_ref(tcx);
|
||||||
let lazily_normalize_ty = |ty| ecx.structurally_normalize_ty(goal.param_env, ty);
|
if ecx.trait_ref_is_knowable(goal.param_env, trait_ref)? {
|
||||||
|
Err(NoSolution)
|
||||||
match coherence::trait_ref_is_knowable(tcx, trait_ref, lazily_normalize_ty)? {
|
} else {
|
||||||
Ok(()) => Err(NoSolution),
|
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
|
||||||
Err(_) => {
|
|
||||||
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
|
@ -27,6 +27,7 @@ use rustc_span::DUMMY_SP;
|
|||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::ops::ControlFlow;
|
use std::ops::ControlFlow;
|
||||||
|
|
||||||
|
use crate::traits::coherence;
|
||||||
use crate::traits::vtable::{count_own_vtable_entries, prepare_vtable_segments, VtblSegment};
|
use crate::traits::vtable::{count_own_vtable_entries, prepare_vtable_segments, VtblSegment};
|
||||||
|
|
||||||
use super::inspect::ProofTreeBuilder;
|
use super::inspect::ProofTreeBuilder;
|
||||||
@ -942,6 +943,17 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(super) fn trait_ref_is_knowable(
|
||||||
|
&mut self,
|
||||||
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
|
trait_ref: ty::TraitRef<'tcx>,
|
||||||
|
) -> Result<bool, NoSolution> {
|
||||||
|
let infcx = self.infcx;
|
||||||
|
let lazily_normalize_ty = |ty| self.structurally_normalize_ty(param_env, ty);
|
||||||
|
coherence::trait_ref_is_knowable(infcx, trait_ref, lazily_normalize_ty)
|
||||||
|
.map(|is_knowable| is_knowable.is_ok())
|
||||||
|
}
|
||||||
|
|
||||||
pub(super) fn can_define_opaque_ty(&self, def_id: impl Into<DefId>) -> bool {
|
pub(super) fn can_define_opaque_ty(&self, def_id: impl Into<DefId>) -> bool {
|
||||||
self.infcx.can_define_opaque_ty(def_id)
|
self.infcx.can_define_opaque_ty(def_id)
|
||||||
}
|
}
|
||||||
|
@ -618,19 +618,20 @@ fn try_prove_negated_where_clause<'tcx>(
|
|||||||
/// This both checks whether any downstream or sibling crates could
|
/// This both checks whether any downstream or sibling crates could
|
||||||
/// implement it and whether an upstream crate can add this impl
|
/// implement it and whether an upstream crate can add this impl
|
||||||
/// without breaking backwards compatibility.
|
/// without breaking backwards compatibility.
|
||||||
#[instrument(level = "debug", skip(tcx, lazily_normalize_ty), ret)]
|
#[instrument(level = "debug", skip(infcx, lazily_normalize_ty), ret)]
|
||||||
pub fn trait_ref_is_knowable<'tcx, E: Debug>(
|
pub fn trait_ref_is_knowable<'tcx, E: Debug>(
|
||||||
tcx: TyCtxt<'tcx>,
|
infcx: &InferCtxt<'tcx>,
|
||||||
trait_ref: ty::TraitRef<'tcx>,
|
trait_ref: ty::TraitRef<'tcx>,
|
||||||
mut lazily_normalize_ty: impl FnMut(Ty<'tcx>) -> Result<Ty<'tcx>, E>,
|
mut lazily_normalize_ty: impl FnMut(Ty<'tcx>) -> Result<Ty<'tcx>, E>,
|
||||||
) -> Result<Result<(), Conflict>, E> {
|
) -> Result<Result<(), Conflict>, E> {
|
||||||
if orphan_check_trait_ref(trait_ref, InCrate::Remote, &mut lazily_normalize_ty)?.is_ok() {
|
if orphan_check_trait_ref(infcx, trait_ref, InCrate::Remote, &mut lazily_normalize_ty)?.is_ok()
|
||||||
|
{
|
||||||
// A downstream or cousin crate is allowed to implement some
|
// A downstream or cousin crate is allowed to implement some
|
||||||
// generic parameters of this trait-ref.
|
// generic parameters of this trait-ref.
|
||||||
return Ok(Err(Conflict::Downstream));
|
return Ok(Err(Conflict::Downstream));
|
||||||
}
|
}
|
||||||
|
|
||||||
if trait_ref_is_local_or_fundamental(tcx, trait_ref) {
|
if trait_ref_is_local_or_fundamental(infcx.tcx, trait_ref) {
|
||||||
// This is a local or fundamental trait, so future-compatibility
|
// This is a local or fundamental trait, so future-compatibility
|
||||||
// is no concern. We know that downstream/cousin crates are not
|
// is no concern. We know that downstream/cousin crates are not
|
||||||
// allowed to implement a generic parameter of this trait ref,
|
// allowed to implement a generic parameter of this trait ref,
|
||||||
@ -648,6 +649,7 @@ pub fn trait_ref_is_knowable<'tcx, E: Debug>(
|
|||||||
// about future-compatibility, which means that we're OK if
|
// about future-compatibility, which means that we're OK if
|
||||||
// we are an owner.
|
// we are an owner.
|
||||||
if orphan_check_trait_ref(
|
if orphan_check_trait_ref(
|
||||||
|
infcx,
|
||||||
trait_ref,
|
trait_ref,
|
||||||
InCrate::Local { mode: OrphanCheckMode::Proper },
|
InCrate::Local { mode: OrphanCheckMode::Proper },
|
||||||
&mut lazily_normalize_ty,
|
&mut lazily_normalize_ty,
|
||||||
@ -786,38 +788,32 @@ pub struct UncoveredTyParams<'tcx, T> {
|
|||||||
///
|
///
|
||||||
/// Note that this function is never called for types that have both type
|
/// Note that this function is never called for types that have both type
|
||||||
/// parameters and inference variables.
|
/// parameters and inference variables.
|
||||||
#[instrument(level = "trace", skip(lazily_normalize_ty), ret)]
|
#[instrument(level = "trace", skip(infcx, lazily_normalize_ty), ret)]
|
||||||
pub fn orphan_check_trait_ref<'tcx, E: Debug>(
|
pub fn orphan_check_trait_ref<'tcx, E: Debug>(
|
||||||
|
infcx: &InferCtxt<'tcx>,
|
||||||
trait_ref: ty::TraitRef<'tcx>,
|
trait_ref: ty::TraitRef<'tcx>,
|
||||||
in_crate: InCrate,
|
in_crate: InCrate,
|
||||||
lazily_normalize_ty: impl FnMut(Ty<'tcx>) -> Result<Ty<'tcx>, E>,
|
lazily_normalize_ty: impl FnMut(Ty<'tcx>) -> Result<Ty<'tcx>, E>,
|
||||||
) -> Result<Result<(), OrphanCheckErr<'tcx, Ty<'tcx>>>, E> {
|
) -> Result<Result<(), OrphanCheckErr<'tcx, Ty<'tcx>>>, E> {
|
||||||
if trait_ref.has_infer() && trait_ref.has_param() {
|
if trait_ref.has_param() {
|
||||||
bug!(
|
bug!("orphan check only expects inference variables: {trait_ref:?}");
|
||||||
"can't orphan check a trait ref with both params and inference variables {:?}",
|
|
||||||
trait_ref
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut checker = OrphanChecker::new(in_crate, lazily_normalize_ty);
|
let mut checker = OrphanChecker::new(infcx, in_crate, lazily_normalize_ty);
|
||||||
|
|
||||||
// Does there exist some local type after the `ParamTy`.
|
|
||||||
let search_first_local_ty = |checker: &mut OrphanChecker<'tcx, _>| {
|
|
||||||
checker.search_first_local_ty = true;
|
|
||||||
match trait_ref.visit_with(checker).break_value() {
|
|
||||||
Some(OrphanCheckEarlyExit::LocalTy(local_ty)) => Some(local_ty),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(match trait_ref.visit_with(&mut checker) {
|
Ok(match trait_ref.visit_with(&mut checker) {
|
||||||
ControlFlow::Continue(()) => Err(OrphanCheckErr::NonLocalInputType(checker.non_local_tys)),
|
ControlFlow::Continue(()) => Err(OrphanCheckErr::NonLocalInputType(checker.non_local_tys)),
|
||||||
ControlFlow::Break(residual) => match residual {
|
ControlFlow::Break(residual) => match residual {
|
||||||
OrphanCheckEarlyExit::NormalizationFailure(err) => return Err(err),
|
OrphanCheckEarlyExit::NormalizationFailure(err) => return Err(err),
|
||||||
OrphanCheckEarlyExit::UncoveredTyParam(ty) => {
|
OrphanCheckEarlyExit::UncoveredTyParam(ty) => {
|
||||||
|
// Does there exist some local type after the `ParamTy`.
|
||||||
|
checker.search_first_local_ty = true;
|
||||||
|
let local_ty = match trait_ref.visit_with(&mut checker).break_value() {
|
||||||
|
Some(OrphanCheckEarlyExit::LocalTy(local_ty)) => Some(local_ty),
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
Err(OrphanCheckErr::UncoveredTyParams(UncoveredTyParams {
|
Err(OrphanCheckErr::UncoveredTyParams(UncoveredTyParams {
|
||||||
uncovered: ty,
|
uncovered: ty,
|
||||||
local_ty: search_first_local_ty(&mut checker),
|
local_ty,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
OrphanCheckEarlyExit::LocalTy(_) => Ok(()),
|
OrphanCheckEarlyExit::LocalTy(_) => Ok(()),
|
||||||
@ -825,7 +821,8 @@ pub fn orphan_check_trait_ref<'tcx, E: Debug>(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
struct OrphanChecker<'tcx, F> {
|
struct OrphanChecker<'a, 'tcx, F> {
|
||||||
|
infcx: &'a InferCtxt<'tcx>,
|
||||||
in_crate: InCrate,
|
in_crate: InCrate,
|
||||||
in_self_ty: bool,
|
in_self_ty: bool,
|
||||||
lazily_normalize_ty: F,
|
lazily_normalize_ty: F,
|
||||||
@ -834,12 +831,13 @@ struct OrphanChecker<'tcx, F> {
|
|||||||
non_local_tys: Vec<(Ty<'tcx>, IsFirstInputType)>,
|
non_local_tys: Vec<(Ty<'tcx>, IsFirstInputType)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx, F, E> OrphanChecker<'tcx, F>
|
impl<'a, 'tcx, F, E> OrphanChecker<'a, 'tcx, F>
|
||||||
where
|
where
|
||||||
F: FnOnce(Ty<'tcx>) -> Result<Ty<'tcx>, E>,
|
F: FnOnce(Ty<'tcx>) -> Result<Ty<'tcx>, E>,
|
||||||
{
|
{
|
||||||
fn new(in_crate: InCrate, lazily_normalize_ty: F) -> Self {
|
fn new(infcx: &'a InferCtxt<'tcx>, in_crate: InCrate, lazily_normalize_ty: F) -> Self {
|
||||||
OrphanChecker {
|
OrphanChecker {
|
||||||
|
infcx,
|
||||||
in_crate,
|
in_crate,
|
||||||
in_self_ty: true,
|
in_self_ty: true,
|
||||||
lazily_normalize_ty,
|
lazily_normalize_ty,
|
||||||
@ -878,7 +876,7 @@ enum OrphanCheckEarlyExit<'tcx, E> {
|
|||||||
LocalTy(Ty<'tcx>),
|
LocalTy(Ty<'tcx>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx, F, E> TypeVisitor<TyCtxt<'tcx>> for OrphanChecker<'tcx, F>
|
impl<'a, 'tcx, F, E> TypeVisitor<TyCtxt<'tcx>> for OrphanChecker<'a, 'tcx, F>
|
||||||
where
|
where
|
||||||
F: FnMut(Ty<'tcx>) -> Result<Ty<'tcx>, E>,
|
F: FnMut(Ty<'tcx>) -> Result<Ty<'tcx>, E>,
|
||||||
{
|
{
|
||||||
@ -889,6 +887,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
|
fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
|
||||||
|
let ty = self.infcx.shallow_resolve(ty);
|
||||||
let ty = match (self.lazily_normalize_ty)(ty) {
|
let ty = match (self.lazily_normalize_ty)(ty) {
|
||||||
Ok(norm_ty) if norm_ty.is_ty_var() => ty,
|
Ok(norm_ty) if norm_ty.is_ty_var() => ty,
|
||||||
Ok(norm_ty) => norm_ty,
|
Ok(norm_ty) => norm_ty,
|
||||||
@ -1149,7 +1148,7 @@ impl<'a, 'tcx> ProofTreeVisitor<'tcx> for AmbiguityCausesVisitor<'a, 'tcx> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
infcx.probe(|_| {
|
infcx.probe(|_| {
|
||||||
match trait_ref_is_knowable(infcx.tcx, trait_ref, lazily_normalize_ty) {
|
match trait_ref_is_knowable(infcx, trait_ref, lazily_normalize_ty) {
|
||||||
Err(()) => {}
|
Err(()) => {}
|
||||||
Ok(Ok(())) => warn!("expected an unknowable trait ref: {trait_ref:?}"),
|
Ok(Ok(())) => warn!("expected an unknowable trait ref: {trait_ref:?}"),
|
||||||
Ok(Err(conflict)) => {
|
Ok(Err(conflict)) => {
|
||||||
|
@ -1497,7 +1497,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||||||
// bound regions.
|
// bound regions.
|
||||||
let trait_ref = predicate.skip_binder().trait_ref;
|
let trait_ref = predicate.skip_binder().trait_ref;
|
||||||
|
|
||||||
coherence::trait_ref_is_knowable::<!>(self.tcx(), trait_ref, |ty| Ok(ty)).unwrap()
|
coherence::trait_ref_is_knowable::<!>(self.infcx, trait_ref, |ty| Ok(ty)).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns `true` if the global caches can be used.
|
/// Returns `true` if the global caches can be used.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user