about summary refs log tree commit diff
path: root/compiler/rustc_next_trait_solver
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-06-29 20:08:10 +0000
committerbors <bors@rust-lang.org>2024-06-29 20:08:10 +0000
commitba1d7f4a083e6402679105115ded645512a7aea8 (patch)
treeec4c45b9a51f50b5727e950b310d009086c11b73 /compiler/rustc_next_trait_solver
parentd1b7355d3d7b4ead564dbecb1d240fcc74fff21b (diff)
parent65a0bee0b77bad05c1bf29bd2dd855e554a9eaf5 (diff)
downloadrust-ba1d7f4a083e6402679105115ded645512a7aea8.tar.gz
rust-ba1d7f4a083e6402679105115ded645512a7aea8.zip
Auto merge of #120639 - fee1-dead-contrib:new-effects-desugaring, r=oli-obk
Implement new effects desugaring

cc `@rust-lang/project-const-traits.` Will write down notes once I have finished.

* [x] See if we want `T: Tr` to desugar into `T: Tr, T::Effects: Compat<true>`
* [x] Fix ICEs on `type Assoc: ~const Tr` and `type Assoc<T: ~const Tr>`
* [ ] add types and traits to minicore test
* [ ] update rustc-dev-guide

Fixes #119717
Fixes #123664
Fixes #124857
Fixes #126148
Diffstat (limited to 'compiler/rustc_next_trait_solver')
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs7
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs62
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/trait_goals.rs41
3 files changed, 110 insertions, 0 deletions
diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
index 21439530c08..6ee684605ac 100644
--- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
@@ -269,6 +269,11 @@ where
         ecx: &mut EvalCtxt<'_, D>,
         goal: Goal<I, Self>,
     ) -> Vec<Candidate<I>>;
+
+    fn consider_builtin_effects_intersection_candidate(
+        ecx: &mut EvalCtxt<'_, D>,
+        goal: Goal<I, Self>,
+    ) -> Result<Candidate<I>, NoSolution>;
 }
 
 impl<D, I> EvalCtxt<'_, D>
@@ -420,6 +425,8 @@ where
             G::consider_builtin_destruct_candidate(self, goal)
         } else if cx.is_lang_item(trait_def_id, TraitSolverLangItem::TransmuteTrait) {
             G::consider_builtin_transmute_candidate(self, goal)
+        } else if cx.is_lang_item(trait_def_id, TraitSolverLangItem::EffectsIntersection) {
+            G::consider_builtin_effects_intersection_candidate(self, goal)
         } else {
             Err(NoSolution)
         };
diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs
index 4e8cb4384f4..9275bcc8e97 100644
--- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs
@@ -864,6 +864,68 @@ where
     ) -> Result<Candidate<I>, NoSolution> {
         panic!("`BikeshedIntrinsicFrom` does not have an associated type: {:?}", goal)
     }
+
+    fn consider_builtin_effects_intersection_candidate(
+        ecx: &mut EvalCtxt<'_, D>,
+        goal: Goal<I, Self>,
+    ) -> Result<Candidate<I>, NoSolution> {
+        let ty::Tuple(types) = goal.predicate.self_ty().kind() else {
+            return Err(NoSolution);
+        };
+
+        let cx = ecx.cx();
+
+        let mut first_non_maybe = None;
+        let mut non_maybe_count = 0;
+        for ty in types.iter() {
+            if !matches!(ty::EffectKind::try_from_ty(cx, ty), Some(ty::EffectKind::Maybe)) {
+                first_non_maybe.get_or_insert(ty);
+                non_maybe_count += 1;
+            }
+        }
+
+        match non_maybe_count {
+            0 => {
+                let ty = ty::EffectKind::Maybe.to_ty(cx);
+                ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
+                    ecx.instantiate_normalizes_to_term(goal, ty.into());
+                    ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
+                })
+            }
+            1 => {
+                let ty = first_non_maybe.unwrap();
+                ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
+                    ecx.instantiate_normalizes_to_term(goal, ty.into());
+                    ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
+                })
+            }
+            _ => {
+                let mut min = ty::EffectKind::Maybe;
+
+                for ty in types.iter() {
+                    // We can't find the intersection if the types used are generic.
+                    //
+                    // FIXME(effects) do we want to look at where clauses to get some
+                    // clue for the case where generic types are being used?
+                    let Some(kind) = ty::EffectKind::try_from_ty(cx, ty) else {
+                        return Err(NoSolution);
+                    };
+
+                    let Some(result) = ty::EffectKind::intersection(min, kind) else {
+                        return Err(NoSolution);
+                    };
+
+                    min = result;
+                }
+
+                let ty = min.to_ty(cx);
+                ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
+                    ecx.instantiate_normalizes_to_term(goal, ty.into());
+                    ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
+                })
+            }
+        }
+    }
 }
 
 impl<D, I> EvalCtxt<'_, D>
diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
index 2bc9d35c2b0..f5832f7e5b4 100644
--- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
@@ -702,6 +702,47 @@ where
             }
         })
     }
+
+    fn consider_builtin_effects_intersection_candidate(
+        ecx: &mut EvalCtxt<'_, D>,
+        goal: Goal<I, Self>,
+    ) -> Result<Candidate<I>, NoSolution> {
+        if goal.predicate.polarity != ty::PredicatePolarity::Positive {
+            return Err(NoSolution);
+        }
+
+        let ty::Tuple(types) = goal.predicate.self_ty().kind() else {
+            return Err(NoSolution);
+        };
+
+        let cx = ecx.cx();
+        let maybe_count = types
+            .iter()
+            .filter_map(|ty| ty::EffectKind::try_from_ty(cx, ty))
+            .filter(|&ty| ty == ty::EffectKind::Maybe)
+            .count();
+
+        // Don't do concrete type check unless there are more than one type that will influence the result.
+        // This would allow `(Maybe, T): Min` pass even if we know nothing about `T`.
+        if types.len() - maybe_count > 1 {
+            let mut min = ty::EffectKind::Maybe;
+
+            for ty in types.iter() {
+                let Some(kind) = ty::EffectKind::try_from_ty(ecx.cx(), ty) else {
+                    return Err(NoSolution);
+                };
+
+                let Some(result) = ty::EffectKind::intersection(min, kind) else {
+                    return Err(NoSolution);
+                };
+
+                min = result;
+            }
+        }
+
+        ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
+            .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
+    }
 }
 
 impl<D, I> EvalCtxt<'_, D>