about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2024-05-02 19:42:49 +0200
committerGitHub <noreply@github.com>2024-05-02 19:42:49 +0200
commitfe62bc5ea5302155558b053fee3d9aa6ed6fcad8 (patch)
treec46a2a986a665689c7d010c3bdd52b7f4c3bee57
parent6cc39592304728ce4594e5a0ecc4cbcc0d132107 (diff)
parentc4e882fd993d575d65e841da02161263c0ff2d16 (diff)
downloadrust-fe62bc5ea5302155558b053fee3d9aa6ed6fcad8.tar.gz
rust-fe62bc5ea5302155558b053fee3d9aa6ed6fcad8.zip
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
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/orphan.rs1
-rw-r--r--compiler/rustc_trait_selection/src/solve/assembly/mod.rs12
-rw-r--r--compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs12
-rw-r--r--compiler/rustc_trait_selection/src/traits/coherence.rs53
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs2
5 files changed, 44 insertions, 36 deletions
diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
index a256d11fd5a..819e0925f68 100644
--- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
@@ -330,6 +330,7 @@ fn orphan_check<'tcx>(
     };
 
     let Ok(result) = traits::orphan_check_trait_ref::<!>(
+        &infcx,
         trait_ref,
         traits::InCrate::Local { mode },
         lazily_normalize_ty,
diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
index b082b0bd4c8..280975f63bd 100644
--- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
@@ -2,7 +2,6 @@
 
 use crate::solve::GoalSource;
 use crate::solve::{inspect, EvalCtxt, SolverMode};
-use crate::traits::coherence;
 use rustc_hir::def_id::DefId;
 use rustc_infer::traits::query::NoSolution;
 use rustc_middle::traits::solve::inspect::ProbeKind;
@@ -769,13 +768,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
         candidates.extend(self.probe_trait_candidate(CandidateSource::CoherenceUnknowable).enter(
             |ecx| {
                 let trait_ref = goal.predicate.trait_ref(tcx);
-                let lazily_normalize_ty = |ty| ecx.structurally_normalize_ty(goal.param_env, ty);
-
-                match coherence::trait_ref_is_knowable(tcx, trait_ref, lazily_normalize_ty)? {
-                    Ok(()) => Err(NoSolution),
-                    Err(_) => {
-                        ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
-                    }
+                if ecx.trait_ref_is_knowable(goal.param_env, trait_ref)? {
+                    Err(NoSolution)
+                } else {
+                    ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
                 }
             },
         ))
diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs
index 8425d68ab59..1710746ae50 100644
--- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs
@@ -27,6 +27,7 @@ use rustc_span::DUMMY_SP;
 use std::io::Write;
 use std::ops::ControlFlow;
 
+use crate::traits::coherence;
 use crate::traits::vtable::{count_own_vtable_entries, prepare_vtable_segments, VtblSegment};
 
 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 {
         self.infcx.can_define_opaque_ty(def_id)
     }
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index 730b7ea70c6..86e7c42376a 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -618,19 +618,20 @@ fn try_prove_negated_where_clause<'tcx>(
 /// This both checks whether any downstream or sibling crates could
 /// implement it and whether an upstream crate can add this impl
 /// 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>(
-    tcx: TyCtxt<'tcx>,
+    infcx: &InferCtxt<'tcx>,
     trait_ref: ty::TraitRef<'tcx>,
     mut lazily_normalize_ty: impl FnMut(Ty<'tcx>) -> Result<Ty<'tcx>, 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
         // generic parameters of this trait-ref.
         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
         // is no concern. We know that downstream/cousin crates are not
         // 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
     // we are an owner.
     if orphan_check_trait_ref(
+        infcx,
         trait_ref,
         InCrate::Local { mode: OrphanCheckMode::Proper },
         &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
 /// 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>(
+    infcx: &InferCtxt<'tcx>,
     trait_ref: ty::TraitRef<'tcx>,
     in_crate: InCrate,
     lazily_normalize_ty: impl FnMut(Ty<'tcx>) -> Result<Ty<'tcx>, E>,
 ) -> Result<Result<(), OrphanCheckErr<'tcx, Ty<'tcx>>>, E> {
-    if trait_ref.has_infer() && trait_ref.has_param() {
-        bug!(
-            "can't orphan check a trait ref with both params and inference variables {:?}",
-            trait_ref
-        );
+    if trait_ref.has_param() {
+        bug!("orphan check only expects inference variables: {trait_ref:?}");
     }
 
-    let mut checker = OrphanChecker::new(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,
-        }
-    };
-
+    let mut checker = OrphanChecker::new(infcx, in_crate, lazily_normalize_ty);
     Ok(match trait_ref.visit_with(&mut checker) {
         ControlFlow::Continue(()) => Err(OrphanCheckErr::NonLocalInputType(checker.non_local_tys)),
         ControlFlow::Break(residual) => match residual {
             OrphanCheckEarlyExit::NormalizationFailure(err) => return Err(err),
             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 {
                     uncovered: ty,
-                    local_ty: search_first_local_ty(&mut checker),
+                    local_ty,
                 }))
             }
             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_self_ty: bool,
     lazily_normalize_ty: F,
@@ -834,12 +831,13 @@ struct OrphanChecker<'tcx, F> {
     non_local_tys: Vec<(Ty<'tcx>, IsFirstInputType)>,
 }
 
-impl<'tcx, F, E> OrphanChecker<'tcx, F>
+impl<'a, 'tcx, F, E> OrphanChecker<'a, 'tcx, F>
 where
     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 {
+            infcx,
             in_crate,
             in_self_ty: true,
             lazily_normalize_ty,
@@ -878,7 +876,7 @@ enum OrphanCheckEarlyExit<'tcx, E> {
     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
     F: FnMut(Ty<'tcx>) -> Result<Ty<'tcx>, E>,
 {
@@ -889,6 +887,7 @@ where
     }
 
     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) {
             Ok(norm_ty) if norm_ty.is_ty_var() => ty,
             Ok(norm_ty) => norm_ty,
@@ -1149,7 +1148,7 @@ impl<'a, 'tcx> ProofTreeVisitor<'tcx> for AmbiguityCausesVisitor<'a, 'tcx> {
                 };
 
                 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(()) => {}
                         Ok(Ok(())) => warn!("expected an unknowable trait ref: {trait_ref:?}"),
                         Ok(Err(conflict)) => {
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 35ab333c9b3..18cb3184fe1 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -1497,7 +1497,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         // bound regions.
         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.