From c7d27a15d0a28d66d9a6b279e6005b6fcd861ae2 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Mon, 24 Jun 2024 16:25:17 +0000 Subject: [PATCH] Implement `Min` trait in new solver --- .../src/collect/predicates_of.rs | 2 +- compiler/rustc_middle/src/ty/context.rs | 5 ++ .../src/solve/assembly/mod.rs | 7 +++ .../src/solve/normalizes_to/mod.rs | 59 +++++++++++++++++++ .../src/solve/trait_goals.rs | 41 +++++++++++++ compiler/rustc_type_ir/src/effects.rs | 56 ++++++++++++++++++ compiler/rustc_type_ir/src/lang_items.rs | 5 ++ compiler/rustc_type_ir/src/lib.rs | 2 + library/core/src/marker.rs | 9 +-- .../trait-where-clause-run.rs | 1 + 10 files changed, 182 insertions(+), 5 deletions(-) create mode 100644 compiler/rustc_type_ir/src/effects.rs diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index 087e02a0305..e3d1e1c423e 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -122,7 +122,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen let identity_args = ty::GenericArgs::identity_for_item(tcx, def_id); let preds = tcx.explicit_predicates_of(parent); - predicates.extend(preds.instantiate_own(tcx, identity_args)); + if let ty::AssocItemContainer::TraitContainer = tcx.associated_item(def_id).container { // for traits, emit `type Effects: TyCompat<<(T1::Effects, ..) as Min>::Output>` // TODO do the same for impls diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 656aba67112..c0ebad9616d 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -598,6 +598,11 @@ fn trait_lang_item_to_lang_item(lang_item: TraitSolverLangItem) -> LangItem { TraitSolverLangItem::Destruct => LangItem::Destruct, TraitSolverLangItem::DiscriminantKind => LangItem::DiscriminantKind, TraitSolverLangItem::DynMetadata => LangItem::DynMetadata, + TraitSolverLangItem::EffectsMaybe => LangItem::EffectsMaybe, + TraitSolverLangItem::EffectsMin => LangItem::EffectsMin, + TraitSolverLangItem::EffectsMinOutput => LangItem::EffectsMinOutput, + TraitSolverLangItem::EffectsNoRuntime => LangItem::EffectsNoRuntime, + TraitSolverLangItem::EffectsRuntime => LangItem::EffectsRuntime, TraitSolverLangItem::FnPtrTrait => LangItem::FnPtrTrait, TraitSolverLangItem::FusedIterator => LangItem::FusedIterator, TraitSolverLangItem::Future => LangItem::Future, 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..8d57c3d9af0 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, ) -> Vec>; + + fn consider_builtin_effects_min_candidate( + ecx: &mut EvalCtxt<'_, D>, + goal: Goal, + ) -> Result, NoSolution>; } impl 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 tcx.is_lang_item(trait_def_id, TraitSolverLangItem::EffectsMin) { + G::consider_builtin_effects_min_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..f75c30eda99 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,65 @@ where ) -> Result, NoSolution> { panic!("`BikeshedIntrinsicFrom` does not have an associated type: {:?}", goal) } + + fn consider_builtin_effects_min_candidate( + ecx: &mut EvalCtxt<'_, D>, + goal: Goal, + ) -> Result, 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 { + 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 { + let Some(kind) = ty::EffectKind::try_from_ty(cx, ty) else { + return Err(NoSolution); + }; + + let Some(result) = ty::EffectKind::min(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 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..8c6e5eb5a4d 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_min_candidate( + ecx: &mut EvalCtxt<'_, D>, + goal: Goal, + ) -> Result, 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 + .into_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 { + let Some(kind) = ty::EffectKind::try_from_ty(ecx.cx(), ty) else { + return Err(NoSolution); + }; + + let Some(result) = ty::EffectKind::min(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 EvalCtxt<'_, D> diff --git a/compiler/rustc_type_ir/src/effects.rs b/compiler/rustc_type_ir/src/effects.rs new file mode 100644 index 00000000000..259072de6e7 --- /dev/null +++ b/compiler/rustc_type_ir/src/effects.rs @@ -0,0 +1,56 @@ +use crate::lang_items::TraitSolverLangItem::{EffectsMaybe, EffectsRuntime, EffectsNoRuntime}; +use crate::Interner; +use crate::inherent::{AdtDef, IntoKind, Ty}; + +#[derive(Clone, Copy, PartialEq, Eq)] +pub enum EffectKind { + Maybe, + Runtime, + NoRuntime, +} + +impl EffectKind { + pub fn try_from_def_id(tcx: I, def_id: I::DefId) -> Option { + if tcx.is_lang_item(def_id, EffectsMaybe) { + Some(EffectKind::Maybe) + } else if tcx.is_lang_item(def_id, EffectsRuntime) { + Some(EffectKind::Runtime) + } else if tcx.is_lang_item(def_id, EffectsNoRuntime) { + Some(EffectKind::NoRuntime) + } else { + None + } + } + + pub fn to_def_id(self, tcx: I) -> I::DefId { + let lang_item = match self { + EffectKind::Maybe => EffectsMaybe, + EffectKind::NoRuntime => EffectsNoRuntime, + EffectKind::Runtime => EffectsRuntime, + }; + + tcx.require_lang_item(lang_item) + } + + pub fn try_from_ty(tcx: I, ty: I::Ty) -> Option { + if let crate::Adt(def, _) = ty.kind() { + Self::try_from_def_id(tcx, def.def_id()) + } else { + None + } + } + + pub fn to_ty(self, tcx: I) -> I::Ty { + I::Ty::new_adt(tcx, tcx.adt_def(self.to_def_id(tcx)), Default::default()) + } + + pub fn min(a: Self, b: Self) -> Option { + use EffectKind::*; + match (a, b) { + (Maybe, x) | (x, Maybe) => Some(x), + (Runtime, Runtime) => Some(Runtime), + (NoRuntime, NoRuntime) => Some(NoRuntime), + (Runtime, NoRuntime) | (NoRuntime, Runtime) => None, + } + } +} \ No newline at end of file diff --git a/compiler/rustc_type_ir/src/lang_items.rs b/compiler/rustc_type_ir/src/lang_items.rs index cf5ec1ab3fe..55b9709b668 100644 --- a/compiler/rustc_type_ir/src/lang_items.rs +++ b/compiler/rustc_type_ir/src/lang_items.rs @@ -17,6 +17,11 @@ pub enum TraitSolverLangItem { Destruct, DiscriminantKind, DynMetadata, + EffectsMaybe, + EffectsMin, + EffectsMinOutput, + EffectsNoRuntime, + EffectsRuntime, FnPtrTrait, FusedIterator, Future, diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index 9b8ca5efdda..d7442e7c89c 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -35,6 +35,7 @@ mod macros; mod binder; mod canonical; mod const_kind; +mod effects; mod flags; mod generic_arg; mod interner; @@ -51,6 +52,7 @@ pub use canonical::*; #[cfg(feature = "nightly")] pub use codec::*; pub use const_kind::*; +pub use effects::*; pub use flags::*; pub use generic_arg::*; pub use interner::*; diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index b3f3cc02126..b71bedaa194 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -1054,14 +1054,15 @@ pub mod effects { #[lang = "EffectsTyCompat"] #[marker] - pub trait TyCompat {} + pub trait TyCompat {} - impl TyCompat for T {} - impl TyCompat for Maybe {} + impl TyCompat for T {} + impl TyCompat for Maybe {} + impl TyCompat for T {} #[lang = "EffectsMin"] pub trait Min { #[lang = "EffectsMinOutput"] - type Output; + type Output: ?Sized; } } diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-run.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-run.rs index afc5b1c8369..ddb26505202 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-run.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-run.rs @@ -1,4 +1,5 @@ //@ run-pass +//@ compile-flags: -Znext-solver #![feature(const_trait_impl, effects)] //~ WARN the feature `effects` is incomplete