diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index d49eb4ece99..3c44acb1657 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -397,8 +397,8 @@ language_item_table! { EffectsRuntime, sym::EffectsRuntime, effects_runtime, Target::Struct, GenericRequirement::None; EffectsNoRuntime, sym::EffectsNoRuntime, effects_no_runtime, Target::Struct, GenericRequirement::None; EffectsMaybe, sym::EffectsMaybe, effects_maybe, Target::Struct, GenericRequirement::None; - EffectsMin, sym::EffectsMin, effects_min, Target::Trait, GenericRequirement::None; - EffectsMinOutput, sym::EffectsMinOutput, effects_min_output, Target::AssocTy, GenericRequirement::None; + EffectsIntersection, sym::EffectsIntersection, effects_intersection, Target::Trait, GenericRequirement::None; + EffectsIntersectionOutput, sym::EffectsIntersectionOutput, effects_intersection_output, Target::AssocTy, GenericRequirement::None; EffectsCompat, sym::EffectsCompat, effects_compat, Target::Trait, GenericRequirement::Exact(1); EffectsTyCompat, sym::EffectsTyCompat, effects_ty_compat, Target::Trait, GenericRequirement::Exact(1); } diff --git a/compiler/rustc_hir_analysis/src/bounds.rs b/compiler/rustc_hir_analysis/src/bounds.rs index 61b7dd8bb8c..c7ee89e73c2 100644 --- a/compiler/rustc_hir_analysis/src/bounds.rs +++ b/compiler/rustc_hir_analysis/src/bounds.rs @@ -71,16 +71,19 @@ impl<'tcx> Bounds<'tcx> { } // For `T: ~const Tr` or `T: const Tr`, we need to add an additional bound on the // associated type of `` and make sure that the effect is compatible. - if let Some(compat_val) = match (tcx.def_kind(defining_def_id), constness) { + let compat_val = match (tcx.def_kind(defining_def_id), constness) { // FIXME(effects): revisit the correctness of this - (_, ty::BoundConstness::Const) => Some(tcx.consts.false_), + (_, ty::BoundConstness::Const) => tcx.consts.false_, // body owners that can have trait bounds (DefKind::Const | DefKind::Fn | DefKind::AssocFn, ty::BoundConstness::ConstIfConst) => { - Some(tcx.expected_host_effect_param_for_body(defining_def_id)) + tcx.expected_host_effect_param_for_body(defining_def_id) } (_, ty::BoundConstness::NotConst) => { - tcx.has_attr(bound_trait_ref.def_id(), sym::const_trait).then_some(tcx.consts.true_) + if !tcx.has_attr(bound_trait_ref.def_id(), sym::const_trait) { + return; + } + tcx.consts.true_ } ( @@ -97,8 +100,12 @@ impl<'tcx> Bounds<'tcx> { let ty = bound_trait_ref .map_bound(|trait_ref| Ty::new_projection(tcx, assoc, trait_ref.args)); - // Replace the binder with dummy types/lifetimes. This should work for any - // binder as long as they don't have any bounds e.g. `for`. + // When the user has written `for<'a, T> X<'a, T>: ~const Foo`, replace the + // binders to dummy ones i.e. `X<'static, ()>` so they can be referenced in + // the `Min` associated type properly (which doesn't allow using `for<>`) + // This should work for any bound variables as long as they don't have any + // bounds e.g. `for`. + // FIXME(effects) reconsider this approach to allow compatibility with `for` let ty = tcx.replace_bound_vars_uncached( ty, FnMutDelegate { @@ -128,24 +135,23 @@ impl<'tcx> Bounds<'tcx> { tcx.dcx().span_delayed_bug(span, "invalid `~const` encountered"); return; } - } { - // create a new projection type `::Effects` - let Some(assoc) = tcx.associated_type_for_effects(bound_trait_ref.def_id()) else { - tcx.dcx().span_delayed_bug( - span, - "`~const` trait bound has no effect assoc yet no errors encountered?", - ); - return; - }; - let self_ty = Ty::new_projection(tcx, assoc, bound_trait_ref.skip_binder().args); - // make `::Effects: Compat` - let new_trait_ref = ty::TraitRef::new( - tcx, - tcx.require_lang_item(LangItem::EffectsCompat, Some(span)), - [ty::GenericArg::from(self_ty), compat_val.into()], + }; + // create a new projection type `::Effects` + let Some(assoc) = tcx.associated_type_for_effects(bound_trait_ref.def_id()) else { + tcx.dcx().span_delayed_bug( + span, + "`~const` trait bound has no effect assoc yet no errors encountered?", ); - self.clauses.push((bound_trait_ref.rebind(new_trait_ref).upcast(tcx), span)); - } + return; + }; + let self_ty = Ty::new_projection(tcx, assoc, bound_trait_ref.skip_binder().args); + // make `::Effects: Compat` + let new_trait_ref = ty::TraitRef::new( + tcx, + tcx.require_lang_item(LangItem::EffectsCompat, Some(span)), + [ty::GenericArg::from(self_ty), compat_val.into()], + ); + self.clauses.push((bound_trait_ref.rebind(new_trait_ref).upcast(tcx), span)); } pub fn push_projection_bound( diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs index b32067ebd6a..c03e074c80b 100644 --- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs +++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs @@ -137,7 +137,7 @@ pub(super) fn explicit_item_bounds_with_filter( let tup = Ty::new(tcx, ty::Tuple(preds.effects_min_tys)); // FIXME(effects) span let span = tcx.def_span(def_id); - let assoc = tcx.require_lang_item(hir::LangItem::EffectsMinOutput, Some(span)); + let assoc = tcx.require_lang_item(hir::LangItem::EffectsIntersectionOutput, Some(span)); let proj = Ty::new_projection(tcx, assoc, [tup]); let self_proj = Ty::new_projection( tcx, diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index c0ebad9616d..fabbec68350 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -599,8 +599,8 @@ fn trait_lang_item_to_lang_item(lang_item: TraitSolverLangItem) -> LangItem { TraitSolverLangItem::DiscriminantKind => LangItem::DiscriminantKind, TraitSolverLangItem::DynMetadata => LangItem::DynMetadata, TraitSolverLangItem::EffectsMaybe => LangItem::EffectsMaybe, - TraitSolverLangItem::EffectsMin => LangItem::EffectsMin, - TraitSolverLangItem::EffectsMinOutput => LangItem::EffectsMinOutput, + TraitSolverLangItem::EffectsIntersection => LangItem::EffectsIntersection, + TraitSolverLangItem::EffectsIntersectionOutput => LangItem::EffectsIntersectionOutput, TraitSolverLangItem::EffectsNoRuntime => LangItem::EffectsNoRuntime, TraitSolverLangItem::EffectsRuntime => LangItem::EffectsRuntime, TraitSolverLangItem::FnPtrTrait => LangItem::FnPtrTrait, 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 8d57c3d9af0..6ee684605ac 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs @@ -270,7 +270,7 @@ where goal: Goal, ) -> Vec>; - fn consider_builtin_effects_min_candidate( + fn consider_builtin_effects_intersection_candidate( ecx: &mut EvalCtxt<'_, D>, goal: Goal, ) -> Result, NoSolution>; @@ -425,8 +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 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 7a81c210c5d..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 @@ -865,7 +865,7 @@ where panic!("`BikeshedIntrinsicFrom` does not have an associated type: {:?}", goal) } - fn consider_builtin_effects_min_candidate( + fn consider_builtin_effects_intersection_candidate( ecx: &mut EvalCtxt<'_, D>, goal: Goal, ) -> Result, NoSolution> { @@ -903,11 +903,15 @@ where 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::min(min, kind) else { + let Some(result) = ty::EffectKind::intersection(min, kind) else { return Err(NoSolution); }; 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 08ed729b144..f5832f7e5b4 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -703,7 +703,7 @@ where }) } - fn consider_builtin_effects_min_candidate( + fn consider_builtin_effects_intersection_candidate( ecx: &mut EvalCtxt<'_, D>, goal: Goal, ) -> Result, NoSolution> { @@ -732,7 +732,7 @@ where return Err(NoSolution); }; - let Some(result) = ty::EffectKind::min(min, kind) else { + let Some(result) = ty::EffectKind::intersection(min, kind) else { return Err(NoSolution); }; diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 4a26e8ae097..8b7a63f5eb9 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -195,9 +195,9 @@ symbols! { DoubleEndedIterator, Duration, EffectsCompat, + EffectsIntersection, + EffectsIntersectionOutput, EffectsMaybe, - EffectsMin, - EffectsMinOutput, EffectsNoRuntime, EffectsRuntime, EffectsTyCompat, diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs index 6a55e83786c..6726db8bb54 100644 --- a/compiler/rustc_ty_utils/src/assoc.rs +++ b/compiler/rustc_ty_utils/src/assoc.rs @@ -184,12 +184,10 @@ fn associated_type_for_effects(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option { let trait_def_id = def_id; - let Some(attr) = tcx.get_attr(def_id, sym::const_trait) else { - return None; - }; + let attr = tcx.get_attr(def_id, sym::const_trait)?; let span = attr.span; let trait_assoc_ty = tcx.at(span).create_def(trait_def_id, kw::Empty, DefKind::AssocTy); @@ -197,8 +195,6 @@ fn associated_type_for_effects(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option, def_id: LocalDefId) -> Option { let impl_def_id = def_id; - let Some(trait_id) = tcx.trait_id_of_impl(def_id.to_def_id()) else { return None }; + let trait_id = tcx.trait_id_of_impl(def_id.to_def_id())?; // first get the DefId of the assoc type on the trait, if there is not, // then we don't need to generate it on the impl. - let Some(trait_assoc_id) = tcx.associated_type_for_effects(trait_id) else { - return None; - }; + let trait_assoc_id = tcx.associated_type_for_effects(trait_id)?; // FIXME(effects): span let span = tcx.def_ident_span(def_id).unwrap(); @@ -263,8 +232,6 @@ fn associated_type_for_effects(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option, def_id: LocalDefId) -> Option, def_id: LocalDefId) -> Option bug!( "associated_type_for_effects: {:?} should be Trait or Impl but is {:?}", def_id, def_kind ), - } + }; + + feed.feed_hir(); + + // visibility is public. + feed.visibility(ty::Visibility::Public); + + // Copy generics_of of the trait/impl, making the trait/impl as parent. + feed.generics_of({ + let parent_generics = tcx.generics_of(parent_did); + let parent_count = parent_generics.parent_count + parent_generics.own_params.len(); + + ty::Generics { + parent: Some(parent_did.to_def_id()), + parent_count, + own_params: vec![], + param_def_id_to_index: parent_generics.param_def_id_to_index.clone(), + has_self: false, + has_late_bound_regions: None, + host_effect_index: parent_generics.host_effect_index, + } + }); + feed.explicit_item_super_predicates(ty::EarlyBinder::bind(&[])); + + // There are no inferred outlives for the synthesized associated type. + feed.inferred_outlives_of(&[]); + + Some(feed.def_id().to_def_id()) } /// Given an `fn_def_id` of a trait or a trait implementation: diff --git a/compiler/rustc_type_ir/src/effects.rs b/compiler/rustc_type_ir/src/effects.rs index 39605936e30..f7942f2f982 100644 --- a/compiler/rustc_type_ir/src/effects.rs +++ b/compiler/rustc_type_ir/src/effects.rs @@ -44,7 +44,10 @@ impl EffectKind { I::Ty::new_adt(tcx, tcx.adt_def(self.to_def_id(tcx)), Default::default()) } - pub fn min(a: Self, b: Self) -> Option { + /// Returns an intersection between two effect kinds. If one effect kind + /// is more permissive than the other (e.g. `Maybe` vs `Runtime`), this + /// returns the less permissive effect kind (`Runtime`). + pub fn intersection(a: Self, b: Self) -> Option { use EffectKind::*; match (a, b) { (Maybe, x) | (x, Maybe) => Some(x), diff --git a/compiler/rustc_type_ir/src/lang_items.rs b/compiler/rustc_type_ir/src/lang_items.rs index 55b9709b668..cf00c37caa2 100644 --- a/compiler/rustc_type_ir/src/lang_items.rs +++ b/compiler/rustc_type_ir/src/lang_items.rs @@ -17,9 +17,9 @@ pub enum TraitSolverLangItem { Destruct, DiscriminantKind, DynMetadata, + EffectsIntersection, + EffectsIntersectionOutput, EffectsMaybe, - EffectsMin, - EffectsMinOutput, EffectsNoRuntime, EffectsRuntime, FnPtrTrait, diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index 042acbf20b1..9f5818f675d 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -1062,9 +1062,14 @@ pub mod effects { impl TyCompat for Maybe {} impl TyCompat for T {} - #[lang = "EffectsMin"] - pub trait Min { - #[lang = "EffectsMinOutput"] + #[lang = "EffectsIntersection"] + pub trait Intersection { + #[lang = "EffectsIntersectionOutput"] type Output: ?Sized; } + + // FIXME(effects): remove this after next trait solver lands + impl Intersection for () { + type Output = Maybe; + } } diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.fixed b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.fixed index 921dcf0b162..f8fc935f367 100644 --- a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.fixed +++ b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.fixed @@ -104,15 +104,18 @@ fn main() {} struct D; +/* FIXME(effects) impl const Drop for D { fn drop(&mut self) { todo!(); } } +*/ // Lint this, since it can be dropped in const contexts // FIXME(effects) -fn d(this: D) {} +const fn d(this: D) {} +//~^ ERROR: this could be a `const fn` mod msrv { struct Foo(*const u8, &'static u8); diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr index 8ba42c0e5b6..8302b074127 100644 --- a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr +++ b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr @@ -161,6 +161,11 @@ error: this could be a `const fn` | LL | fn d(this: D) {} | ^^^^^^^^^^^^^^^^ + | +help: make the function `const` + | +LL | const fn d(this: D) {} + | +++++ error: this could be a `const fn` --> tests/ui/missing_const_for_fn/could_be_const.rs:125:9 diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-fns-are-early-bound.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-fns-are-early-bound.rs index fdc53dbab1c..b3087349e4d 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-fns-are-early-bound.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-fns-are-early-bound.rs @@ -126,10 +126,10 @@ pub mod effects { #[stable(feature = "minicore", since = "1.0.0")] impl TyCompat for T {} - #[lang = "EffectsMin"] + #[lang = "EffectsIntersection"] #[stable(feature = "minicore", since = "1.0.0")] - pub trait Min { - #[lang = "EffectsMinOutput"] + pub trait Intersection { + #[lang = "EffectsIntersectionOutput"] #[stable(feature = "minicore", since = "1.0.0")] type Output: ?Sized; } diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail.rs index bb8e06ab2f7..637a24f53bc 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail.rs @@ -1,4 +1,5 @@ //@ check-pass +//@ compile-flags: -Znext-solver #![allow(incomplete_features)] #![feature(const_trait_impl, effects)] diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits.rs index b32c8cab7ec..fbe89b00b97 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits.rs @@ -1,5 +1,7 @@ // FIXME(effects) check-pass //@ known-bug: #110395 +//@ compile-flags: -Znext-solver +#![allow(incomplete_features)] #![feature(const_trait_impl, effects)] #[const_trait] diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits.stderr index a9cb68a247c..5b6b39ee05e 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits.stderr @@ -1,20 +1,11 @@ -warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/super-traits.rs:3:30 - | -LL | #![feature(const_trait_impl, effects)] - | ^^^^^^^ - | - = note: see issue #102090 for more information - = note: `#[warn(incomplete_features)]` on by default - error[E0277]: the trait bound `Foo::{synthetic#0}: ~const Compat` is not satisfied - --> $DIR/super-traits.rs:21:7 + --> $DIR/super-traits.rs:23:7 | LL | t.a(); | ^ the trait `~const Compat` is not implemented for `Foo::{synthetic#0}` | note: required by a bound in `Foo::a` - --> $DIR/super-traits.rs:5:1 + --> $DIR/super-traits.rs:7:1 | LL | #[const_trait] | ^^^^^^^^^^^^^^ required by this bound in `Foo::a` @@ -26,6 +17,6 @@ help: consider further restricting the associated type LL | const fn foo(t: &T) where Foo::{synthetic#0}: ~const Compat { | +++++++++++++++++++++++++++++++++++++++ -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0277`.