diff options
Diffstat (limited to 'compiler')
96 files changed, 1283 insertions, 1445 deletions
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index c43106c6e5f..97fa90d340e 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -57,7 +57,7 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> { owner: NodeId, f: impl FnOnce(&mut LoweringContext<'_, 'hir>) -> hir::OwnerNode<'hir>, ) { - let mut lctx = LoweringContext::new(self.tcx, self.resolver, self.ast_index); + let mut lctx = LoweringContext::new(self.tcx, self.resolver); lctx.with_hir_id_owner(owner, |lctx| f(lctx)); for (def_id, info) in lctx.children { @@ -193,8 +193,6 @@ impl<'hir> LoweringContext<'_, 'hir> { ItemKind::Const(box ast::ConstItem { generics, ty, expr, .. }) => { let (generics, (ty, body_id)) = self.lower_generics( generics, - Const::No, - false, id, ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| { @@ -225,16 +223,9 @@ impl<'hir> LoweringContext<'_, 'hir> { ); let itctx = ImplTraitContext::Universal; - let (generics, decl) = - this.lower_generics(generics, header.constness, false, id, itctx, |this| { - this.lower_fn_decl( - decl, - id, - *fn_sig_span, - FnDeclKind::Fn, - coroutine_kind, - ) - }); + let (generics, decl) = this.lower_generics(generics, id, itctx, |this| { + this.lower_fn_decl(decl, id, *fn_sig_span, FnDeclKind::Fn, coroutine_kind) + }); let sig = hir::FnSig { decl, header: this.lower_fn_header(*header, hir::Safety::Safe), @@ -269,8 +260,6 @@ impl<'hir> LoweringContext<'_, 'hir> { add_ty_alias_where_clause(&mut generics, *where_clauses, true); let (generics, ty) = self.lower_generics( &generics, - Const::No, - false, id, ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| match ty { @@ -294,8 +283,6 @@ impl<'hir> LoweringContext<'_, 'hir> { ItemKind::Enum(enum_definition, generics) => { let (generics, variants) = self.lower_generics( generics, - Const::No, - false, id, ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| { @@ -309,8 +296,6 @@ impl<'hir> LoweringContext<'_, 'hir> { ItemKind::Struct(struct_def, generics) => { let (generics, struct_def) = self.lower_generics( generics, - Const::No, - false, id, ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| this.lower_variant_data(hir_id, struct_def), @@ -320,8 +305,6 @@ impl<'hir> LoweringContext<'_, 'hir> { ItemKind::Union(vdata, generics) => { let (generics, vdata) = self.lower_generics( generics, - Const::No, - false, id, ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| this.lower_variant_data(hir_id, vdata), @@ -353,7 +336,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // parent lifetime. let itctx = ImplTraitContext::Universal; let (generics, (trait_ref, lowered_ty)) = - self.lower_generics(ast_generics, Const::No, false, id, itctx, |this| { + self.lower_generics(ast_generics, id, itctx, |this| { let modifiers = TraitBoundModifiers { constness: BoundConstness::Never, asyncness: BoundAsyncness::Normal, @@ -405,8 +388,6 @@ impl<'hir> LoweringContext<'_, 'hir> { ItemKind::Trait(box Trait { is_auto, safety, generics, bounds, items }) => { let (generics, (safety, items, bounds)) = self.lower_generics( generics, - Const::No, - false, id, ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| { @@ -426,8 +407,6 @@ impl<'hir> LoweringContext<'_, 'hir> { ItemKind::TraitAlias(generics, bounds) => { let (generics, bounds) = self.lower_generics( generics, - Const::No, - false, id, ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| { @@ -604,50 +583,23 @@ impl<'hir> LoweringContext<'_, 'hir> { ctxt: AssocCtxt, parent_hir: &'hir hir::OwnerInfo<'hir>, ) -> hir::OwnerNode<'hir> { - // Evaluate with the lifetimes in `params` in-scope. - // This is used to track which lifetimes have already been defined, - // and which need to be replicated when lowering an async fn. - let parent_item = parent_hir.node().expect_item(); - let constness = match parent_item.kind { + match parent_item.kind { hir::ItemKind::Impl(impl_) => { self.is_in_trait_impl = impl_.of_trait.is_some(); - // N.B. the impl should always lower to methods that have `const host: bool` params if the trait - // is const. It doesn't matter whether the `impl` itself is const. Disallowing const fn from - // calling non-const impls are done through associated types. - if let Some(def_id) = impl_.of_trait.and_then(|tr| tr.trait_def_id()) { - if let Some(local_def) = def_id.as_local() { - match &self.ast_index[local_def] { - AstOwner::Item(ast::Item { attrs, .. }) => attrs - .iter() - .find(|attr| attr.has_name(sym::const_trait)) - .map_or(Const::No, |attr| Const::Yes(attr.span)), - _ => Const::No, - } - } else if self.tcx.is_const_trait(def_id) { - // FIXME(effects) span - Const::Yes(self.tcx.def_ident_span(def_id).unwrap()) - } else { - Const::No - } - } else { - Const::No - } } - hir::ItemKind::Trait(_, _, _, _, _) => parent_hir - .attrs - .get(parent_item.hir_id().local_id) - .iter() - .find(|attr| attr.has_name(sym::const_trait)) - .map_or(Const::No, |attr| Const::Yes(attr.span)), + hir::ItemKind::Trait(_, _, _, _, _) => {} kind => { span_bug!(item.span, "assoc item has unexpected kind of parent: {}", kind.descr()) } - }; + } + // Evaluate with the lifetimes in `params` in-scope. + // This is used to track which lifetimes have already been defined, + // and which need to be replicated when lowering an async fn. match ctxt { - AssocCtxt::Trait => hir::OwnerNode::TraitItem(self.lower_trait_item(item, constness)), - AssocCtxt::Impl => hir::OwnerNode::ImplItem(self.lower_impl_item(item, constness)), + AssocCtxt::Trait => hir::OwnerNode::TraitItem(self.lower_trait_item(item)), + AssocCtxt::Impl => hir::OwnerNode::ImplItem(self.lower_impl_item(item)), } } @@ -663,7 +615,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let fdec = &sig.decl; let itctx = ImplTraitContext::Universal; let (generics, (decl, fn_args)) = - self.lower_generics(generics, Const::No, false, i.id, itctx, |this| { + self.lower_generics(generics, i.id, itctx, |this| { ( // Disallow `impl Trait` in foreign items. this.lower_fn_decl( @@ -775,11 +727,7 @@ impl<'hir> LoweringContext<'_, 'hir> { } } - fn lower_trait_item( - &mut self, - i: &AssocItem, - trait_constness: Const, - ) -> &'hir hir::TraitItem<'hir> { + fn lower_trait_item(&mut self, i: &AssocItem) -> &'hir hir::TraitItem<'hir> { let hir_id = self.lower_node_id(i.id); self.lower_attrs(hir_id, &i.attrs); let trait_item_def_id = hir_id.expect_owner(); @@ -788,8 +736,6 @@ impl<'hir> LoweringContext<'_, 'hir> { AssocItemKind::Const(box ConstItem { generics, ty, expr, .. }) => { let (generics, kind) = self.lower_generics( generics, - Const::No, - false, i.id, ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| { @@ -810,7 +756,6 @@ impl<'hir> LoweringContext<'_, 'hir> { i.id, FnDeclKind::Trait, sig.header.coroutine_kind, - trait_constness, ); (generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Required(names)), false) } @@ -829,7 +774,6 @@ impl<'hir> LoweringContext<'_, 'hir> { i.id, FnDeclKind::Trait, sig.header.coroutine_kind, - trait_constness, ); (generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Provided(body_id)), true) } @@ -838,8 +782,6 @@ impl<'hir> LoweringContext<'_, 'hir> { add_ty_alias_where_clause(&mut generics, *where_clauses, false); let (generics, kind) = self.lower_generics( &generics, - Const::No, - false, i.id, ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| { @@ -912,11 +854,7 @@ impl<'hir> LoweringContext<'_, 'hir> { self.expr(span, hir::ExprKind::Err(guar)) } - fn lower_impl_item( - &mut self, - i: &AssocItem, - constness_of_trait: Const, - ) -> &'hir hir::ImplItem<'hir> { + fn lower_impl_item(&mut self, i: &AssocItem) -> &'hir hir::ImplItem<'hir> { // Since `default impl` is not yet implemented, this is always true in impls. let has_value = true; let (defaultness, _) = self.lower_defaultness(i.kind.defaultness(), has_value); @@ -926,8 +864,6 @@ impl<'hir> LoweringContext<'_, 'hir> { let (generics, kind) = match &i.kind { AssocItemKind::Const(box ConstItem { generics, ty, expr, .. }) => self.lower_generics( generics, - Const::No, - false, i.id, ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| { @@ -953,7 +889,6 @@ impl<'hir> LoweringContext<'_, 'hir> { i.id, if self.is_in_trait_impl { FnDeclKind::Impl } else { FnDeclKind::Inherent }, sig.header.coroutine_kind, - constness_of_trait, ); (generics, hir::ImplItemKind::Fn(sig, body_id)) @@ -963,8 +898,6 @@ impl<'hir> LoweringContext<'_, 'hir> { add_ty_alias_where_clause(&mut generics, *where_clauses, false); self.lower_generics( &generics, - Const::No, - false, i.id, ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| match ty { @@ -1370,18 +1303,12 @@ impl<'hir> LoweringContext<'_, 'hir> { id: NodeId, kind: FnDeclKind, coroutine_kind: Option<CoroutineKind>, - parent_constness: Const, ) -> (&'hir hir::Generics<'hir>, hir::FnSig<'hir>) { let header = self.lower_fn_header(sig.header, hir::Safety::Safe); - // Don't pass along the user-provided constness of trait associated functions; we don't want to - // synthesize a host effect param for them. We reject `const` on them during AST validation. - let constness = - if kind == FnDeclKind::Inherent { sig.header.constness } else { parent_constness }; let itctx = ImplTraitContext::Universal; - let (generics, decl) = - self.lower_generics(generics, constness, kind == FnDeclKind::Impl, id, itctx, |this| { - this.lower_fn_decl(&sig.decl, id, sig.span, kind, coroutine_kind) - }); + let (generics, decl) = self.lower_generics(generics, id, itctx, |this| { + this.lower_fn_decl(&sig.decl, id, sig.span, kind, coroutine_kind) + }); (generics, hir::FnSig { header, decl, span: self.lower_span(sig.span) }) } @@ -1460,8 +1387,6 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_generics<T>( &mut self, generics: &Generics, - constness: Const, - force_append_constness: bool, parent_node_id: NodeId, itctx: ImplTraitContext, f: impl FnOnce(&mut Self) -> T, @@ -1524,30 +1449,6 @@ impl<'hir> LoweringContext<'_, 'hir> { } } - // Desugar `~const` bound in generics into an additional `const host: bool` param - // if the effects feature is enabled. This needs to be done before we lower where - // clauses since where clauses need to bind to the DefId of the host param - let host_param_parts = if let Const::Yes(span) = constness - // if this comes from implementing a `const` trait, we must force constness to be appended - // to the impl item, no matter whether effects is enabled. - && (self.tcx.features().effects() || force_append_constness) - { - let span = self.lower_span(span); - let param_node_id = self.next_node_id(); - let hir_id = self.next_id(); - let def_id = self.create_def( - self.local_def_id(parent_node_id), - param_node_id, - sym::host, - DefKind::ConstParam, - span, - ); - self.host_param_id = Some(def_id); - Some((span, hir_id, def_id)) - } else { - None - }; - let mut predicates: SmallVec<[hir::WherePredicate<'hir>; 4]> = SmallVec::new(); predicates.extend(generics.params.iter().filter_map(|param| { self.lower_generic_bound_predicate( @@ -1595,74 +1496,6 @@ impl<'hir> LoweringContext<'_, 'hir> { let impl_trait_bounds = std::mem::take(&mut self.impl_trait_bounds); predicates.extend(impl_trait_bounds.into_iter()); - if let Some((span, hir_id, def_id)) = host_param_parts { - let const_node_id = self.next_node_id(); - let anon_const_did = - self.create_def(def_id, const_node_id, kw::Empty, DefKind::AnonConst, span); - - let const_id = self.next_id(); - let const_expr_id = self.next_id(); - let bool_id = self.next_id(); - - self.children.push((def_id, hir::MaybeOwner::NonOwner(hir_id))); - self.children.push((anon_const_did, hir::MaybeOwner::NonOwner(const_id))); - - let const_body = self.lower_body(|this| { - (&[], hir::Expr { - hir_id: const_expr_id, - kind: hir::ExprKind::Lit( - this.arena.alloc(hir::Lit { node: LitKind::Bool(true), span }), - ), - span, - }) - }); - - let default_ac = self.arena.alloc(hir::AnonConst { - def_id: anon_const_did, - hir_id: const_id, - body: const_body, - span, - }); - let default_ct = self.arena.alloc(hir::ConstArg { - hir_id: self.next_id(), - kind: hir::ConstArgKind::Anon(default_ac), - is_desugared_from_effects: false, - }); - let param = hir::GenericParam { - def_id, - hir_id, - name: hir::ParamName::Plain(Ident { name: sym::host, span }), - span, - kind: hir::GenericParamKind::Const { - ty: self.arena.alloc(self.ty( - span, - hir::TyKind::Path(hir::QPath::Resolved( - None, - self.arena.alloc(hir::Path { - res: Res::PrimTy(hir::PrimTy::Bool), - span, - segments: self.arena.alloc_from_iter([hir::PathSegment { - ident: Ident { name: sym::bool, span }, - hir_id: bool_id, - res: Res::PrimTy(hir::PrimTy::Bool), - args: None, - infer_args: false, - }]), - }), - )), - )), - default: Some(default_ct), - is_host_effect: true, - synthetic: true, - }, - colon_span: None, - pure_wrt_drop: false, - source: hir::GenericParamSource::Generics, - }; - - params.push(param); - } - let lowered_generics = self.arena.alloc(hir::Generics { params: self.arena.alloc_from_iter(params), predicates: self.arena.alloc_from_iter(predicates), diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 7cd0cd1ebcd..34b8137aea8 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -154,17 +154,10 @@ struct LoweringContext<'a, 'hir> { /// defined on the TAIT, so we have type Foo<'a1> = ... and we establish a mapping in this /// field from the original parameter 'a to the new parameter 'a1. generics_def_id_map: Vec<LocalDefIdMap<LocalDefId>>, - - host_param_id: Option<LocalDefId>, - ast_index: &'a IndexSlice<LocalDefId, AstOwner<'a>>, } impl<'a, 'hir> LoweringContext<'a, 'hir> { - fn new( - tcx: TyCtxt<'hir>, - resolver: &'a mut ResolverAstLowering, - ast_index: &'a IndexSlice<LocalDefId, AstOwner<'a>>, - ) -> Self { + fn new(tcx: TyCtxt<'hir>, resolver: &'a mut ResolverAstLowering) -> Self { Self { // Pseudo-globals. tcx, @@ -204,8 +197,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // interact with `gen`/`async gen` blocks allow_async_iterator: [sym::gen_future, sym::async_iterator].into(), generics_def_id_map: Default::default(), - host_param_id: None, - ast_index, } } @@ -2054,11 +2045,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { param: &GenericParam, source: hir::GenericParamSource, ) -> hir::GenericParam<'hir> { - let (name, kind) = self.lower_generic_param_kind( - param, - source, - attr::contains_name(¶m.attrs, sym::rustc_runtime), - ); + let (name, kind) = self.lower_generic_param_kind(param, source); let hir_id = self.lower_node_id(param.id); self.lower_attrs(hir_id, ¶m.attrs); @@ -2078,7 +2065,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { &mut self, param: &GenericParam, source: hir::GenericParamSource, - is_host_effect: bool, ) -> (hir::ParamName, hir::GenericParamKind<'hir>) { match ¶m.kind { GenericParamKind::Lifetime => { @@ -2144,7 +2130,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ( hir::ParamName::Plain(self.lower_ident(param.ident)), - hir::GenericParamKind::Const { ty, default, is_host_effect, synthetic: false }, + hir::GenericParamKind::Const { ty, default, synthetic: false }, ) } } diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 753195bf691..5921fbc0fd7 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -838,10 +838,6 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ rustc_const_panic_str, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::Yes, INTERNAL_UNSTABLE ), - rustc_attr!( - rustc_runtime, Normal, template!(Word), WarnFollowing, - EncodeCrossCrate::No, INTERNAL_UNSTABLE - ), // ========================================================================== // Internal attributes, Layout related: diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 45be04c6db9..1c268c8bbe0 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -580,7 +580,6 @@ pub enum GenericParamKind<'hir> { ty: &'hir Ty<'hir>, /// Optional default value for the const generic param default: Option<&'hir ConstArg<'hir>>, - is_host_effect: bool, synthetic: bool, }, } diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index ffe519b0e7d..322f8e2a517 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -935,7 +935,7 @@ pub fn walk_generic_param<'v, V: Visitor<'v>>( match param.kind { GenericParamKind::Lifetime { .. } => {} GenericParamKind::Type { ref default, .. } => visit_opt!(visitor, visit_ty, default), - GenericParamKind::Const { ref ty, ref default, is_host_effect: _, synthetic: _ } => { + GenericParamKind::Const { ref ty, ref default, synthetic: _ } => { try_visit!(visitor.visit_ty(ty)); if let Some(ref default) = default { try_visit!(visitor.visit_const_param_default(param.hir_id, default)); diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index ae046c09ebe..7d81f977c22 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -415,14 +415,6 @@ language_item_table! { String, sym::String, string, Target::Struct, GenericRequirement::None; CStr, sym::CStr, c_str, Target::Struct, GenericRequirement::None; - - 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; - 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); } pub enum GenericRequirement { diff --git a/compiler/rustc_hir_analysis/src/bounds.rs b/compiler/rustc_hir_analysis/src/bounds.rs index 77df0cb7ef9..1121ca53240 100644 --- a/compiler/rustc_hir_analysis/src/bounds.rs +++ b/compiler/rustc_hir_analysis/src/bounds.rs @@ -3,13 +3,8 @@ use rustc_data_structures::fx::FxIndexMap; use rustc_hir::LangItem; -use rustc_hir::def::DefKind; -use rustc_middle::ty::fold::FnMutDelegate; use rustc_middle::ty::{self, Ty, TyCtxt, Upcast}; use rustc_span::Span; -use rustc_span::def_id::DefId; - -use crate::hir_ty_lowering::PredicateFilter; /// Collects together a list of type bounds. These lists of bounds occur in many places /// in Rust's syntax: @@ -47,12 +42,9 @@ impl<'tcx> Bounds<'tcx> { pub(crate) fn push_trait_bound( &mut self, tcx: TyCtxt<'tcx>, - defining_def_id: DefId, bound_trait_ref: ty::PolyTraitRef<'tcx>, span: Span, polarity: ty::PredicatePolarity, - constness: Option<ty::BoundConstness>, - predicate_filter: PredicateFilter, ) { let clause = ( bound_trait_ref @@ -68,137 +60,6 @@ impl<'tcx> Bounds<'tcx> { } else { self.clauses.push(clause); } - - // FIXME(effects): Lift this out of `push_trait_bound`, and move it somewhere else. - // Perhaps moving this into `lower_poly_trait_ref`, just like we lower associated - // type bounds. - if !tcx.features().effects() { - return; - } - match predicate_filter { - PredicateFilter::SelfOnly | PredicateFilter::SelfThatDefines(_) => { - return; - } - PredicateFilter::All | PredicateFilter::SelfAndAssociatedTypeBounds => { - // Ok. - } - } - - // For `T: ~const Tr` or `T: const Tr`, we need to add an additional bound on the - // associated type of `<T as Tr>` and make sure that the effect is compatible. - let compat_val = match (tcx.def_kind(defining_def_id), constness) { - // FIXME(effects): revisit the correctness of this - (_, Some(ty::BoundConstness::Const)) => tcx.consts.false_, - // body owners that can have trait bounds - ( - DefKind::Const | DefKind::Fn | DefKind::AssocFn, - Some(ty::BoundConstness::ConstIfConst), - ) => tcx.expected_host_effect_param_for_body(defining_def_id), - - (_, None) => { - if !tcx.is_const_trait(bound_trait_ref.def_id()) { - return; - } - tcx.consts.true_ - } - (DefKind::Trait, Some(ty::BoundConstness::ConstIfConst)) => { - // we are in a trait, where `bound_trait_ref` could be: - // (1) a super trait `trait Foo: ~const Bar`. - // - This generates `<Self as Foo>::Effects: TyCompat<<Self as Bar>::Effects>` - // - // (2) a where clause `where for<..> Something: ~const Bar`. - // - This generates `for<..> <Self as Foo>::Effects: TyCompat<<Something as Bar>::Effects>` - let Some(own_fx) = tcx.associated_type_for_effects(defining_def_id) else { - tcx.dcx().span_delayed_bug(span, "should not have allowed `~const` on a trait that doesn't have `#[const_trait]`"); - return; - }; - let own_fx_ty = Ty::new_projection( - tcx, - own_fx, - ty::GenericArgs::identity_for_item(tcx, own_fx), - ); - let Some(their_fx) = tcx.associated_type_for_effects(bound_trait_ref.def_id()) - else { - tcx.dcx().span_delayed_bug(span, "`~const` on trait without Effects assoc"); - return; - }; - let their_fx_ty = - Ty::new_projection(tcx, their_fx, bound_trait_ref.skip_binder().args); - let compat = tcx.require_lang_item(LangItem::EffectsTyCompat, Some(span)); - let clause = bound_trait_ref - .map_bound(|_| { - let trait_ref = ty::TraitRef::new(tcx, compat, [own_fx_ty, their_fx_ty]); - ty::ClauseKind::Trait(ty::TraitPredicate { - trait_ref, - polarity: ty::PredicatePolarity::Positive, - }) - }) - .upcast(tcx); - - self.clauses.push((clause, span)); - return; - } - - (DefKind::Impl { of_trait: true }, Some(ty::BoundConstness::ConstIfConst)) => { - // this is a where clause on an impl header. - // push `<T as Tr>::Effects` into the set for the `Min` bound. - let Some(assoc) = tcx.associated_type_for_effects(bound_trait_ref.def_id()) else { - tcx.dcx().span_delayed_bug(span, "`~const` on trait without Effects assoc"); - return; - }; - - let ty = bound_trait_ref - .map_bound(|trait_ref| Ty::new_projection(tcx, assoc, trait_ref.args)); - - // 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<T: Trait>`. - // FIXME(effects) reconsider this approach to allow compatibility with `for<T: Tr>` - let ty = tcx.replace_bound_vars_uncached(ty, FnMutDelegate { - regions: &mut |_| tcx.lifetimes.re_static, - types: &mut |_| tcx.types.unit, - consts: &mut |_| unimplemented!("`~const` does not support const binders"), - }); - - self.effects_min_tys.insert(ty, span); - return; - } - // for - // ``` - // trait Foo { type Bar: ~const Trait } - // ``` - // ensure that `<Self::Bar as Trait>::Effects: TyCompat<Self::Effects>`. - // - // FIXME(effects) this is equality for now, which wouldn't be helpful for a non-const implementor - // that uses a `Bar` that implements `Trait` with `Maybe` effects. - (DefKind::AssocTy, Some(ty::BoundConstness::ConstIfConst)) => { - // FIXME(effects): implement this - return; - } - // probably illegal in this position. - (_, Some(ty::BoundConstness::ConstIfConst)) => { - tcx.dcx().span_delayed_bug(span, "invalid `~const` encountered"); - return; - } - }; - // create a new projection type `<T as Tr>::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 `<T as Tr>::Effects: Compat<runtime>` - 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(crate) fn push_projection_bound( @@ -220,6 +81,21 @@ impl<'tcx> Bounds<'tcx> { self.clauses.insert(0, (trait_ref.upcast(tcx), span)); } + /// Push a `const` or `~const` bound as a `HostEffect` predicate. + pub(crate) fn push_const_bound( + &mut self, + tcx: TyCtxt<'tcx>, + bound_trait_ref: ty::PolyTraitRef<'tcx>, + host: ty::HostPolarity, + span: Span, + ) { + if tcx.is_const_trait(bound_trait_ref.def_id()) { + self.clauses.push((bound_trait_ref.to_host_effect_clause(tcx, host), span)); + } else { + tcx.dcx().span_delayed_bug(span, "tried to lower {host:?} bound for non-const trait"); + } + } + pub(crate) fn clauses( &self, // FIXME(effects): remove tcx diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index 7a56b3784f8..02cf1a502f1 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -181,6 +181,7 @@ fn compare_method_predicate_entailment<'tcx>( }); // Create mapping from trait method to impl method. + let impl_def_id = impl_m.container_id(tcx); let trait_to_impl_args = GenericArgs::identity_for_item(tcx, impl_m.def_id).rebase_onto( tcx, impl_m.container_id(tcx), @@ -204,6 +205,24 @@ fn compare_method_predicate_entailment<'tcx>( trait_m_predicates.instantiate_own(tcx, trait_to_impl_args).map(|(predicate, _)| predicate), ); + // FIXME(effects): This should be replaced with a more dedicated method. + let is_conditionally_const = tcx.is_conditionally_const(impl_def_id); + if is_conditionally_const { + // Augment the hybrid param-env with the const conditions + // of the impl header and the trait method. + hybrid_preds.extend( + tcx.const_conditions(impl_def_id) + .instantiate_identity(tcx) + .into_iter() + .chain( + tcx.const_conditions(trait_m.def_id).instantiate_own(tcx, trait_to_impl_args), + ) + .map(|(trait_ref, _)| { + trait_ref.to_host_effect_clause(tcx, ty::HostPolarity::Maybe) + }), + ); + } + let normalize_cause = traits::ObligationCause::misc(impl_m_span, impl_m_def_id); let param_env = ty::ParamEnv::new(tcx.mk_clauses(&hybrid_preds), Reveal::UserFacing); let param_env = traits::normalize_param_env_or_error(tcx, param_env, normalize_cause); @@ -230,6 +249,34 @@ fn compare_method_predicate_entailment<'tcx>( ocx.register_obligation(traits::Obligation::new(tcx, cause, param_env, predicate)); } + // If we're within a const implementation, we need to make sure that the method + // does not assume stronger `~const` bounds than the trait definition. + // + // This registers the `~const` bounds of the impl method, which we will prove + // using the hybrid param-env that we earlier augmented with the const conditions + // from the impl header and trait method declaration. + if is_conditionally_const { + for (const_condition, span) in + tcx.const_conditions(impl_m.def_id).instantiate_own_identity() + { + let normalize_cause = traits::ObligationCause::misc(span, impl_m_def_id); + let const_condition = ocx.normalize(&normalize_cause, param_env, const_condition); + + let cause = + ObligationCause::new(span, impl_m_def_id, ObligationCauseCode::CompareImplItem { + impl_item_def_id: impl_m_def_id, + trait_item_def_id: trait_m.def_id, + kind: impl_m.kind, + }); + ocx.register_obligation(traits::Obligation::new( + tcx, + cause, + param_env, + const_condition.to_host_effect_clause(tcx, ty::HostPolarity::Maybe), + )); + } + } + // We now need to check that the signature of the impl method is // compatible with that of the trait method. We do this by // checking that `impl_fty <: trait_fty`. @@ -1846,9 +1893,10 @@ fn compare_type_predicate_entailment<'tcx>( trait_ty: ty::AssocItem, impl_trait_ref: ty::TraitRef<'tcx>, ) -> Result<(), ErrorGuaranteed> { + let impl_def_id = impl_ty.container_id(tcx); let trait_to_impl_args = GenericArgs::identity_for_item(tcx, impl_ty.def_id).rebase_onto( tcx, - impl_ty.container_id(tcx), + impl_def_id, impl_trait_ref.args, ); @@ -1856,6 +1904,7 @@ fn compare_type_predicate_entailment<'tcx>( let trait_ty_predicates = tcx.predicates_of(trait_ty.def_id); let impl_ty_own_bounds = impl_ty_predicates.instantiate_own_identity(); + // If there are no bounds, then there are no const conditions, so no need to check that here. if impl_ty_own_bounds.len() == 0 { // Nothing to check. return Ok(()); @@ -1881,6 +1930,23 @@ fn compare_type_predicate_entailment<'tcx>( let impl_ty_span = tcx.def_span(impl_ty_def_id); let normalize_cause = ObligationCause::misc(impl_ty_span, impl_ty_def_id); + let is_conditionally_const = tcx.is_conditionally_const(impl_ty.def_id); + if is_conditionally_const { + // Augment the hybrid param-env with the const conditions + // of the impl header and the trait assoc type. + hybrid_preds.extend( + tcx.const_conditions(impl_ty_predicates.parent.unwrap()) + .instantiate_identity(tcx) + .into_iter() + .chain( + tcx.const_conditions(trait_ty.def_id).instantiate_own(tcx, trait_to_impl_args), + ) + .map(|(trait_ref, _)| { + trait_ref.to_host_effect_clause(tcx, ty::HostPolarity::Maybe) + }), + ); + } + let param_env = ty::ParamEnv::new(tcx.mk_clauses(&hybrid_preds), Reveal::UserFacing); let param_env = traits::normalize_param_env_or_error(tcx, param_env, normalize_cause); debug!(caller_bounds=?param_env.caller_bounds()); @@ -1901,6 +1967,29 @@ fn compare_type_predicate_entailment<'tcx>( ocx.register_obligation(traits::Obligation::new(tcx, cause, param_env, predicate)); } + if is_conditionally_const { + // Validate the const conditions of the impl associated type. + let impl_ty_own_const_conditions = + tcx.const_conditions(impl_ty.def_id).instantiate_own_identity(); + for (const_condition, span) in impl_ty_own_const_conditions { + let normalize_cause = traits::ObligationCause::misc(span, impl_ty_def_id); + let const_condition = ocx.normalize(&normalize_cause, param_env, const_condition); + + let cause = + ObligationCause::new(span, impl_ty_def_id, ObligationCauseCode::CompareImplItem { + impl_item_def_id: impl_ty_def_id, + trait_item_def_id: trait_ty.def_id, + kind: impl_ty.kind, + }); + ocx.register_obligation(traits::Obligation::new( + tcx, + cause, + param_env, + const_condition.to_host_effect_clause(tcx, ty::HostPolarity::Maybe), + )); + } + } + // Check that all obligations are satisfied by the implementation's // version. let errors = ocx.select_all_or_error(); @@ -1983,7 +2072,7 @@ pub(super) fn check_type_bounds<'tcx>( ObligationCause::new(impl_ty_span, impl_ty_def_id, code) }; - let obligations: Vec<_> = tcx + let mut obligations: Vec<_> = tcx .explicit_item_bounds(trait_ty.def_id) .iter_instantiated_copied(tcx, rebased_args) .map(|(concrete_ty_bound, span)| { @@ -1991,6 +2080,22 @@ pub(super) fn check_type_bounds<'tcx>( traits::Obligation::new(tcx, mk_cause(span), param_env, concrete_ty_bound) }) .collect(); + + // Only in a const implementation do we need to check that the `~const` item bounds hold. + if tcx.is_conditionally_const(impl_ty_def_id) { + obligations.extend( + tcx.implied_const_bounds(trait_ty.def_id) + .iter_instantiated_copied(tcx, rebased_args) + .map(|(c, span)| { + traits::Obligation::new( + tcx, + mk_cause(span), + param_env, + c.to_host_effect_clause(tcx, ty::HostPolarity::Maybe), + ) + }), + ); + } debug!(item_bounds=?obligations); // Normalize predicates with the assumption that the GAT may always normalize diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index 06317a3b304..c75bdcec388 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -58,15 +58,9 @@ fn equate_intrinsic_type<'tcx>( // the host effect param should be invisible as it shouldn't matter // whether effects is enabled for the intrinsic provider crate. - let consts_count = if generics.host_effect_index.is_some() { - own_counts.consts - 1 - } else { - own_counts.consts - }; - if gen_count_ok(own_counts.lifetimes, n_lts, "lifetime") && gen_count_ok(own_counts.types, n_tps, "type") - && gen_count_ok(consts_count, n_cts, "const") + && gen_count_ok(own_counts.consts, n_cts, "const") { let _ = check_function_signature( tcx, diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index d70e8673c52..499e42d31c9 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -32,7 +32,8 @@ use rustc_trait_selection::traits::misc::{ use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; use rustc_trait_selection::traits::{ - self, FulfillmentError, ObligationCause, ObligationCauseCode, ObligationCtxt, WellFormedLoc, + self, FulfillmentError, Obligation, ObligationCause, ObligationCauseCode, ObligationCtxt, + WellFormedLoc, }; use rustc_type_ir::TypeFlags; use rustc_type_ir::solve::NoSolution; @@ -86,7 +87,7 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> { self.body_def_id, ObligationCauseCode::WellFormed(loc), ); - self.ocx.register_obligation(traits::Obligation::new( + self.ocx.register_obligation(Obligation::new( self.tcx(), cause, self.param_env, @@ -913,12 +914,7 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) -> Result<(), hir::GenericParamKind::Lifetime { .. } | hir::GenericParamKind::Type { .. } => Ok(()), // Const parameters are well formed if their type is structural match. - hir::GenericParamKind::Const { - ty: hir_ty, - default: _, - is_host_effect: _, - synthetic: _, - } => { + hir::GenericParamKind::Const { ty: hir_ty, default: _, synthetic: _ } => { let ty = tcx.type_of(param.def_id).instantiate_identity(); if tcx.features().unsized_const_params() { @@ -1178,7 +1174,7 @@ fn check_type_defn<'tcx>( wfcx.body_def_id, ObligationCauseCode::Misc, ); - wfcx.register_obligation(traits::Obligation::new( + wfcx.register_obligation(Obligation::new( tcx, cause, wfcx.param_env, @@ -1374,6 +1370,30 @@ fn check_impl<'tcx>( obligation.cause.span = hir_self_ty.span; } } + + // Ensure that the `~const` where clauses of the trait hold for the impl. + if tcx.is_conditionally_const(item.owner_id.def_id) { + for (bound, _) in + tcx.const_conditions(trait_ref.def_id).instantiate(tcx, trait_ref.args) + { + let bound = wfcx.normalize( + item.span, + Some(WellFormedLoc::Ty(item.hir_id().expect_owner().def_id)), + bound, + ); + wfcx.register_obligation(Obligation::new( + tcx, + ObligationCause::new( + hir_self_ty.span, + wfcx.body_def_id, + ObligationCauseCode::WellFormed(None), + ), + wfcx.param_env, + bound.to_host_effect_clause(tcx, ty::HostPolarity::Maybe), + )) + } + } + debug!(?obligations); wfcx.register_obligations(obligations); } @@ -1566,7 +1586,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id wfcx.body_def_id, ObligationCauseCode::WhereClause(def_id.to_def_id(), DUMMY_SP), ); - traits::Obligation::new(tcx, cause, wfcx.param_env, pred) + Obligation::new(tcx, cause, wfcx.param_env, pred) }); let predicates = predicates.instantiate_identity(tcx); @@ -1857,7 +1877,7 @@ fn receiver_is_implemented<'tcx>( let tcx = wfcx.tcx(); let trait_ref = ty::TraitRef::new(tcx, receiver_trait_def_id, [receiver_ty]); - let obligation = traits::Obligation::new(tcx, cause, wfcx.param_env, trait_ref); + let obligation = Obligation::new(tcx, cause, wfcx.param_env, trait_ref); if wfcx.infcx.predicate_must_hold_modulo_regions(&obligation) { true @@ -2193,7 +2213,7 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> { .unwrap_or(obligation_span); } - let obligation = traits::Obligation::new( + let obligation = Obligation::new( tcx, traits::ObligationCause::new( span, diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index acc21d0994b..f46b7a8bc9c 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -77,6 +77,8 @@ pub fn provide(providers: &mut Providers) { explicit_supertraits_containing_assoc_item: predicates_of::explicit_supertraits_containing_assoc_item, trait_explicit_predicates_and_bounds: predicates_of::trait_explicit_predicates_and_bounds, + const_conditions: predicates_of::const_conditions, + implied_const_bounds: predicates_of::implied_const_bounds, type_param_predicates: predicates_of::type_param_predicates, trait_def, adt_def, diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index 348b2260d26..3eec0e12665 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -53,7 +53,6 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { param_def_id_to_index, has_self: opaque_ty_generics.has_self, has_late_bound_regions: opaque_ty_generics.has_late_bound_regions, - host_effect_index: parent_generics.host_effect_index, }; } @@ -161,7 +160,6 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { param_def_id_to_index, has_self: generics.has_self, has_late_bound_regions: generics.has_late_bound_regions, - host_effect_index: None, }; } else { // HACK(eddyb) this provides the correct generics when @@ -292,12 +290,10 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { let has_self = opt_self.is_some(); let mut parent_has_self = false; let mut own_start = has_self as u32; - let mut host_effect_index = None; let parent_count = parent_def_id.map_or(0, |def_id| { let generics = tcx.generics_of(def_id); assert!(!has_self); parent_has_self = generics.has_self; - host_effect_index = generics.host_effect_index; own_start = generics.count() as u32; generics.parent_count + generics.own_params.len() }); @@ -361,12 +357,8 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { kind, }) } - GenericParamKind::Const { ty: _, default, is_host_effect, synthetic } => { - if !matches!(allow_defaults, Defaults::Allowed) - && default.is_some() - // `host` effect params are allowed to have defaults. - && !is_host_effect - { + GenericParamKind::Const { ty: _, default, synthetic } => { + if !matches!(allow_defaults, Defaults::Allowed) && default.is_some() { tcx.dcx().span_err( param.span, "defaults for const parameters are only allowed in \ @@ -376,27 +368,12 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { let index = next_index(); - if is_host_effect { - if let Some(idx) = host_effect_index { - tcx.dcx().span_delayed_bug( - param.span, - format!("parent also has host effect param? index: {idx}, def: {def_id:?}"), - ); - } - - host_effect_index = Some(index as usize); - } - Some(ty::GenericParamDef { index, name: param.name.ident().name, def_id: param.def_id.to_def_id(), pure_wrt_drop: param.pure_wrt_drop, - kind: ty::GenericParamDefKind::Const { - has_default: default.is_some(), - is_host_effect, - synthetic, - }, + kind: ty::GenericParamDefKind::Const { has_default: default.is_some(), synthetic }, }) } })); @@ -459,7 +436,6 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { param_def_id_to_index, has_self: has_self || parent_has_self, has_late_bound_regions: has_late_bound_regions(tcx, node), - host_effect_index, } } @@ -540,8 +516,7 @@ impl<'v> Visitor<'v> for AnonConstInParamTyDetector { type Result = ControlFlow<()>; fn visit_generic_param(&mut self, p: &'v hir::GenericParam<'v>) -> Self::Result { - if let GenericParamKind::Const { ty, default: _, is_host_effect: _, synthetic: _ } = p.kind - { + if let GenericParamKind::Const { ty, default: _, synthetic: _ } = p.kind { let prev = self.in_param_ty; self.in_param_ty = true; let res = self.visit_ty(ty); diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs index 69ebd3a928a..075faea3d2a 100644 --- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs +++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs @@ -40,7 +40,16 @@ fn associated_type_bounds<'tcx>( let mut bounds = Bounds::default(); icx.lowerer().lower_bounds(item_ty, hir_bounds, &mut bounds, ty::List::empty(), filter); // Associated types are implicitly sized unless a `?Sized` bound is found - icx.lowerer().add_sized_bound(&mut bounds, item_ty, hir_bounds, None, span); + match filter { + PredicateFilter::All + | PredicateFilter::SelfOnly + | PredicateFilter::SelfThatDefines(_) + | PredicateFilter::SelfAndAssociatedTypeBounds => { + icx.lowerer().add_sized_bound(&mut bounds, item_ty, hir_bounds, None, span); + } + // `ConstIfConst` is only interested in `~const` bounds. + PredicateFilter::ConstIfConst | PredicateFilter::SelfConstIfConst => {} + } let trait_def_id = tcx.local_parent(assoc_item_def_id); let trait_predicates = tcx.trait_explicit_predicates_and_bounds(trait_def_id); @@ -109,10 +118,19 @@ fn remap_gat_vars_and_recurse_into_nested_projections<'tcx>( } else { // Only collect *self* type bounds if the filter is for self. match filter { - PredicateFilter::SelfOnly | PredicateFilter::SelfThatDefines(_) => { + PredicateFilter::All => {} + PredicateFilter::SelfOnly => { return None; } - PredicateFilter::All | PredicateFilter::SelfAndAssociatedTypeBounds => {} + PredicateFilter::SelfThatDefines(_) + | PredicateFilter::SelfConstIfConst + | PredicateFilter::SelfAndAssociatedTypeBounds + | PredicateFilter::ConstIfConst => { + unreachable!( + "invalid predicate filter for \ + `remap_gat_vars_and_recurse_into_nested_projections`" + ) + } } clause_ty = alias_ty.self_ty(); @@ -308,7 +326,17 @@ fn opaque_type_bounds<'tcx>( let mut bounds = Bounds::default(); icx.lowerer().lower_bounds(item_ty, hir_bounds, &mut bounds, ty::List::empty(), filter); // Opaque types are implicitly sized unless a `?Sized` bound is found - icx.lowerer().add_sized_bound(&mut bounds, item_ty, hir_bounds, None, span); + match filter { + PredicateFilter::All + | PredicateFilter::SelfOnly + | PredicateFilter::SelfThatDefines(_) + | PredicateFilter::SelfAndAssociatedTypeBounds => { + // Associated types are implicitly sized unless a `?Sized` bound is found + icx.lowerer().add_sized_bound(&mut bounds, item_ty, hir_bounds, None, span); + } + //`ConstIfConst` is only interested in `~const` bounds. + PredicateFilter::ConstIfConst | PredicateFilter::SelfConstIfConst => {} + } debug!(?bounds); tcx.arena.alloc_from_iter(bounds.clauses(tcx)) diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index 097a1fbc393..61dc4b1677c 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -12,6 +12,7 @@ use rustc_span::symbol::Ident; use rustc_span::{DUMMY_SP, Span}; use tracing::{debug, instrument, trace}; +use super::item_bounds::explicit_item_bounds_with_filter; use crate::bounds::Bounds; use crate::collect::ItemCtxt; use crate::constrained_generic_params as cgp; @@ -78,7 +79,6 @@ pub(super) fn predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredic #[instrument(level = "trace", skip(tcx), ret)] fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::GenericPredicates<'_> { use rustc_hir::*; - use rustc_middle::ty::Ty; match tcx.opt_rpitit_info(def_id.to_def_id()) { Some(ImplTraitInTraitData::Trait { fn_def_id, .. }) => { @@ -345,26 +345,6 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen debug!(?predicates); } - // add `Self::Effects: Compat<HOST>` to ensure non-const impls don't get called - // in const contexts. - if let Node::TraitItem(&TraitItem { kind: TraitItemKind::Fn(..), .. }) = node - && let Some(host_effect_index) = generics.host_effect_index - { - let parent = generics.parent.unwrap(); - let Some(assoc_def_id) = tcx.associated_type_for_effects(parent) else { - bug!("associated_type_for_effects returned None when there is host effect in generics"); - }; - let effects = - Ty::new_projection(tcx, assoc_def_id, ty::GenericArgs::identity_for_item(tcx, parent)); - let param = generics.param_at(host_effect_index, tcx); - let span = tcx.def_span(param.def_id); - let host = ty::Const::new_param(tcx, ty::ParamConst::for_def(param)); - let compat = tcx.require_lang_item(LangItem::EffectsCompat, Some(span)); - let trait_ref = - ty::TraitRef::new(tcx, compat, [ty::GenericArg::from(effects), host.into()]); - predicates.push((ty::Binder::dummy(trait_ref).upcast(tcx), span)); - } - ty::GenericPredicates { parent: generics.parent, predicates: tcx.arena.alloc_from_iter(predicates), @@ -706,29 +686,76 @@ pub(super) fn assert_only_contains_predicates_from<'tcx>( assert_eq!( trait_predicate.self_ty(), ty, - "expected `Self` predicate when computing `{filter:?}` implied bounds: {clause:?}" + "expected `Self` predicate when computing \ + `{filter:?}` implied bounds: {clause:?}" ); } ty::ClauseKind::Projection(projection_predicate) => { assert_eq!( projection_predicate.self_ty(), ty, - "expected `Self` predicate when computing `{filter:?}` implied bounds: {clause:?}" + "expected `Self` predicate when computing \ + `{filter:?}` implied bounds: {clause:?}" ); } ty::ClauseKind::TypeOutlives(outlives_predicate) => { assert_eq!( outlives_predicate.0, ty, - "expected `Self` predicate when computing `{filter:?}` implied bounds: {clause:?}" + "expected `Self` predicate when computing \ + `{filter:?}` implied bounds: {clause:?}" ); } ty::ClauseKind::RegionOutlives(_) | ty::ClauseKind::ConstArgHasType(_, _) | ty::ClauseKind::WellFormed(_) - | ty::ClauseKind::ConstEvaluatable(_) => { + | ty::ClauseKind::ConstEvaluatable(_) + | ty::ClauseKind::HostEffect(..) => { + bug!( + "unexpected non-`Self` predicate when computing \ + `{filter:?}` implied bounds: {clause:?}" + ); + } + } + } + } + PredicateFilter::ConstIfConst => { + for (clause, _) in bounds { + match clause.kind().skip_binder() { + ty::ClauseKind::HostEffect(ty::HostEffectPredicate { + trait_ref: _, + host: ty::HostPolarity::Maybe, + }) => {} + _ => { + bug!( + "unexpected non-`HostEffect` predicate when computing \ + `{filter:?}` implied bounds: {clause:?}" + ); + } + } + } + } + PredicateFilter::SelfConstIfConst => { + for (clause, _) in bounds { + match clause.kind().skip_binder() { + ty::ClauseKind::HostEffect(pred) => { + assert_eq!( + pred.host, + ty::HostPolarity::Maybe, + "expected `~const` predicate when computing `{filter:?}` \ + implied bounds: {clause:?}", + ); + assert_eq!( + pred.trait_ref.self_ty(), + ty, + "expected `Self` predicate when computing `{filter:?}` \ + implied bounds: {clause:?}" + ); + } + _ => { bug!( - "unexpected non-`Self` predicate when computing `{filter:?}` implied bounds: {clause:?}" + "unexpected non-`HostEffect` predicate when computing \ + `{filter:?}` implied bounds: {clause:?}" ); } } @@ -850,3 +877,144 @@ impl<'tcx> ItemCtxt<'tcx> { bounds.clauses(self.tcx).collect() } } + +/// Compute the conditions that need to hold for a conditionally-const item to be const. +/// That is, compute the set of `~const` where clauses for a given item. +/// +/// This query also computes the `~const` where clauses for associated types, which are +/// not "const", but which have item bounds which may be `~const`. These must hold for +/// the `~const` item bound to hold. +pub(super) fn const_conditions<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: LocalDefId, +) -> ty::ConstConditions<'tcx> { + if !tcx.is_conditionally_const(def_id) { + bug!("const_conditions invoked for item that is not conditionally const: {def_id:?}"); + } + + let (generics, trait_def_id_and_supertraits, has_parent) = match tcx.hir_node_by_def_id(def_id) + { + Node::Item(item) => match item.kind { + hir::ItemKind::Impl(impl_) => (impl_.generics, None, false), + hir::ItemKind::Fn(_, generics, _) => (generics, None, false), + hir::ItemKind::Trait(_, _, generics, supertraits, _) => { + (generics, Some((item.owner_id.def_id, supertraits)), false) + } + _ => bug!("const_conditions called on wrong item: {def_id:?}"), + }, + // While associated types are not really const, we do allow them to have `~const` + // bounds and where clauses. `const_conditions` is responsible for gathering + // these up so we can check them in `compare_type_predicate_entailment`, and + // in `HostEffect` goal computation. + Node::TraitItem(item) => match item.kind { + hir::TraitItemKind::Fn(_, _) | hir::TraitItemKind::Type(_, _) => { + (item.generics, None, true) + } + _ => bug!("const_conditions called on wrong item: {def_id:?}"), + }, + Node::ImplItem(item) => match item.kind { + hir::ImplItemKind::Fn(_, _) | hir::ImplItemKind::Type(_) => { + (item.generics, None, tcx.is_conditionally_const(tcx.local_parent(def_id))) + } + _ => bug!("const_conditions called on wrong item: {def_id:?}"), + }, + Node::ForeignItem(item) => match item.kind { + hir::ForeignItemKind::Fn(_, _, generics) => (generics, None, false), + _ => bug!("const_conditions called on wrong item: {def_id:?}"), + }, + // N.B. Tuple ctors are unconditionally constant. + Node::Ctor(hir::VariantData::Tuple { .. }) => return Default::default(), + _ => bug!("const_conditions called on wrong item: {def_id:?}"), + }; + + let icx = ItemCtxt::new(tcx, def_id); + let mut bounds = Bounds::default(); + + for pred in generics.predicates { + match pred { + hir::WherePredicate::BoundPredicate(bound_pred) => { + let ty = icx.lowerer().lower_ty_maybe_return_type_notation(bound_pred.bounded_ty); + let bound_vars = tcx.late_bound_vars(bound_pred.hir_id); + icx.lowerer().lower_bounds( + ty, + bound_pred.bounds.iter(), + &mut bounds, + bound_vars, + PredicateFilter::ConstIfConst, + ); + } + _ => {} + } + } + + if let Some((def_id, supertraits)) = trait_def_id_and_supertraits { + bounds.push_const_bound( + tcx, + ty::Binder::dummy(ty::TraitRef::identity(tcx, def_id.to_def_id())), + ty::HostPolarity::Maybe, + DUMMY_SP, + ); + + icx.lowerer().lower_bounds( + tcx.types.self_param, + supertraits.into_iter(), + &mut bounds, + ty::List::empty(), + PredicateFilter::ConstIfConst, + ); + } + + ty::ConstConditions { + parent: has_parent.then(|| tcx.local_parent(def_id).to_def_id()), + predicates: tcx.arena.alloc_from_iter(bounds.clauses(tcx).map(|(clause, span)| { + ( + clause.kind().map_bound(|clause| match clause { + ty::ClauseKind::HostEffect(ty::HostEffectPredicate { + trait_ref, + host: ty::HostPolarity::Maybe, + }) => trait_ref, + _ => bug!("converted {clause:?}"), + }), + span, + ) + })), + } +} + +pub(super) fn implied_const_bounds<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: LocalDefId, +) -> ty::EarlyBinder<'tcx, &'tcx [(ty::PolyTraitRef<'tcx>, Span)]> { + if !tcx.is_conditionally_const(def_id) { + bug!("const_conditions invoked for item that is not conditionally const: {def_id:?}"); + } + + let bounds = match tcx.hir_node_by_def_id(def_id) { + Node::Item(hir::Item { kind: hir::ItemKind::Trait(..), .. }) => { + implied_predicates_with_filter( + tcx, + def_id.to_def_id(), + PredicateFilter::SelfConstIfConst, + ) + } + Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Type(..), .. }) => { + explicit_item_bounds_with_filter(tcx, def_id, PredicateFilter::ConstIfConst) + } + _ => bug!("implied_const_bounds called on wrong item: {def_id:?}"), + }; + + bounds.map_bound(|bounds| { + &*tcx.arena.alloc_from_iter(bounds.iter().copied().map(|(clause, span)| { + ( + clause.kind().map_bound(|clause| match clause { + ty::ClauseKind::HostEffect(ty::HostEffectPredicate { + trait_ref, + host: ty::HostPolarity::Maybe, + }) => trait_ref, + _ => bug!("converted {clause:?}"), + }), + span, + ) + })) + }) +} diff --git a/compiler/rustc_hir_analysis/src/delegation.rs b/compiler/rustc_hir_analysis/src/delegation.rs index 1ccb7faaf30..4d3595965c9 100644 --- a/compiler/rustc_hir_analysis/src/delegation.rs +++ b/compiler/rustc_hir_analysis/src/delegation.rs @@ -186,7 +186,6 @@ impl<'tcx> GenericsBuilder<'tcx> { param_def_id_to_index, has_self, has_late_bound_regions: sig_generics.has_late_bound_regions, - host_effect_index: sig_generics.host_effect_index, } } } @@ -472,10 +471,6 @@ fn check_constraints<'tcx>( })); }; - if tcx.has_host_param(sig_id) { - emit("delegation to a function with effect parameter is not supported yet"); - } - if let Some(local_sig_id) = sig_id.as_local() && tcx.hir().opt_delegation_sig_id(local_sig_id).is_some() { diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs index 2b0e1350108..c902e85c267 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs @@ -154,7 +154,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { for hir_bound in hir_bounds { // In order to avoid cycles, when we're lowering `SelfThatDefines`, // we skip over any traits that don't define the given associated type. - if let PredicateFilter::SelfThatDefines(assoc_name) = predicate_filter { if let Some(trait_ref) = hir_bound.trait_ref() && let Some(trait_did) = trait_ref.trait_def_id() @@ -193,6 +192,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ); } hir::GenericBound::Outlives(lifetime) => { + // `ConstIfConst` is only interested in `~const` bounds. + if matches!( + predicate_filter, + PredicateFilter::ConstIfConst | PredicateFilter::SelfConstIfConst + ) { + continue; + } + let region = self.lower_lifetime(lifetime, RegionInferReason::OutlivesBound); bounds.push_region_bound( self.tcx(), @@ -392,21 +399,31 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { }, ); - bounds.push_projection_bound( - tcx, - projection_term.map_bound(|projection_term| ty::ProjectionPredicate { - projection_term, - term, - }), - constraint.span, - ); + match predicate_filter { + PredicateFilter::All + | PredicateFilter::SelfOnly + | PredicateFilter::SelfThatDefines(_) + | PredicateFilter::SelfAndAssociatedTypeBounds => { + bounds.push_projection_bound( + tcx, + projection_term.map_bound(|projection_term| ty::ProjectionPredicate { + projection_term, + term, + }), + constraint.span, + ); + } + // `ConstIfConst` is only interested in `~const` bounds. + PredicateFilter::ConstIfConst | PredicateFilter::SelfConstIfConst => {} + } } // Lower a constraint like `Item: Debug` as found in HIR bound `T: Iterator<Item: Debug>` // to a bound involving a projection: `<T as Iterator>::Item: Debug`. hir::AssocItemConstraintKind::Bound { bounds: hir_bounds } => { match predicate_filter { - PredicateFilter::SelfOnly | PredicateFilter::SelfThatDefines(_) => {} - PredicateFilter::All | PredicateFilter::SelfAndAssociatedTypeBounds => { + PredicateFilter::All + | PredicateFilter::SelfAndAssociatedTypeBounds + | PredicateFilter::ConstIfConst => { let projection_ty = projection_term .map_bound(|projection_term| projection_term.expect_ty(self.tcx())); // Calling `skip_binder` is okay, because `lower_bounds` expects the `param_ty` @@ -421,6 +438,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { predicate_filter, ); } + PredicateFilter::SelfOnly + | PredicateFilter::SelfThatDefines(_) + | PredicateFilter::SelfConstIfConst => {} } } } diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs index 2cee7c77aa5..3449270564a 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs @@ -78,7 +78,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ty::ClauseKind::RegionOutlives(_) | ty::ClauseKind::ConstArgHasType(..) | ty::ClauseKind::WellFormed(_) - | ty::ClauseKind::ConstEvaluatable(_) => { + | ty::ClauseKind::ConstEvaluatable(_) + | ty::ClauseKind::HostEffect(..) => { span_bug!(span, "did not expect {pred} clause in object bounds"); } } diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index a73a2f925cd..863c077a9e0 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -81,6 +81,12 @@ pub enum PredicateFilter { /// For example, given `Self: Tr<A: B>`, this would expand to `Self: Tr` /// and `<Self as Tr>::A: B`. SelfAndAssociatedTypeBounds, + + /// Filter only the `~const` bounds, which are lowered into `HostEffect` clauses. + ConstIfConst, + + /// Filter only the `~const` bounds which are *also* in the supertrait position. + SelfConstIfConst, } #[derive(Debug)] @@ -693,16 +699,49 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { bound_vars, ); - debug!(?poly_trait_ref); - bounds.push_trait_bound( - tcx, - self.item_def_id().to_def_id(), - poly_trait_ref, - span, - polarity, - constness, - predicate_filter, - ); + match predicate_filter { + PredicateFilter::All + | PredicateFilter::SelfOnly + | PredicateFilter::SelfThatDefines(..) + | PredicateFilter::SelfAndAssociatedTypeBounds => { + debug!(?poly_trait_ref); + bounds.push_trait_bound(tcx, poly_trait_ref, span, polarity); + + match constness { + Some(ty::BoundConstness::Const) => { + if polarity == ty::PredicatePolarity::Positive { + bounds.push_const_bound( + tcx, + poly_trait_ref, + ty::HostPolarity::Const, + span, + ); + } + } + Some(ty::BoundConstness::ConstIfConst) => { + // We don't emit a const bound here, since that would mean that we + // unconditionally need to prove a `HostEffect` predicate, even when + // the predicates are being instantiated in a non-const context. This + // is instead handled in the `const_conditions` query. + } + None => {} + } + } + // On the flip side, when filtering `ConstIfConst` bounds, we only need to convert + // `~const` bounds. All other predicates are handled in their respective queries. + // + // Note that like `PredicateFilter::SelfOnly`, we don't need to do any filtering + // here because we only call this on self bounds, and deal with the recursive case + // in `lower_assoc_item_constraint`. + PredicateFilter::ConstIfConst | PredicateFilter::SelfConstIfConst => match constness { + Some(ty::BoundConstness::ConstIfConst) => { + if polarity == ty::PredicatePolarity::Positive { + bounds.push_const_bound(tcx, poly_trait_ref, ty::HostPolarity::Maybe, span); + } + } + None | Some(ty::BoundConstness::Const) => {} + }, + } let mut dup_constraints = FxIndexMap::default(); for constraint in trait_segment.args().constraints { diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs index 0355adfcb11..a394fc2fbb1 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs @@ -530,6 +530,7 @@ fn trait_specialization_kind<'tcx>( | ty::ClauseKind::Projection(_) | ty::ClauseKind::ConstArgHasType(..) | ty::ClauseKind::WellFormed(_) - | ty::ClauseKind::ConstEvaluatable(..) => None, + | ty::ClauseKind::ConstEvaluatable(..) + | ty::ClauseKind::HostEffect(..) => None, } } diff --git a/compiler/rustc_hir_analysis/src/outlives/explicit.rs b/compiler/rustc_hir_analysis/src/outlives/explicit.rs index f576499ecac..2c1d443f951 100644 --- a/compiler/rustc_hir_analysis/src/outlives/explicit.rs +++ b/compiler/rustc_hir_analysis/src/outlives/explicit.rs @@ -53,7 +53,8 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> { | ty::ClauseKind::Projection(_) | ty::ClauseKind::ConstArgHasType(_, _) | ty::ClauseKind::WellFormed(_) - | ty::ClauseKind::ConstEvaluatable(_) => {} + | ty::ClauseKind::ConstEvaluatable(_) + | ty::ClauseKind::HostEffect(..) => {} } } diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 3ba9c76bcee..61214b99215 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -2134,7 +2134,7 @@ impl<'a> State<'a> { self.print_type(default); } } - GenericParamKind::Const { ty, ref default, is_host_effect: _, synthetic: _ } => { + GenericParamKind::Const { ty, ref default, synthetic: _ } => { self.word_space(":"); self.print_type(ty); if let Some(default) = default { diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index 06e2a5e3493..190e405282c 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -20,7 +20,7 @@ use rustc_target::spec::abi; use rustc_trait_selection::error_reporting::traits::DefIdOrName; use rustc_trait_selection::infer::InferCtxtExt as _; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; -use tracing::{debug, instrument, trace}; +use tracing::{debug, instrument}; use super::method::MethodCallee; use super::method::probe::ProbeScope; @@ -843,29 +843,38 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { callee_did: DefId, callee_args: GenericArgsRef<'tcx>, ) { - let tcx = self.tcx; - - // fast-reject if callee doesn't have the host effect param (non-const) - let generics = tcx.generics_of(callee_did); - let Some(host_effect_index) = generics.host_effect_index else { return }; - - let effect = tcx.expected_host_effect_param_for_body(self.body_id); - - trace!(?effect, ?generics, ?callee_args); + // FIXME(effects): We should be enforcing these effects unconditionally. + // This can be done as soon as we convert the standard library back to + // using const traits, since if we were to enforce these conditions now, + // we'd fail on basically every builtin trait call (i.e. `1 + 2`). + if !self.tcx.features().effects() { + return; + } - let param = callee_args.const_at(host_effect_index); - let cause = self.misc(span); - // We know the type of `effect` to be `bool`, there will be no opaque type inference. - match self.at(&cause, self.param_env).eq(infer::DefineOpaqueTypes::Yes, effect, param) { - Ok(infer::InferOk { obligations, value: () }) => { - self.register_predicates(obligations); + let host = match self.tcx.hir().body_const_context(self.body_id) { + Some(hir::ConstContext::Const { .. } | hir::ConstContext::Static(_)) => { + ty::HostPolarity::Const } - Err(e) => { - // FIXME(effects): better diagnostic - self.err_ctxt() - .report_mismatched_consts(&cause, self.param_env, effect, param, e) - .emit(); + Some(hir::ConstContext::ConstFn) => ty::HostPolarity::Maybe, + None => return, + }; + + // FIXME(effects): Should this be `is_const_fn_raw`? It depends on if we move + // const stability checking here too, I guess. + if self.tcx.is_conditionally_const(callee_did) { + let q = self.tcx.const_conditions(callee_did); + // FIXME(effects): Use this span with a better cause code. + for (cond, _) in q.instantiate(self.tcx, callee_args) { + self.register_predicate(Obligation::new( + self.tcx, + self.misc(span), + self.param_env, + cond.to_host_effect_clause(self.tcx, host), + )); } + } else { + // FIXME(effects): This should eventually be caught here. + // For now, though, we defer some const checking to MIR. } } diff --git a/compiler/rustc_hir_typeck/src/fallback.rs b/compiler/rustc_hir_typeck/src/fallback.rs index 4fd508ab896..68776c52555 100644 --- a/compiler/rustc_hir_typeck/src/fallback.rs +++ b/compiler/rustc_hir_typeck/src/fallback.rs @@ -7,8 +7,6 @@ use rustc_data_structures::unord::{UnordBag, UnordMap, UnordSet}; use rustc_hir as hir; use rustc_hir::HirId; use rustc_hir::intravisit::Visitor; -use rustc_infer::infer::{DefineOpaqueTypes, InferOk}; -use rustc_middle::bug; use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable}; use rustc_session::lint; use rustc_span::def_id::LocalDefId; @@ -48,7 +46,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { self.fulfillment_cx.borrow_mut().pending_obligations() ); - let fallback_occurred = self.fallback_types() | self.fallback_effects(); + let fallback_occurred = self.fallback_types(); if !fallback_occurred { return; @@ -103,31 +101,6 @@ impl<'tcx> FnCtxt<'_, 'tcx> { fallback_occurred } - fn fallback_effects(&self) -> bool { - let unsolved_effects = self.unsolved_effects(); - - if unsolved_effects.is_empty() { - return false; - } - - // not setting the `fallback_has_occurred` field here because - // that field is only used for type fallback diagnostics. - for effect in unsolved_effects { - let expected = self.tcx.consts.true_; - let cause = self.misc(DUMMY_SP); - match self.at(&cause, self.param_env).eq(DefineOpaqueTypes::Yes, expected, effect) { - Ok(InferOk { obligations, value: () }) => { - self.register_predicates(obligations); - } - Err(e) => { - bug!("cannot eq unsolved effect: {e:?}") - } - } - } - - true - } - // Tries to apply a fallback to `ty` if it is an unsolved variable. // // - Unconstrained ints are replaced with `i32`. diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index d2d311ef565..0fc566c58f7 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -1262,15 +1262,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (GenericParamDefKind::Type { .. }, GenericArg::Infer(inf)) => { self.fcx.ty_infer(Some(param), inf.span).into() } - ( - &GenericParamDefKind::Const { has_default, is_host_effect, .. }, - GenericArg::Infer(inf), - ) => { - if has_default && is_host_effect { - self.fcx.var_for_effect(param) - } else { - self.fcx.ct_infer(Some(param), inf.span).into() - } + (&GenericParamDefKind::Const { .. }, GenericArg::Infer(inf)) => { + self.fcx.ct_infer(Some(param), inf.span).into() } _ => unreachable!(), } @@ -1305,20 +1298,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.fcx.var_for_def(self.span, param) } } - GenericParamDefKind::Const { has_default, is_host_effect, .. } => { + GenericParamDefKind::Const { has_default, .. } => { if has_default { - // N.B. this is a bit of a hack. `infer_args` is passed depending on - // whether the user has provided generic args. E.g. for `Vec::new` - // we would have to infer the generic types. However, for `Vec::<T>::new` - // where the allocator param `A` has a default we will *not* infer. But - // for effect params this is a different story: if the user has not written - // anything explicit for the effect param, we always need to try to infer - // it before falling back to default, such that a `const fn` such as - // `needs_drop::<()>` can still be called in const contexts. (if we defaulted - // instead of inferred, typeck would error) - if is_host_effect { - return self.fcx.var_for_effect(param); - } else if !infer_args { + if !infer_args { return tcx .const_param_default(param.def_id) .instantiate(tcx, preceding_args) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs index 693cb4465cc..eb5fe3a86e4 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs @@ -52,6 +52,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | ty::PredicateKind::AliasRelate(..) | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) | ty::PredicateKind::ConstEquate(..) + | ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(..)) | ty::PredicateKind::Ambiguous => false, } } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index 4123feebb40..3940d138deb 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -247,12 +247,6 @@ impl<'tcx> HirTyLowerer<'tcx> for FnCtxt<'_, 'tcx> { fn ct_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Const<'tcx> { // FIXME ideally this shouldn't use unwrap match param { - Some( - param @ ty::GenericParamDef { - kind: ty::GenericParamDefKind::Const { is_host_effect: true, .. }, - .. - }, - ) => self.var_for_effect(param).as_const().unwrap(), Some(param) => self.var_for_def(span, param).as_const().unwrap(), None => self.next_const_var(span), } diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs index 69b9be00276..e20a0cb67c3 100644 --- a/compiler/rustc_hir_typeck/src/method/mod.rs +++ b/compiler/rustc_hir_typeck/src/method/mod.rs @@ -369,17 +369,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> { let (obligation, args) = self.obligation_for_method(cause, trait_def_id, self_ty, opt_input_types); - // FIXME(effects) find a better way to do this - // Operators don't have generic methods, but making them `#[const_trait]` gives them - // `const host: bool`. - let args = if self.tcx.is_const_trait(trait_def_id) { - self.tcx.mk_args_from_iter( - args.iter() - .chain([self.tcx.expected_host_effect_param_for_body(self.body_id).into()]), - ) - } else { - args - }; self.construct_obligation_for_trait(m_name, trait_def_id, obligation, args) } diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index b60fa8bbfa1..569fdea11ce 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -813,7 +813,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { | ty::ClauseKind::Projection(_) | ty::ClauseKind::ConstArgHasType(_, _) | ty::ClauseKind::WellFormed(_) - | ty::ClauseKind::ConstEvaluatable(_) => None, + | ty::ClauseKind::ConstEvaluatable(_) + | ty::ClauseKind::HostEffect(..) => None, } }); diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs index e3519dfb028..90d07964fda 100644 --- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs +++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs @@ -489,17 +489,6 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> { } } } - ty::ConstKind::Infer(InferConst::EffectVar(vid)) => { - match self.infcx.unwrap().probe_effect_var(vid) { - Some(value) => return self.fold_const(value), - None => { - return self.canonicalize_const_var( - CanonicalVarInfo { kind: CanonicalVarKind::Effect }, - ct, - ); - } - } - } ty::ConstKind::Infer(InferConst::Fresh(_)) => { bug!("encountered a fresh const during canonicalization") } @@ -700,8 +689,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { .iter() .map(|v| CanonicalVarInfo { kind: match v.kind { - CanonicalVarKind::Ty(CanonicalTyVarKind::Int | CanonicalTyVarKind::Float) - | CanonicalVarKind::Effect => { + CanonicalVarKind::Ty(CanonicalTyVarKind::Int | CanonicalTyVarKind::Float) => { return *v; } CanonicalVarKind::Ty(CanonicalTyVarKind::General(u)) => { diff --git a/compiler/rustc_infer/src/infer/canonical/mod.rs b/compiler/rustc_infer/src/infer/canonical/mod.rs index 8caedcd4053..fb5fc3a53fe 100644 --- a/compiler/rustc_infer/src/infer/canonical/mod.rs +++ b/compiler/rustc_infer/src/infer/canonical/mod.rs @@ -24,7 +24,6 @@ pub use instantiate::CanonicalExt; use rustc_index::IndexVec; pub use rustc_middle::infer::canonical::*; -use rustc_middle::infer::unify_key::EffectVarValue; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::{self, GenericArg, List, Ty, TyCtxt}; use rustc_span::Span; @@ -145,15 +144,6 @@ impl<'tcx> InferCtxt<'tcx> { CanonicalVarKind::Const(ui) => { self.next_const_var_in_universe(span, universe_map(ui)).into() } - CanonicalVarKind::Effect => { - let vid = self - .inner - .borrow_mut() - .effect_unification_table() - .new_key(EffectVarValue::Unknown) - .vid; - ty::Const::new_infer(self.tcx, ty::InferConst::EffectVar(vid)).into() - } CanonicalVarKind::PlaceholderConst(ty::PlaceholderConst { universe, bound }) => { let universe_mapped = universe_map(universe); let placeholder_mapped = ty::PlaceholderConst { universe: universe_mapped, bound }; diff --git a/compiler/rustc_infer/src/infer/context.rs b/compiler/rustc_infer/src/infer/context.rs index 57007752cad..0c151a11ad4 100644 --- a/compiler/rustc_infer/src/infer/context.rs +++ b/compiler/rustc_infer/src/infer/context.rs @@ -1,6 +1,5 @@ ///! Definition of `InferCtxtLike` from the librarified type layer. use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_middle::infer::unify_key::EffectVarValue; use rustc_middle::traits::ObligationCause; use rustc_middle::traits::solve::SolverMode; use rustc_middle::ty::fold::TypeFoldable; @@ -88,15 +87,6 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> { } } - fn opportunistic_resolve_effect_var(&self, vid: ty::EffectVid) -> ty::Const<'tcx> { - match self.probe_effect_var(vid) { - Some(ct) => ct, - None => { - ty::Const::new_infer(self.tcx, ty::InferConst::EffectVar(self.root_effect_var(vid))) - } - } - } - fn opportunistic_resolve_lt_var(&self, vid: ty::RegionVid) -> ty::Region<'tcx> { self.inner.borrow_mut().unwrap_region_constraints().opportunistic_resolve_var(self.tcx, vid) } @@ -152,10 +142,6 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> { self.inner.borrow_mut().const_unification_table().union(a, b); } - fn equate_effect_vids_raw(&self, a: rustc_type_ir::EffectVid, b: rustc_type_ir::EffectVid) { - self.inner.borrow_mut().effect_unification_table().union(a, b); - } - fn instantiate_ty_var_raw<R: PredicateEmittingRelation<Self>>( &self, relation: &mut R, @@ -189,13 +175,6 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> { self.inner.borrow_mut().float_unification_table().union_value(vid, value); } - fn instantiate_effect_var_raw(&self, vid: rustc_type_ir::EffectVid, value: ty::Const<'tcx>) { - self.inner - .borrow_mut() - .effect_unification_table() - .union_value(vid, EffectVarValue::Known(value)); - } - fn instantiate_const_var_raw<R: PredicateEmittingRelation<Self>>( &self, relation: &mut R, diff --git a/compiler/rustc_infer/src/infer/freshen.rs b/compiler/rustc_infer/src/infer/freshen.rs index c4294111ebe..28eac5b7496 100644 --- a/compiler/rustc_infer/src/infer/freshen.rs +++ b/compiler/rustc_infer/src/infer/freshen.rs @@ -153,15 +153,6 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for TypeFreshener<'a, 'tcx> { drop(inner); self.freshen_const(input, ty::InferConst::Fresh) } - ty::ConstKind::Infer(ty::InferConst::EffectVar(v)) => { - let mut inner = self.infcx.inner.borrow_mut(); - let input = - inner.effect_unification_table().probe_value(v).known().ok_or_else(|| { - ty::InferConst::EffectVar(inner.effect_unification_table().find(v).vid) - }); - drop(inner); - self.freshen_const(input, ty::InferConst::Fresh) - } ty::ConstKind::Infer(ty::InferConst::Fresh(i)) => { if i >= self.const_freshen_count { bug!( diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 5afdf3c2454..be43cba97f0 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -26,9 +26,7 @@ use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_macros::extension; pub use rustc_macros::{TypeFoldable, TypeVisitable}; use rustc_middle::infer::canonical::{CanonicalQueryInput, CanonicalVarValues}; -use rustc_middle::infer::unify_key::{ - ConstVariableOrigin, ConstVariableValue, ConstVidKey, EffectVarValue, EffectVidKey, -}; +use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableValue, ConstVidKey}; use rustc_middle::mir::ConstraintCategory; use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult}; use rustc_middle::traits::select; @@ -39,7 +37,7 @@ use rustc_middle::ty::fold::{ }; use rustc_middle::ty::visit::TypeVisitableExt; use rustc_middle::ty::{ - self, ConstVid, EffectVid, FloatVid, GenericArg, GenericArgKind, GenericArgs, GenericArgsRef, + self, ConstVid, FloatVid, GenericArg, GenericArgKind, GenericArgs, GenericArgsRef, GenericParamDefKind, InferConst, IntVid, Ty, TyCtxt, TyVid, }; use rustc_middle::{bug, span_bug}; @@ -117,9 +115,6 @@ pub struct InferCtxtInner<'tcx> { /// Map from floating variable to the kind of float it represents. float_unification_storage: ut::UnificationTableStorage<ty::FloatVid>, - /// Map from effect variable to the effect param it represents. - effect_unification_storage: ut::UnificationTableStorage<EffectVidKey<'tcx>>, - /// Tracks the set of region variables and the constraints between them. /// /// This is initially `Some(_)` but when @@ -176,7 +171,6 @@ impl<'tcx> InferCtxtInner<'tcx> { const_unification_storage: Default::default(), int_unification_storage: Default::default(), float_unification_storage: Default::default(), - effect_unification_storage: Default::default(), region_constraint_storage: Some(Default::default()), region_obligations: vec![], opaque_type_storage: Default::default(), @@ -228,10 +222,6 @@ impl<'tcx> InferCtxtInner<'tcx> { self.const_unification_storage.with_log(&mut self.undo_log) } - fn effect_unification_table(&mut self) -> UnificationTable<'_, 'tcx, EffectVidKey<'tcx>> { - self.effect_unification_storage.with_log(&mut self.undo_log) - } - #[inline] pub fn unwrap_region_constraints(&mut self) -> RegionConstraintCollector<'_, 'tcx> { self.region_constraint_storage @@ -524,7 +514,6 @@ impl fmt::Display for FixupError { ), Ty(_) => write!(f, "unconstrained type"), Const(_) => write!(f, "unconstrained const value"), - Effect(_) => write!(f, "unconstrained effect value"), } } } @@ -726,17 +715,6 @@ impl<'tcx> InferCtxt<'tcx> { vars } - pub fn unsolved_effects(&self) -> Vec<ty::Const<'tcx>> { - let mut inner = self.inner.borrow_mut(); - let mut table = inner.effect_unification_table(); - - (0..table.len()) - .map(|i| ty::EffectVid::from_usize(i)) - .filter(|&vid| table.probe_value(vid).is_unknown()) - .map(|v| ty::Const::new_infer(self.tcx, ty::InferConst::EffectVar(v))) - .collect() - } - #[instrument(skip(self), level = "debug")] pub fn sub_regions( &self, @@ -899,13 +877,6 @@ impl<'tcx> InferCtxt<'tcx> { ty::Const::new_var(self.tcx, vid) } - fn next_effect_var(&self) -> ty::Const<'tcx> { - let effect_vid = - self.inner.borrow_mut().effect_unification_table().new_key(EffectVarValue::Unknown).vid; - - ty::Const::new_infer(self.tcx, ty::InferConst::EffectVar(effect_vid)) - } - pub fn next_int_var(&self) -> Ty<'tcx> { let next_int_var_id = self.inner.borrow_mut().int_unification_table().new_key(ty::IntVarValue::Unknown); @@ -991,10 +962,7 @@ impl<'tcx> InferCtxt<'tcx> { Ty::new_var(self.tcx, ty_var_id).into() } - GenericParamDefKind::Const { is_host_effect, .. } => { - if is_host_effect { - return self.var_for_effect(param); - } + GenericParamDefKind::Const { .. } => { let origin = ConstVariableOrigin { param_def_id: Some(param.def_id), span }; let const_var_id = self .inner @@ -1007,16 +975,6 @@ impl<'tcx> InferCtxt<'tcx> { } } - pub fn var_for_effect(&self, param: &ty::GenericParamDef) -> GenericArg<'tcx> { - let ty = self - .tcx - .type_of(param.def_id) - .no_bound_vars() - .expect("const parameter types cannot be generic"); - debug_assert_eq!(self.tcx.types.bool, ty); - self.next_effect_var().into() - } - /// Given a set of generics defined on a type or impl, returns the generic parameters mapping /// each type/region parameter to a fresh inference variable. pub fn fresh_args_for_item(&self, span: Span, def_id: DefId) -> GenericArgsRef<'tcx> { @@ -1142,13 +1100,6 @@ impl<'tcx> InferCtxt<'tcx> { .probe_value(vid) .known() .unwrap_or(ct), - InferConst::EffectVar(vid) => self - .inner - .borrow_mut() - .effect_unification_table() - .probe_value(vid) - .known() - .unwrap_or(ct), InferConst::Fresh(_) => ct, }, ty::ConstKind::Param(_) @@ -1169,10 +1120,6 @@ impl<'tcx> InferCtxt<'tcx> { self.inner.borrow_mut().const_unification_table().find(var).vid } - pub fn root_effect_var(&self, var: ty::EffectVid) -> ty::EffectVid { - self.inner.borrow_mut().effect_unification_table().find(var).vid - } - /// Resolves an int var to a rigid int type, if it was constrained to one, /// or else the root int var in the unification table. pub fn opportunistic_resolve_int_var(&self, vid: ty::IntVid) -> Ty<'tcx> { @@ -1238,10 +1185,6 @@ impl<'tcx> InferCtxt<'tcx> { } } - pub fn probe_effect_var(&self, vid: EffectVid) -> Option<ty::Const<'tcx>> { - self.inner.borrow_mut().effect_unification_table().probe_value(vid).known() - } - /// Attempts to resolve all type/region/const variables in /// `value`. Region inference must have been run already (e.g., /// by calling `resolve_regions_and_report_errors`). If some @@ -1511,14 +1454,6 @@ impl<'tcx> InferCtxt<'tcx> { ConstVariableValue::Known { .. } => true, } } - - TyOrConstInferVar::Effect(v) => { - // If `probe_value` returns `Some`, it never equals - // `ty::ConstKind::Infer(ty::InferConst::Effect(v))`. - // - // Not `inlined_probe_value(v)` because this call site is colder. - self.probe_effect_var(v).is_some() - } } } @@ -1545,8 +1480,6 @@ pub enum TyOrConstInferVar { /// Equivalent to `ty::ConstKind::Infer(ty::InferConst::Var(_))`. Const(ConstVid), - /// Equivalent to `ty::ConstKind::Infer(ty::InferConst::EffectVar(_))`. - Effect(EffectVid), } impl<'tcx> TyOrConstInferVar { @@ -1577,7 +1510,6 @@ impl<'tcx> TyOrConstInferVar { fn maybe_from_const(ct: ty::Const<'tcx>) -> Option<Self> { match ct.kind() { ty::ConstKind::Infer(InferConst::Var(v)) => Some(TyOrConstInferVar::Const(v)), - ty::ConstKind::Infer(InferConst::EffectVar(v)) => Some(TyOrConstInferVar::Effect(v)), _ => None, } } diff --git a/compiler/rustc_infer/src/infer/outlives/mod.rs b/compiler/rustc_infer/src/infer/outlives/mod.rs index e23bb1aaa56..1afe50e336d 100644 --- a/compiler/rustc_infer/src/infer/outlives/mod.rs +++ b/compiler/rustc_infer/src/infer/outlives/mod.rs @@ -24,19 +24,9 @@ pub fn explicit_outlives_bounds<'tcx>( param_env .caller_bounds() .into_iter() - .map(ty::Clause::kind) + .filter_map(ty::Clause::as_region_outlives_clause) .filter_map(ty::Binder::no_bound_vars) - .filter_map(move |kind| match kind { - ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(r_a, r_b)) => { - Some(OutlivesBound::RegionSubRegion(r_b, r_a)) - } - ty::ClauseKind::Trait(_) - | ty::ClauseKind::TypeOutlives(_) - | ty::ClauseKind::Projection(_) - | ty::ClauseKind::ConstArgHasType(_, _) - | ty::ClauseKind::WellFormed(_) - | ty::ClauseKind::ConstEvaluatable(_) => None, - }) + .map(|ty::OutlivesPredicate(r_a, r_b)| OutlivesBound::RegionSubRegion(r_b, r_a)) } impl<'tcx> InferCtxt<'tcx> { diff --git a/compiler/rustc_infer/src/infer/relate/generalize.rs b/compiler/rustc_infer/src/infer/relate/generalize.rs index 7049444db9b..32817dbcb21 100644 --- a/compiler/rustc_infer/src/infer/relate/generalize.rs +++ b/compiler/rustc_infer/src/infer/relate/generalize.rs @@ -660,7 +660,6 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for Generalizer<'_, 'tcx> { } } } - ty::ConstKind::Infer(InferConst::EffectVar(_)) => Ok(c), // FIXME: Unevaluated constants are also not rigid, so the current // approach of always relating them structurally is incomplete. // diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs index 64cc76f827e..6ec2e0152f0 100644 --- a/compiler/rustc_infer/src/infer/resolve.rs +++ b/compiler/rustc_infer/src/infer/resolve.rs @@ -176,9 +176,6 @@ impl<'a, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for FullTypeResolver<'a, 'tcx> { ty::ConstKind::Infer(InferConst::Fresh(_)) => { bug!("Unexpected const in full const resolver: {:?}", c); } - ty::ConstKind::Infer(InferConst::EffectVar(evid)) => { - return Err(FixupError { unresolved: super::TyOrConstInferVar::Effect(evid) }); - } _ => {} } c.try_super_fold_with(self) diff --git a/compiler/rustc_infer/src/infer/snapshot/fudge.rs b/compiler/rustc_infer/src/infer/snapshot/fudge.rs index 613cebc266d..394e07a81e7 100644 --- a/compiler/rustc_infer/src/infer/snapshot/fudge.rs +++ b/compiler/rustc_infer/src/infer/snapshot/fudge.rs @@ -4,7 +4,6 @@ use rustc_data_structures::{snapshot_vec as sv, unify as ut}; use rustc_middle::infer::unify_key::{ConstVariableValue, ConstVidKey}; use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; use rustc_middle::ty::{self, ConstVid, FloatVid, IntVid, RegionVid, Ty, TyCtxt, TyVid}; -use rustc_type_ir::EffectVid; use rustc_type_ir::visit::TypeVisitableExt; use tracing::instrument; use ut::UnifyKey; @@ -129,7 +128,6 @@ struct SnapshotVarData { int_vars: Range<IntVid>, float_vars: Range<FloatVid>, const_vars: (Range<ConstVid>, Vec<ConstVariableOrigin>), - effect_vars: Range<EffectVid>, } impl SnapshotVarData { @@ -148,30 +146,16 @@ impl SnapshotVarData { &mut inner.const_unification_table(), vars_pre_snapshot.const_var_len, ); - let effect_vars = vars_since_snapshot( - &inner.effect_unification_table(), - vars_pre_snapshot.effect_var_len, - ); - let effect_vars = effect_vars.start.vid..effect_vars.end.vid; - - SnapshotVarData { region_vars, type_vars, int_vars, float_vars, const_vars, effect_vars } + SnapshotVarData { region_vars, type_vars, int_vars, float_vars, const_vars } } fn is_empty(&self) -> bool { - let SnapshotVarData { - region_vars, - type_vars, - int_vars, - float_vars, - const_vars, - effect_vars, - } = self; + let SnapshotVarData { region_vars, type_vars, int_vars, float_vars, const_vars } = self; region_vars.0.is_empty() && type_vars.0.is_empty() && int_vars.is_empty() && float_vars.is_empty() && const_vars.0.is_empty() - && effect_vars.is_empty() } } @@ -258,13 +242,6 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for InferenceFudger<'a, 'tcx> { ct } } - ty::InferConst::EffectVar(vid) => { - if self.snapshot_vars.effect_vars.contains(&vid) { - self.infcx.next_effect_var() - } else { - ct - } - } ty::InferConst::Fresh(_) => { unreachable!("unexpected fresh infcx var") } diff --git a/compiler/rustc_infer/src/infer/snapshot/mod.rs b/compiler/rustc_infer/src/infer/snapshot/mod.rs index fa813500c54..b16c80cf201 100644 --- a/compiler/rustc_infer/src/infer/snapshot/mod.rs +++ b/compiler/rustc_infer/src/infer/snapshot/mod.rs @@ -23,7 +23,6 @@ struct VariableLengths { int_var_len: usize, float_var_len: usize, const_var_len: usize, - effect_var_len: usize, } impl<'tcx> InferCtxt<'tcx> { @@ -35,7 +34,6 @@ impl<'tcx> InferCtxt<'tcx> { int_var_len: inner.int_unification_table().len(), float_var_len: inner.float_unification_table().len(), const_var_len: inner.const_unification_table().len(), - effect_var_len: inner.effect_unification_table().len(), } } diff --git a/compiler/rustc_infer/src/infer/snapshot/undo_log.rs b/compiler/rustc_infer/src/infer/snapshot/undo_log.rs index 79ea0915c9c..713389f4618 100644 --- a/compiler/rustc_infer/src/infer/snapshot/undo_log.rs +++ b/compiler/rustc_infer/src/infer/snapshot/undo_log.rs @@ -2,7 +2,7 @@ use std::marker::PhantomData; use rustc_data_structures::undo_log::{Rollback, UndoLogs}; use rustc_data_structures::{snapshot_vec as sv, unify as ut}; -use rustc_middle::infer::unify_key::{ConstVidKey, EffectVidKey, RegionVidKey}; +use rustc_middle::infer::unify_key::{ConstVidKey, RegionVidKey}; use rustc_middle::ty::{self, OpaqueHiddenType, OpaqueTypeKey}; use tracing::debug; @@ -22,7 +22,6 @@ pub(crate) enum UndoLog<'tcx> { ConstUnificationTable(sv::UndoLog<ut::Delegate<ConstVidKey<'tcx>>>), IntUnificationTable(sv::UndoLog<ut::Delegate<ty::IntVid>>), FloatUnificationTable(sv::UndoLog<ut::Delegate<ty::FloatVid>>), - EffectUnificationTable(sv::UndoLog<ut::Delegate<EffectVidKey<'tcx>>>), RegionConstraintCollector(region_constraints::UndoLog<'tcx>), RegionUnificationTable(sv::UndoLog<ut::Delegate<RegionVidKey<'tcx>>>), ProjectionCache(traits::UndoLog<'tcx>), @@ -50,7 +49,6 @@ impl_from! { FloatUnificationTable(sv::UndoLog<ut::Delegate<ty::FloatVid>>), ConstUnificationTable(sv::UndoLog<ut::Delegate<ConstVidKey<'tcx>>>), - EffectUnificationTable(sv::UndoLog<ut::Delegate<EffectVidKey<'tcx>>>), RegionUnificationTable(sv::UndoLog<ut::Delegate<RegionVidKey<'tcx>>>), ProjectionCache(traits::UndoLog<'tcx>), @@ -65,7 +63,6 @@ impl<'tcx> Rollback<UndoLog<'tcx>> for InferCtxtInner<'tcx> { UndoLog::ConstUnificationTable(undo) => self.const_unification_storage.reverse(undo), UndoLog::IntUnificationTable(undo) => self.int_unification_storage.reverse(undo), UndoLog::FloatUnificationTable(undo) => self.float_unification_storage.reverse(undo), - UndoLog::EffectUnificationTable(undo) => self.effect_unification_storage.reverse(undo), UndoLog::RegionConstraintCollector(undo) => { self.region_constraint_storage.as_mut().unwrap().reverse(undo) } diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 5c5cd99345e..a1e4bc75c21 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -1554,7 +1554,9 @@ impl<'tcx> LateLintPass<'tcx> for TrivialConstraints { // Ignore bounds that a user can't type | ClauseKind::WellFormed(..) // FIXME(generic_const_exprs): `ConstEvaluatable` can be written - | ClauseKind::ConstEvaluatable(..) => continue, + | ClauseKind::ConstEvaluatable(..) + // Users don't write this directly, only via another trait ref. + | ty::ClauseKind::HostEffect(..) => continue, }; if predicate.is_global() { cx.emit_span_lint(TRIVIAL_BOUNDS, span, BuiltinTrivialBounds { diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs index 83a8ca4307e..1c27e1daa90 100644 --- a/compiler/rustc_lint/src/nonstandard_style.rs +++ b/compiler/rustc_lint/src/nonstandard_style.rs @@ -542,11 +542,7 @@ impl<'tcx> LateLintPass<'tcx> for NonUpperCaseGlobals { } fn check_generic_param(&mut self, cx: &LateContext<'_>, param: &hir::GenericParam<'_>) { - if let GenericParamKind::Const { is_host_effect, .. } = param.kind { - // `host` params are explicitly allowed to be lowercase. - if is_host_effect { - return; - } + if let GenericParamKind::Const { .. } = param.kind { NonUpperCaseGlobals::check_upper_case(cx, "const parameter", ¶m.name.ident()); } } diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 7bb40996d58..71c7231a788 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -275,6 +275,8 @@ provide! { tcx, def_id, other, cdata, impl_parent => { table } defaultness => { table_direct } constness => { table_direct } + const_conditions => { table } + implied_const_bounds => { table_defaulted_array } coerce_unsized_info => { Ok(cdata .root @@ -330,7 +332,6 @@ provide! { tcx, def_id, other, cdata, .process_decoded(tcx, || panic!("{def_id:?} does not have trait_impl_trait_tys"))) } - associated_type_for_effects => { table } associated_types_for_impl_traits_in_associated_fn => { table_defaulted_array } visibility => { cdata.get_visibility(def_id.index) } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index ec678c7515b..e06c86ae4c0 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1433,6 +1433,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } } } + if tcx.is_conditionally_const(def_id) { + record!(self.tables.const_conditions[def_id] <- self.tcx.const_conditions(def_id)); + } if should_encode_type(tcx, local_id, def_kind) { record!(self.tables.type_of[def_id] <- self.tcx.type_of(def_id)); } @@ -1456,10 +1459,13 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.tcx.explicit_super_predicates_of(def_id).skip_binder()); record_defaulted_array!(self.tables.explicit_implied_predicates_of[def_id] <- self.tcx.explicit_implied_predicates_of(def_id).skip_binder()); - let module_children = self.tcx.module_children_local(local_id); record_array!(self.tables.module_children_non_reexports[def_id] <- module_children.iter().map(|child| child.res.def_id().index)); + if self.tcx.is_const_trait(def_id) { + record_defaulted_array!(self.tables.implied_const_bounds[def_id] + <- self.tcx.implied_const_bounds(def_id).skip_binder()); + } } if let DefKind::TraitAlias = def_kind { record!(self.tables.trait_def[def_id] <- self.tcx.trait_def(def_id)); @@ -1479,9 +1485,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { for &def_id in associated_item_def_ids { self.encode_info_for_assoc_item(def_id); } - if let Some(assoc_def_id) = self.tcx.associated_type_for_effects(def_id) { - record!(self.tables.associated_type_for_effects[def_id] <- assoc_def_id); - } } if let DefKind::Closure | DefKind::SyntheticCoroutineBody = def_kind && let Some(coroutine_kind) = self.tcx.coroutine_kind(def_id) @@ -1652,6 +1655,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { if let ty::AssocKind::Type = item.kind { self.encode_explicit_item_bounds(def_id); self.encode_explicit_item_super_predicates(def_id); + if tcx.is_conditionally_const(def_id) { + record_defaulted_array!(self.tables.implied_const_bounds[def_id] + <- self.tcx.implied_const_bounds(def_id).skip_binder()); + } } } AssocItemContainer::ImplContainer => { diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 79bd1c13b12..a00ca27aacc 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -392,9 +392,9 @@ define_tables! { inferred_outlives_of: Table<DefIndex, LazyArray<(ty::Clause<'static>, Span)>>, explicit_super_predicates_of: Table<DefIndex, LazyArray<(ty::Clause<'static>, Span)>>, explicit_implied_predicates_of: Table<DefIndex, LazyArray<(ty::Clause<'static>, Span)>>, + implied_const_bounds: Table<DefIndex, LazyArray<(ty::PolyTraitRef<'static>, Span)>>, inherent_impls: Table<DefIndex, LazyArray<DefIndex>>, associated_types_for_impl_traits_in_associated_fn: Table<DefIndex, LazyArray<DefId>>, - associated_type_for_effects: Table<DefIndex, Option<LazyValue<DefId>>>, opt_rpitit_info: Table<DefIndex, Option<LazyValue<ty::ImplTraitInTraitData>>>, is_effects_desugaring: Table<DefIndex, bool>, unused_generic_params: Table<DefIndex, UnusedGenericParams>, @@ -436,6 +436,7 @@ define_tables! { thir_abstract_const: Table<DefIndex, LazyValue<ty::EarlyBinder<'static, ty::Const<'static>>>>, impl_parent: Table<DefIndex, RawDefId>, constness: Table<DefIndex, hir::Constness>, + const_conditions: Table<DefIndex, LazyValue<ty::ConstConditions<'static>>>, defaultness: Table<DefIndex, hir::Defaultness>, // FIXME(eddyb) perhaps compute this on the fly if cheap enough? coerce_unsized_info: Table<DefIndex, LazyValue<ty::adjustment::CoerceUnsizedInfo>>, diff --git a/compiler/rustc_middle/src/infer/unify_key.rs b/compiler/rustc_middle/src/infer/unify_key.rs index cf692b145b8..7f9211043d6 100644 --- a/compiler/rustc_middle/src/infer/unify_key.rs +++ b/compiler/rustc_middle/src/infer/unify_key.rs @@ -172,70 +172,3 @@ impl<'tcx> UnifyValue for ConstVariableValue<'tcx> { } } } - -/// values for the effect inference variable -#[derive(Clone, Copy, Debug)] -pub enum EffectVarValue<'tcx> { - Unknown, - Known(ty::Const<'tcx>), -} - -impl<'tcx> EffectVarValue<'tcx> { - pub fn known(self) -> Option<ty::Const<'tcx>> { - match self { - EffectVarValue::Unknown => None, - EffectVarValue::Known(value) => Some(value), - } - } - - pub fn is_unknown(self) -> bool { - match self { - EffectVarValue::Unknown => true, - EffectVarValue::Known(_) => false, - } - } -} - -impl<'tcx> UnifyValue for EffectVarValue<'tcx> { - type Error = NoError; - - fn unify_values(value1: &Self, value2: &Self) -> Result<Self, Self::Error> { - match (*value1, *value2) { - (EffectVarValue::Unknown, EffectVarValue::Unknown) => Ok(EffectVarValue::Unknown), - (EffectVarValue::Unknown, EffectVarValue::Known(val)) - | (EffectVarValue::Known(val), EffectVarValue::Unknown) => { - Ok(EffectVarValue::Known(val)) - } - (EffectVarValue::Known(_), EffectVarValue::Known(_)) => { - bug!("equating known inference variables: {value1:?} {value2:?}") - } - } - } -} - -#[derive(PartialEq, Copy, Clone, Debug)] -pub struct EffectVidKey<'tcx> { - pub vid: ty::EffectVid, - pub phantom: PhantomData<ty::Const<'tcx>>, -} - -impl<'tcx> From<ty::EffectVid> for EffectVidKey<'tcx> { - fn from(vid: ty::EffectVid) -> Self { - EffectVidKey { vid, phantom: PhantomData } - } -} - -impl<'tcx> UnifyKey for EffectVidKey<'tcx> { - type Value = EffectVarValue<'tcx>; - #[inline] - fn index(&self) -> u32 { - self.vid.as_u32() - } - #[inline] - fn from_index(i: u32) -> Self { - EffectVidKey::from(ty::EffectVid::from_u32(i)) - } - fn tag() -> &'static str { - "EffectVidKey" - } -} diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index 48bf4ffced0..5f8427bd707 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -370,6 +370,7 @@ tcx_lifetime! { rustc_middle::ty::FnSig, rustc_middle::ty::GenericArg, rustc_middle::ty::GenericPredicates, + rustc_middle::ty::ConstConditions, rustc_middle::ty::inhabitedness::InhabitedPredicate, rustc_middle::ty::Instance, rustc_middle::ty::InstanceKind, diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index f8ba606e087..d03fc39c9ad 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -683,6 +683,24 @@ rustc_queries! { } } + query const_conditions( + key: DefId + ) -> ty::ConstConditions<'tcx> { + desc { |tcx| "computing the conditions for `{}` to be considered const", + tcx.def_path_str(key) + } + separate_provide_extern + } + + query implied_const_bounds( + key: DefId + ) -> ty::EarlyBinder<'tcx, &'tcx [(ty::PolyTraitRef<'tcx>, Span)]> { + desc { |tcx| "computing the implied `~const` bounds for `{}`", + tcx.def_path_str(key) + } + separate_provide_extern + } + /// To avoid cycles within the predicates of a single item we compute /// per-type-parameter predicates for resolving `T::AssocTy`. query type_param_predicates( @@ -854,12 +872,6 @@ rustc_queries! { separate_provide_extern } - query associated_type_for_effects(def_id: DefId) -> Option<DefId> { - desc { |tcx| "creating associated items for effects in `{}`", tcx.def_path_str(def_id) } - cache_on_disk_if { def_id.is_local() } - separate_provide_extern - } - /// Given an impl trait in trait `opaque_ty_def_id`, create and return the corresponding /// associated item. query associated_type_for_impl_trait_in_trait(opaque_ty_def_id: LocalDefId) -> LocalDefId { diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs index 7e533bc4291..ef9dfdd2f96 100644 --- a/compiler/rustc_middle/src/ty/codec.rs +++ b/compiler/rustc_middle/src/ty/codec.rs @@ -387,6 +387,17 @@ impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> for [(ty::Claus } impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> + for [(ty::PolyTraitRef<'tcx>, Span)] +{ + fn decode(decoder: &mut D) -> &'tcx Self { + decoder + .interner() + .arena + .alloc_from_iter((0..decoder.read_usize()).map(|_| Decodable::decode(decoder))) + } +} + +impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> for ty::List<ty::BoundVariableKind> { fn decode(decoder: &mut D) -> &'tcx Self { diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index b682524ae39..eab106a4403 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -78,10 +78,10 @@ use crate::traits::solve::{ use crate::ty::predicate::ExistentialPredicateStableCmpExt as _; use crate::ty::{ self, AdtDef, AdtDefData, AdtKind, Binder, Clause, Clauses, Const, GenericArg, GenericArgs, - GenericArgsRef, GenericParamDefKind, ImplPolarity, List, ListWithCachedTypeInfo, ParamConst, - ParamTy, Pattern, PatternKind, PolyExistentialPredicate, PolyFnSig, Predicate, PredicateKind, - PredicatePolarity, Region, RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, TyVid, - Visibility, + GenericArgsRef, GenericParamDefKind, HostPolarity, ImplPolarity, List, ListWithCachedTypeInfo, + ParamConst, ParamTy, Pattern, PatternKind, PolyExistentialPredicate, PolyFnSig, Predicate, + PredicateKind, PredicatePolarity, Region, RegionKind, ReprOptions, TraitObjectVisitor, Ty, + TyKind, TyVid, Visibility, }; #[allow(rustc::usage_of_ty_tykind)] @@ -383,6 +383,28 @@ impl<'tcx> Interner for TyCtxt<'tcx> { self.explicit_implied_predicates_of(def_id).map_bound(|preds| preds.into_iter().copied()) } + fn is_const_impl(self, def_id: DefId) -> bool { + self.is_conditionally_const(def_id) + } + + fn const_conditions( + self, + def_id: DefId, + ) -> ty::EarlyBinder<'tcx, impl IntoIterator<Item = ty::Binder<'tcx, ty::TraitRef<'tcx>>>> { + ty::EarlyBinder::bind( + self.const_conditions(def_id).instantiate_identity(self).into_iter().map(|(c, _)| c), + ) + } + + fn implied_const_bounds( + self, + def_id: DefId, + ) -> ty::EarlyBinder<'tcx, impl IntoIterator<Item = ty::Binder<'tcx, ty::TraitRef<'tcx>>>> { + ty::EarlyBinder::bind( + self.implied_const_bounds(def_id).iter_identity_copied().map(|(c, _)| c), + ) + } + fn has_target_features(self, def_id: DefId) -> bool { !self.codegen_fn_attrs(def_id).target_features.is_empty() } @@ -646,13 +668,6 @@ bidirectional_lang_item_map! { Destruct, DiscriminantKind, DynMetadata, - EffectsCompat, - EffectsIntersection, - EffectsIntersectionOutput, - EffectsMaybe, - EffectsNoRuntime, - EffectsRuntime, - EffectsTyCompat, Fn, FnMut, FnOnce, @@ -2196,7 +2211,7 @@ macro_rules! nop_slice_lift { nop_slice_lift! {ty::ValTree<'a> => ty::ValTree<'tcx>} TrivialLiftImpls! { - ImplPolarity, PredicatePolarity, Promoted + ImplPolarity, PredicatePolarity, Promoted, HostPolarity, } macro_rules! sty_debug_print { @@ -3125,6 +3140,7 @@ impl<'tcx> TyCtxt<'tcx> { } } + // FIXME(effects): Please remove this. It's a footgun. /// Whether the trait impl is marked const. This does not consider stability or feature gates. pub fn is_const_trait_impl_raw(self, def_id: DefId) -> bool { let Some(local_def_id) = def_id.as_local() else { return false }; diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index 8bd2ae9128f..64405d18c7d 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -592,9 +592,6 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for IsSuggestableVisitor<'tcx> { match c.kind() { ConstKind::Infer(InferConst::Var(_)) if self.infer_suggestable => {} - // effect variables are always suggestable, because they are not visible - ConstKind::Infer(InferConst::EffectVar(_)) => {} - ConstKind::Infer(..) | ConstKind::Bound(..) | ConstKind::Placeholder(..) diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs index 92a975c028e..704a197aa49 100644 --- a/compiler/rustc_middle/src/ty/flags.rs +++ b/compiler/rustc_middle/src/ty/flags.rs @@ -265,6 +265,12 @@ impl FlagComputation { ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)) => { self.add_args(trait_pred.trait_ref.args); } + ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(ty::HostEffectPredicate { + trait_ref, + host: _, + })) => { + self.add_args(trait_ref.args); + } ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate( a, b, @@ -354,9 +360,7 @@ impl FlagComputation { self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE); match infer { InferConst::Fresh(_) => self.add_flags(TypeFlags::HAS_CT_FRESH), - InferConst::Var(_) | InferConst::EffectVar(_) => { - self.add_flags(TypeFlags::HAS_CT_INFER) - } + InferConst::Var(_) => self.add_flags(TypeFlags::HAS_CT_INFER), } } ty::ConstKind::Bound(debruijn, _) => { diff --git a/compiler/rustc_middle/src/ty/generic_args.rs b/compiler/rustc_middle/src/ty/generic_args.rs index daf1362e25c..56111ee063e 100644 --- a/compiler/rustc_middle/src/ty/generic_args.rs +++ b/compiler/rustc_middle/src/ty/generic_args.rs @@ -501,12 +501,11 @@ impl<'tcx> GenericArgs<'tcx> { #[inline] pub fn non_erasable_generics( &'tcx self, - tcx: TyCtxt<'tcx>, - def_id: DefId, + // FIXME(effects): Remove these + _tcx: TyCtxt<'tcx>, + _def_id: DefId, ) -> impl DoubleEndedIterator<Item = GenericArgKind<'tcx>> + 'tcx { - let generics = tcx.generics_of(def_id); - self.iter().enumerate().filter_map(|(i, k)| match k.unpack() { - _ if Some(i) == generics.host_effect_index => None, + self.iter().filter_map(|k| match k.unpack() { ty::GenericArgKind::Lifetime(_) => None, generic => Some(generic), }) diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs index 63534a3d017..ab1b8fa6a73 100644 --- a/compiler/rustc_middle/src/ty/generics.rs +++ b/compiler/rustc_middle/src/ty/generics.rs @@ -14,7 +14,7 @@ use crate::ty::{EarlyBinder, GenericArgsRef}; pub enum GenericParamDefKind { Lifetime, Type { has_default: bool, synthetic: bool }, - Const { has_default: bool, is_host_effect: bool, synthetic: bool }, + Const { has_default: bool, synthetic: bool }, } impl GenericParamDefKind { @@ -81,10 +81,6 @@ impl GenericParamDef { } } - pub fn is_host_effect(&self) -> bool { - matches!(self.kind, GenericParamDefKind::Const { is_host_effect: true, .. }) - } - pub fn default_value<'tcx>( &self, tcx: TyCtxt<'tcx>, @@ -133,9 +129,6 @@ pub struct Generics { pub has_self: bool, pub has_late_bound_regions: Option<Span>, - - // The index of the host effect when instantiated. (i.e. might be index to parent args) - pub host_effect_index: Option<usize>, } impl<'tcx> rustc_type_ir::inherent::GenericsOf<TyCtxt<'tcx>> for &'tcx Generics { @@ -216,12 +209,10 @@ impl<'tcx> Generics { pub fn own_requires_monomorphization(&self) -> bool { for param in &self.own_params { match param.kind { - GenericParamDefKind::Type { .. } - | GenericParamDefKind::Const { is_host_effect: false, .. } => { + GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => { return true; } - GenericParamDefKind::Lifetime - | GenericParamDefKind::Const { is_host_effect: true, .. } => {} + GenericParamDefKind::Lifetime => {} } } false @@ -300,8 +291,6 @@ impl<'tcx> Generics { own_params.start = 1; } - let verbose = tcx.sess.verbose_internals(); - // Filter the default arguments. // // This currently uses structural equality instead @@ -316,8 +305,6 @@ impl<'tcx> Generics { param.default_value(tcx).is_some_and(|default| { default.instantiate(tcx, args) == args[param.index as usize] }) - // filter out trailing effect params, if we're not in `-Zverbose-internals`. - || (!verbose && matches!(param.kind, GenericParamDefKind::Const { is_host_effect: true, .. })) }) .count(); @@ -435,3 +422,73 @@ impl<'tcx> GenericPredicates<'tcx> { instantiated.spans.extend(self.predicates.iter().map(|(_, s)| s)); } } + +/// `~const` bounds for a given item. This is represented using a struct much like +/// `GenericPredicates`, where you can either choose to only instantiate the "own" +/// bounds or all of the bounds including those from the parent. This distinction +/// is necessary for code like `compare_method_predicate_entailment`. +#[derive(Copy, Clone, Default, Debug, TyEncodable, TyDecodable, HashStable)] +pub struct ConstConditions<'tcx> { + pub parent: Option<DefId>, + pub predicates: &'tcx [(ty::PolyTraitRef<'tcx>, Span)], +} + +impl<'tcx> ConstConditions<'tcx> { + pub fn instantiate( + self, + tcx: TyCtxt<'tcx>, + args: GenericArgsRef<'tcx>, + ) -> Vec<(ty::PolyTraitRef<'tcx>, Span)> { + let mut instantiated = vec![]; + self.instantiate_into(tcx, &mut instantiated, args); + instantiated + } + + pub fn instantiate_own( + self, + tcx: TyCtxt<'tcx>, + args: GenericArgsRef<'tcx>, + ) -> impl Iterator<Item = (ty::PolyTraitRef<'tcx>, Span)> + DoubleEndedIterator + ExactSizeIterator + { + EarlyBinder::bind(self.predicates).iter_instantiated_copied(tcx, args) + } + + pub fn instantiate_own_identity( + self, + ) -> impl Iterator<Item = (ty::PolyTraitRef<'tcx>, Span)> + DoubleEndedIterator + ExactSizeIterator + { + EarlyBinder::bind(self.predicates).iter_identity_copied() + } + + #[instrument(level = "debug", skip(self, tcx))] + fn instantiate_into( + self, + tcx: TyCtxt<'tcx>, + instantiated: &mut Vec<(ty::PolyTraitRef<'tcx>, Span)>, + args: GenericArgsRef<'tcx>, + ) { + if let Some(def_id) = self.parent { + tcx.const_conditions(def_id).instantiate_into(tcx, instantiated, args); + } + instantiated.extend( + self.predicates.iter().map(|&(p, s)| (EarlyBinder::bind(p).instantiate(tcx, args), s)), + ); + } + + pub fn instantiate_identity(self, tcx: TyCtxt<'tcx>) -> Vec<(ty::PolyTraitRef<'tcx>, Span)> { + let mut instantiated = vec![]; + self.instantiate_identity_into(tcx, &mut instantiated); + instantiated + } + + fn instantiate_identity_into( + self, + tcx: TyCtxt<'tcx>, + instantiated: &mut Vec<(ty::PolyTraitRef<'tcx>, Span)>, + ) { + if let Some(def_id) = self.parent { + tcx.const_conditions(def_id).instantiate_identity_into(tcx, instantiated); + } + instantiated.extend(self.predicates.iter().copied()); + } +} diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index b1c5ff50fdc..61cb4322501 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -476,7 +476,6 @@ impl<'tcx> Instance<'tcx> { pub fn mono(tcx: TyCtxt<'tcx>, def_id: DefId) -> Instance<'tcx> { let args = GenericArgs::for_item(tcx, def_id, |param, _| match param.kind { ty::GenericParamDefKind::Lifetime => tcx.lifetimes.re_erased.into(), - ty::GenericParamDefKind::Const { is_host_effect: true, .. } => tcx.consts.true_.into(), ty::GenericParamDefKind::Type { .. } => { bug!("Instance::mono: {:?} has type parameters", def_id) } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index ed24fcc7eb8..85414764817 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -84,12 +84,13 @@ pub use self::parameterized::ParameterizedOverTcx; pub use self::pattern::{Pattern, PatternKind}; pub use self::predicate::{ AliasTerm, Clause, ClauseKind, CoercePredicate, ExistentialPredicate, - ExistentialPredicateStableCmpExt, ExistentialProjection, ExistentialTraitRef, NormalizesTo, - OutlivesPredicate, PolyCoercePredicate, PolyExistentialPredicate, PolyExistentialProjection, - PolyExistentialTraitRef, PolyProjectionPredicate, PolyRegionOutlivesPredicate, - PolySubtypePredicate, PolyTraitPredicate, PolyTraitRef, PolyTypeOutlivesPredicate, Predicate, - PredicateKind, ProjectionPredicate, RegionOutlivesPredicate, SubtypePredicate, ToPolyTraitRef, - TraitPredicate, TraitRef, TypeOutlivesPredicate, + ExistentialPredicateStableCmpExt, ExistentialProjection, ExistentialTraitRef, + HostEffectPredicate, NormalizesTo, OutlivesPredicate, PolyCoercePredicate, + PolyExistentialPredicate, PolyExistentialProjection, PolyExistentialTraitRef, + PolyProjectionPredicate, PolyRegionOutlivesPredicate, PolySubtypePredicate, PolyTraitPredicate, + PolyTraitRef, PolyTypeOutlivesPredicate, Predicate, PredicateKind, ProjectionPredicate, + RegionOutlivesPredicate, SubtypePredicate, ToPolyTraitRef, TraitPredicate, TraitRef, + TypeOutlivesPredicate, }; pub use self::region::BoundRegionKind::*; pub use self::region::{ @@ -1998,10 +1999,75 @@ impl<'tcx> TyCtxt<'tcx> { pub fn is_const_fn_raw(self, def_id: DefId) -> bool { matches!( self.def_kind(def_id), - DefKind::Fn | DefKind::AssocFn | DefKind::Ctor(..) | DefKind::Closure + DefKind::Fn | DefKind::AssocFn | DefKind::Ctor(_, CtorKind::Fn) | DefKind::Closure ) && self.constness(def_id) == hir::Constness::Const } + /// Whether this item is conditionally constant for the purposes of the + /// effects implementation. + /// + /// This roughly corresponds to all const functions and other callable + /// items, along with const impls and traits, and associated types within + /// those impls and traits. + pub fn is_conditionally_const(self, def_id: impl Into<DefId>) -> bool { + let def_id: DefId = def_id.into(); + match self.def_kind(def_id) { + DefKind::Impl { of_trait: true } => { + self.constness(def_id) == hir::Constness::Const + && self.is_const_trait( + self.trait_id_of_impl(def_id) + .expect("expected trait for trait implementation"), + ) + } + DefKind::Fn | DefKind::Ctor(_, CtorKind::Fn) => { + self.constness(def_id) == hir::Constness::Const + } + DefKind::Trait => self.is_const_trait(def_id), + DefKind::AssocTy | DefKind::AssocFn => { + let parent_def_id = self.parent(def_id); + match self.def_kind(parent_def_id) { + DefKind::Impl { of_trait: false } => { + self.constness(def_id) == hir::Constness::Const + } + DefKind::Impl { of_trait: true } | DefKind::Trait => { + self.is_conditionally_const(parent_def_id) + } + _ => bug!("unexpected parent item of associated item: {parent_def_id:?}"), + } + } + DefKind::Closure | DefKind::OpaqueTy => { + // Closures and RPITs will eventually have const conditions + // for `~const` bounds. + false + } + DefKind::Ctor(_, CtorKind::Const) + | DefKind::Impl { of_trait: false } + | DefKind::Mod + | DefKind::Struct + | DefKind::Union + | DefKind::Enum + | DefKind::Variant + | DefKind::TyAlias + | DefKind::ForeignTy + | DefKind::TraitAlias + | DefKind::TyParam + | DefKind::Const + | DefKind::ConstParam + | DefKind::Static { .. } + | DefKind::AssocConst + | DefKind::Macro(_) + | DefKind::ExternCrate + | DefKind::Use + | DefKind::ForeignMod + | DefKind::AnonConst + | DefKind::InlineConst + | DefKind::Field + | DefKind::LifetimeParam + | DefKind::GlobalAsm + | DefKind::SyntheticCoroutineBody => false, + } + } + #[inline] pub fn is_const_trait(self, def_id: DefId) -> bool { self.trait_def(def_id).constness == hir::Constness::Const diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs index 7e1255f606c..43bdce5b576 100644 --- a/compiler/rustc_middle/src/ty/parameterized.rs +++ b/compiler/rustc_middle/src/ty/parameterized.rs @@ -132,6 +132,7 @@ parameterized_over_tcx! { ty::Ty, ty::FnSig, ty::GenericPredicates, + ty::ConstConditions, ty::TraitRef, ty::Const, ty::Predicate, diff --git a/compiler/rustc_middle/src/ty/predicate.rs b/compiler/rustc_middle/src/ty/predicate.rs index d20cb368278..3ecaa3e22d3 100644 --- a/compiler/rustc_middle/src/ty/predicate.rs +++ b/compiler/rustc_middle/src/ty/predicate.rs @@ -19,6 +19,7 @@ pub type ExistentialPredicate<'tcx> = ir::ExistentialPredicate<TyCtxt<'tcx>>; pub type ExistentialTraitRef<'tcx> = ir::ExistentialTraitRef<TyCtxt<'tcx>>; pub type ExistentialProjection<'tcx> = ir::ExistentialProjection<TyCtxt<'tcx>>; pub type TraitPredicate<'tcx> = ir::TraitPredicate<TyCtxt<'tcx>>; +pub type HostEffectPredicate<'tcx> = ir::HostEffectPredicate<TyCtxt<'tcx>>; pub type ClauseKind<'tcx> = ir::ClauseKind<TyCtxt<'tcx>>; pub type PredicateKind<'tcx> = ir::PredicateKind<TyCtxt<'tcx>>; pub type NormalizesTo<'tcx> = ir::NormalizesTo<TyCtxt<'tcx>>; @@ -143,6 +144,7 @@ impl<'tcx> Predicate<'tcx> { | PredicateKind::AliasRelate(..) | PredicateKind::NormalizesTo(..) => false, PredicateKind::Clause(ClauseKind::Trait(_)) + | PredicateKind::Clause(ClauseKind::HostEffect(..)) | PredicateKind::Clause(ClauseKind::RegionOutlives(_)) | PredicateKind::Clause(ClauseKind::TypeOutlives(_)) | PredicateKind::Clause(ClauseKind::Projection(_)) @@ -644,6 +646,7 @@ impl<'tcx> Predicate<'tcx> { match predicate.skip_binder() { PredicateKind::Clause(ClauseKind::Trait(t)) => Some(predicate.rebind(t)), PredicateKind::Clause(ClauseKind::Projection(..)) + | PredicateKind::Clause(ClauseKind::HostEffect(..)) | PredicateKind::Clause(ClauseKind::ConstArgHasType(..)) | PredicateKind::NormalizesTo(..) | PredicateKind::AliasRelate(..) @@ -664,6 +667,7 @@ impl<'tcx> Predicate<'tcx> { match predicate.skip_binder() { PredicateKind::Clause(ClauseKind::Projection(t)) => Some(predicate.rebind(t)), PredicateKind::Clause(ClauseKind::Trait(..)) + | PredicateKind::Clause(ClauseKind::HostEffect(..)) | PredicateKind::Clause(ClauseKind::ConstArgHasType(..)) | PredicateKind::NormalizesTo(..) | PredicateKind::AliasRelate(..) diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 10c3522eb0e..0248aad53e2 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -3075,6 +3075,15 @@ define_print! { p!(print(self.trait_ref.print_trait_sugared())) } + ty::HostEffectPredicate<'tcx> { + let constness = match self.host { + ty::HostPolarity::Const => { "const" } + ty::HostPolarity::Maybe => { "~const" } + }; + p!(print(self.trait_ref.self_ty()), ": {constness} "); + p!(print(self.trait_ref.print_trait_sugared())) + } + ty::TypeAndMut<'tcx> { p!(write("{}", self.mutbl.prefix_str()), print(self.ty)) } @@ -3087,6 +3096,7 @@ define_print! { ty::ClauseKind::RegionOutlives(predicate) => p!(print(predicate)), ty::ClauseKind::TypeOutlives(predicate) => p!(print(predicate)), ty::ClauseKind::Projection(predicate) => p!(print(predicate)), + ty::ClauseKind::HostEffect(predicate) => p!(print(predicate)), ty::ClauseKind::ConstArgHasType(ct, ty) => { p!("the constant `", print(ct), "` has type `", print(ty), "`") }, diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 06cbb6c9f1d..7fd7e463acf 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -17,10 +17,10 @@ use rustc_span::sym; use rustc_target::abi::{Float, Integer, IntegerType, Size}; use rustc_target::spec::abi::Abi; use smallvec::{SmallVec, smallvec}; -use tracing::{debug, instrument, trace}; +use tracing::{debug, instrument}; use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags; -use crate::query::{IntoQueryParam, Providers}; +use crate::query::Providers; use crate::ty::layout::{FloatExt, IntegerExt}; use crate::ty::{ self, Asyncness, FallibleTypeFolder, GenericArgKind, GenericArgsRef, Ty, TyCtxt, TypeFoldable, @@ -865,48 +865,6 @@ impl<'tcx> TyCtxt<'tcx> { || self.extern_crate(key).is_some_and(|e| e.is_direct()) } - /// Whether the item has a host effect param. This is different from `TyCtxt::is_const`, - /// because the item must also be "maybe const", and the crate where the item is - /// defined must also have the effects feature enabled. - pub fn has_host_param(self, def_id: impl IntoQueryParam<DefId>) -> bool { - self.generics_of(def_id).host_effect_index.is_some() - } - - pub fn expected_host_effect_param_for_body(self, def_id: impl Into<DefId>) -> ty::Const<'tcx> { - let def_id = def_id.into(); - // FIXME(effects): This is suspicious and should probably not be done, - // especially now that we enforce host effects and then properly handle - // effect vars during fallback. - let mut host_always_on = !self.features().effects() - || self.sess.opts.unstable_opts.unleash_the_miri_inside_of_you; - - // Compute the constness required by the context. - let const_context = self.hir().body_const_context(def_id); - - let kind = self.def_kind(def_id); - debug_assert_ne!(kind, DefKind::ConstParam); - - if self.has_attr(def_id, sym::rustc_do_not_const_check) { - trace!("do not const check this context"); - host_always_on = true; - } - - match const_context { - _ if host_always_on => self.consts.true_, - Some(hir::ConstContext::Static(_) | hir::ConstContext::Const { .. }) => { - self.consts.false_ - } - Some(hir::ConstContext::ConstFn) => { - let host_idx = self - .generics_of(def_id) - .host_effect_index - .expect("ConstContext::Maybe must have host effect param"); - ty::GenericArgs::identity_for_item(self, def_id).const_at(host_idx) - } - None => self.consts.true_, - } - } - /// Expand any [weak alias types][weak] contained within the given `value`. /// /// This should be used over other normalization routines in situations where diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index b4d084d4dff..e5c59d60822 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -1522,7 +1522,6 @@ fn create_mono_items_for_default_impls<'tcx>( // it, to validate whether or not the impl is legal to instantiate at all. let only_region_params = |param: &ty::GenericParamDef, _: &_| match param.kind { GenericParamDefKind::Lifetime => tcx.lifetimes.re_erased.into(), - GenericParamDefKind::Const { is_host_effect: true, .. } => tcx.consts.true_.into(), GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => { unreachable!( "`own_requires_monomorphization` check means that \ diff --git a/compiler/rustc_next_trait_solver/src/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonicalizer.rs index 23634d35c07..63608f9e856 100644 --- a/compiler/rustc_next_trait_solver/src/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonicalizer.rs @@ -431,7 +431,6 @@ impl<D: SolverDelegate<Interner = I>, I: Interner> TypeFolder<I> for Canonicaliz ); CanonicalVarKind::Const(self.delegate.universe_of_ct(vid).unwrap()) } - ty::InferConst::EffectVar(_) => CanonicalVarKind::Effect, ty::InferConst::Fresh(_) => todo!(), }, ty::ConstKind::Placeholder(placeholder) => match self.canonicalize_mode { diff --git a/compiler/rustc_next_trait_solver/src/resolve.rs b/compiler/rustc_next_trait_solver/src/resolve.rs index f2654f7534e..71c87714745 100644 --- a/compiler/rustc_next_trait_solver/src/resolve.rs +++ b/compiler/rustc_next_trait_solver/src/resolve.rs @@ -76,9 +76,6 @@ impl<D: SolverDelegate<Interner = I>, I: Interner> TypeFolder<I> for EagerResolv resolved } } - ty::ConstKind::Infer(ty::InferConst::EffectVar(vid)) => { - self.delegate.opportunistic_resolve_effect_var(vid) - } _ => { if c.has_infer() { c.super_fold_with(self) 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 c9c0d6391fc..5e604a5d74f 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs @@ -270,11 +270,6 @@ 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> @@ -481,9 +476,6 @@ where Some(TraitSolverLangItem::TransmuteTrait) => { G::consider_builtin_transmute_candidate(self, goal) } - Some(TraitSolverLangItem::EffectsIntersection) => { - G::consider_builtin_effects_intersection_candidate(self, goal) - } _ => Err(NoSolution), } }; diff --git a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs new file mode 100644 index 00000000000..62b4bb0004c --- /dev/null +++ b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs @@ -0,0 +1,296 @@ +//! Dealing with host effect goals, i.e. enforcing the constness in +//! `T: const Trait` or `T: ~const Trait`. + +use rustc_type_ir::fast_reject::DeepRejectCtxt; +use rustc_type_ir::inherent::*; +use rustc_type_ir::{self as ty, Interner}; +use tracing::instrument; + +use super::assembly::Candidate; +use crate::delegate::SolverDelegate; +use crate::solve::assembly::{self}; +use crate::solve::{ + BuiltinImplSource, CandidateSource, Certainty, EvalCtxt, Goal, GoalSource, NoSolution, + QueryResult, +}; + +impl<D, I> assembly::GoalKind<D> for ty::HostEffectPredicate<I> +where + D: SolverDelegate<Interner = I>, + I: Interner, +{ + fn self_ty(self) -> I::Ty { + self.self_ty() + } + + fn trait_ref(self, _: I) -> ty::TraitRef<I> { + self.trait_ref + } + + fn with_self_ty(self, cx: I, self_ty: I::Ty) -> Self { + self.with_self_ty(cx, self_ty) + } + + fn trait_def_id(self, _: I) -> I::DefId { + self.def_id() + } + + fn probe_and_match_goal_against_assumption( + ecx: &mut EvalCtxt<'_, D>, + source: rustc_type_ir::solve::CandidateSource<I>, + goal: Goal<I, Self>, + assumption: <I as Interner>::Clause, + then: impl FnOnce(&mut EvalCtxt<'_, D>) -> QueryResult<I>, + ) -> Result<Candidate<I>, NoSolution> { + if let Some(host_clause) = assumption.as_host_effect_clause() { + if host_clause.def_id() == goal.predicate.def_id() + && host_clause.host().satisfies(goal.predicate.host) + { + if !DeepRejectCtxt::relate_rigid_rigid(ecx.cx()).args_may_unify( + goal.predicate.trait_ref.args, + host_clause.skip_binder().trait_ref.args, + ) { + return Err(NoSolution); + } + + ecx.probe_trait_candidate(source).enter(|ecx| { + let assumption_trait_pred = ecx.instantiate_binder_with_infer(host_clause); + ecx.eq( + goal.param_env, + goal.predicate.trait_ref, + assumption_trait_pred.trait_ref, + )?; + then(ecx) + }) + } else { + Err(NoSolution) + } + } else { + Err(NoSolution) + } + } + + fn consider_impl_candidate( + ecx: &mut EvalCtxt<'_, D>, + goal: Goal<I, Self>, + impl_def_id: <I as Interner>::DefId, + ) -> Result<Candidate<I>, NoSolution> { + let cx = ecx.cx(); + + let impl_trait_ref = cx.impl_trait_ref(impl_def_id); + if !DeepRejectCtxt::relate_rigid_infer(ecx.cx()) + .args_may_unify(goal.predicate.trait_ref.args, impl_trait_ref.skip_binder().args) + { + return Err(NoSolution); + } + + let impl_polarity = cx.impl_polarity(impl_def_id); + match impl_polarity { + ty::ImplPolarity::Negative => return Err(NoSolution), + ty::ImplPolarity::Reservation => { + unimplemented!("reservation impl for const trait: {:?}", goal) + } + ty::ImplPolarity::Positive => {} + }; + + if !cx.is_const_impl(impl_def_id) { + return Err(NoSolution); + } + + ecx.probe_trait_candidate(CandidateSource::Impl(impl_def_id)).enter(|ecx| { + let impl_args = ecx.fresh_args_for_item(impl_def_id); + ecx.record_impl_args(impl_args); + let impl_trait_ref = impl_trait_ref.instantiate(cx, impl_args); + + ecx.eq(goal.param_env, goal.predicate.trait_ref, impl_trait_ref)?; + let where_clause_bounds = cx + .predicates_of(impl_def_id) + .iter_instantiated(cx, impl_args) + .map(|pred| goal.with(cx, pred)); + ecx.add_goals(GoalSource::ImplWhereBound, where_clause_bounds); + + // For this impl to be `const`, we need to check its `~const` bounds too. + let const_conditions = cx + .const_conditions(impl_def_id) + .iter_instantiated(cx, impl_args) + .map(|bound_trait_ref| { + goal.with(cx, bound_trait_ref.to_host_effect_clause(cx, goal.predicate.host)) + }); + ecx.add_goals(GoalSource::ImplWhereBound, const_conditions); + + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + }) + } + + fn consider_error_guaranteed_candidate( + ecx: &mut EvalCtxt<'_, D>, + _guar: <I as Interner>::ErrorGuaranteed, + ) -> Result<Candidate<I>, NoSolution> { + ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc) + .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)) + } + + fn consider_auto_trait_candidate( + _ecx: &mut EvalCtxt<'_, D>, + _goal: Goal<I, Self>, + ) -> Result<Candidate<I>, NoSolution> { + unreachable!("auto traits are never const") + } + + fn consider_trait_alias_candidate( + _ecx: &mut EvalCtxt<'_, D>, + _goal: Goal<I, Self>, + ) -> Result<Candidate<I>, NoSolution> { + unreachable!("trait aliases are never const") + } + + fn consider_builtin_sized_candidate( + _ecx: &mut EvalCtxt<'_, D>, + _goal: Goal<I, Self>, + ) -> Result<Candidate<I>, NoSolution> { + unreachable!("Sized is never const") + } + + fn consider_builtin_copy_clone_candidate( + _ecx: &mut EvalCtxt<'_, D>, + _goal: Goal<I, Self>, + ) -> Result<Candidate<I>, NoSolution> { + todo!("Copy/Clone is not yet const") + } + + fn consider_builtin_pointer_like_candidate( + _ecx: &mut EvalCtxt<'_, D>, + _goal: Goal<I, Self>, + ) -> Result<Candidate<I>, NoSolution> { + unreachable!("PointerLike is not const") + } + + fn consider_builtin_fn_ptr_trait_candidate( + _ecx: &mut EvalCtxt<'_, D>, + _goal: Goal<I, Self>, + ) -> Result<Candidate<I>, NoSolution> { + todo!("Fn* are not yet const") + } + + fn consider_builtin_fn_trait_candidates( + _ecx: &mut EvalCtxt<'_, D>, + _goal: Goal<I, Self>, + _kind: rustc_type_ir::ClosureKind, + ) -> Result<Candidate<I>, NoSolution> { + todo!("Fn* are not yet const") + } + + fn consider_builtin_async_fn_trait_candidates( + _ecx: &mut EvalCtxt<'_, D>, + _goal: Goal<I, Self>, + _kind: rustc_type_ir::ClosureKind, + ) -> Result<Candidate<I>, NoSolution> { + todo!("AsyncFn* are not yet const") + } + + fn consider_builtin_async_fn_kind_helper_candidate( + _ecx: &mut EvalCtxt<'_, D>, + _goal: Goal<I, Self>, + ) -> Result<Candidate<I>, NoSolution> { + unreachable!("AsyncFnKindHelper is not const") + } + + fn consider_builtin_tuple_candidate( + _ecx: &mut EvalCtxt<'_, D>, + _goal: Goal<I, Self>, + ) -> Result<Candidate<I>, NoSolution> { + unreachable!("Tuple trait is not const") + } + + fn consider_builtin_pointee_candidate( + _ecx: &mut EvalCtxt<'_, D>, + _goal: Goal<I, Self>, + ) -> Result<Candidate<I>, NoSolution> { + unreachable!("Pointee is not const") + } + + fn consider_builtin_future_candidate( + _ecx: &mut EvalCtxt<'_, D>, + _goal: Goal<I, Self>, + ) -> Result<Candidate<I>, NoSolution> { + unreachable!("Future is not const") + } + + fn consider_builtin_iterator_candidate( + _ecx: &mut EvalCtxt<'_, D>, + _goal: Goal<I, Self>, + ) -> Result<Candidate<I>, NoSolution> { + todo!("Iterator is not yet const") + } + + fn consider_builtin_fused_iterator_candidate( + _ecx: &mut EvalCtxt<'_, D>, + _goal: Goal<I, Self>, + ) -> Result<Candidate<I>, NoSolution> { + unreachable!("FusedIterator is not const") + } + + fn consider_builtin_async_iterator_candidate( + _ecx: &mut EvalCtxt<'_, D>, + _goal: Goal<I, Self>, + ) -> Result<Candidate<I>, NoSolution> { + unreachable!("AsyncIterator is not const") + } + + fn consider_builtin_coroutine_candidate( + _ecx: &mut EvalCtxt<'_, D>, + _goal: Goal<I, Self>, + ) -> Result<Candidate<I>, NoSolution> { + unreachable!("Coroutine is not const") + } + + fn consider_builtin_discriminant_kind_candidate( + _ecx: &mut EvalCtxt<'_, D>, + _goal: Goal<I, Self>, + ) -> Result<Candidate<I>, NoSolution> { + unreachable!("DiscriminantKind is not const") + } + + fn consider_builtin_async_destruct_candidate( + _ecx: &mut EvalCtxt<'_, D>, + _goal: Goal<I, Self>, + ) -> Result<Candidate<I>, NoSolution> { + unreachable!("AsyncDestruct is not const") + } + + fn consider_builtin_destruct_candidate( + _ecx: &mut EvalCtxt<'_, D>, + _goal: Goal<I, Self>, + ) -> Result<Candidate<I>, NoSolution> { + unreachable!("Destruct is not const") + } + + fn consider_builtin_transmute_candidate( + _ecx: &mut EvalCtxt<'_, D>, + _goal: Goal<I, Self>, + ) -> Result<Candidate<I>, NoSolution> { + unreachable!("TransmuteFrom is not const") + } + + fn consider_structural_builtin_unsize_candidates( + _ecx: &mut EvalCtxt<'_, D>, + _goal: Goal<I, Self>, + ) -> Vec<Candidate<I>> { + unreachable!("Unsize is not const") + } +} + +impl<D, I> EvalCtxt<'_, D> +where + D: SolverDelegate<Interner = I>, + I: Interner, +{ + #[instrument(level = "trace", skip(self))] + pub(super) fn compute_host_effect_goal( + &mut self, + goal: Goal<I, ty::HostEffectPredicate<I>>, + ) -> QueryResult<I> { + let candidates = self.assemble_and_evaluate_candidates(goal); + self.merge_candidates(candidates) + } +} diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index 250174e033e..7608253882a 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -443,6 +443,9 @@ where ty::PredicateKind::Clause(ty::ClauseKind::Trait(predicate)) => { self.compute_trait_goal(Goal { param_env, predicate }) } + ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(predicate)) => { + self.compute_host_effect_goal(Goal { param_env, predicate }) + } ty::PredicateKind::Clause(ty::ClauseKind::Projection(predicate)) => { self.compute_projection_goal(Goal { param_env, predicate }) } diff --git a/compiler/rustc_next_trait_solver/src/solve/mod.rs b/compiler/rustc_next_trait_solver/src/solve/mod.rs index a475a58e483..6793779b205 100644 --- a/compiler/rustc_next_trait_solver/src/solve/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/mod.rs @@ -13,6 +13,7 @@ mod alias_relate; mod assembly; +mod effect_goals; mod eval_ctxt; pub mod inspect; mod normalizes_to; @@ -182,12 +183,6 @@ where let (ct, ty) = goal.predicate; let ct_ty = match ct.kind() { - // FIXME: Ignore effect vars because canonicalization doesn't handle them correctly - // and if we stall on the var then we wind up creating ambiguity errors in a probe - // for this goal which contains an effect var. Which then ends up ICEing. - ty::ConstKind::Infer(ty::InferConst::EffectVar(_)) => { - return self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes); - } ty::ConstKind::Infer(_) => { return self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS); } 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 4d8b193ee49..c98fd853551 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 @@ -911,68 +911,6 @@ where ) -> Result<Candidate<I>, NoSolution> { panic!("`TransmuteFrom` 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 a8d6536baad..6b26f960286 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -719,47 +719,6 @@ 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> diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 7827975d3ca..05954143aee 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -137,6 +137,10 @@ where ty::ClauseKind::Trait(ty::TraitPredicate { trait_ref, polarity: _ }) => { self.visit_trait(trait_ref) } + ty::ClauseKind::HostEffect(pred) => { + try_visit!(self.visit_trait(pred.trait_ref)); + pred.host.visit_with(self) + } ty::ClauseKind::Projection(ty::ProjectionPredicate { projection_term: projection_ty, term, diff --git a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs index ef2ee9a166a..8f05f859c07 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs @@ -588,7 +588,6 @@ impl<'tcx> Stable<'tcx> for ty::Generics { .has_late_bound_regions .as_ref() .map(|late_bound_regions| late_bound_regions.stable(tables)), - host_effect_index: self.host_effect_index, } } } @@ -603,7 +602,7 @@ impl<'tcx> Stable<'tcx> for rustc_middle::ty::GenericParamDefKind { ty::GenericParamDefKind::Type { has_default, synthetic } => { GenericParamDefKind::Type { has_default: *has_default, synthetic: *synthetic } } - ty::GenericParamDefKind::Const { has_default, is_host_effect: _, synthetic: _ } => { + ty::GenericParamDefKind::Const { has_default, synthetic: _ } => { GenericParamDefKind::Const { has_default: *has_default } } } @@ -690,6 +689,9 @@ impl<'tcx> Stable<'tcx> for ty::ClauseKind<'tcx> { ClauseKind::ConstEvaluatable(const_) => { stable_mir::ty::ClauseKind::ConstEvaluatable(const_.stable(tables)) } + ClauseKind::HostEffect(..) => { + todo!() + } } } } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index aa05b88ea0c..bf5f948fe91 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -195,14 +195,6 @@ symbols! { Display, DoubleEndedIterator, Duration, - EffectsCompat, - EffectsIntersection, - EffectsIntersectionOutput, - EffectsMaybe, - EffectsNoRuntime, - EffectsRuntime, - EffectsTyCompat, - Effects__, Encodable, Encoder, Enumerate, @@ -1737,7 +1729,6 @@ symbols! { rustc_reallocator, rustc_regions, rustc_reservation_impl, - rustc_runtime, rustc_safe_intrinsic, rustc_serialize, rustc_skip_during_method_dispatch, diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index 6ef64c3ed80..b7e2ed391cd 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -156,8 +156,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { (leaf_trait_predicate, &obligation) }; - let (main_trait_predicate, leaf_trait_predicate, predicate_constness) = self.get_effects_trait_pred_override(main_trait_predicate, leaf_trait_predicate, span); - let main_trait_ref = main_trait_predicate.to_poly_trait_ref(); let leaf_trait_ref = leaf_trait_predicate.to_poly_trait_ref(); @@ -228,7 +226,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let err_msg = self.get_standard_error_message( main_trait_predicate, message, - predicate_constness, + None, append_const_msg, post_message, ); @@ -289,13 +287,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ); } - if tcx.is_lang_item(leaf_trait_ref.def_id(), LangItem::Drop) - && matches!(predicate_constness, Some(ty::BoundConstness::ConstIfConst | ty::BoundConstness::Const)) - { - err.note("`~const Drop` was renamed to `~const Destruct`"); - err.note("See <https://github.com/rust-lang/rust/pull/94901> for more details"); - } - let explanation = get_explanation_based_on_obligation( self.tcx, &obligation, @@ -541,6 +532,29 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { err } + ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(predicate)) => { + // FIXME(effects): We should recompute the predicate with `~const` + // if it's `const`, and if it holds, explain that this bound only + // *conditionally* holds. If that fails, we should also do selection + // to drill this down to an impl or built-in source, so we can + // point at it and explain that while the trait *is* implemented, + // that implementation is not const. + let err_msg = self.get_standard_error_message( + bound_predicate.rebind(ty::TraitPredicate { + trait_ref: predicate.trait_ref, + polarity: ty::PredicatePolarity::Positive, + }), + None, + Some(match predicate.host { + ty::HostPolarity::Maybe => ty::BoundConstness::ConstIfConst, + ty::HostPolarity::Const => ty::BoundConstness::Const, + }), + None, + String::new(), + ); + struct_span_code_err!(self.dcx(), span, E0277, "{}", err_msg) + } + ty::PredicateKind::Subtype(predicate) => { // Errors for Subtype predicates show up as // `FulfillmentErrorCode::SubtypeError`, @@ -2374,52 +2388,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { }) } - /// For effects predicates such as `<u32 as Add>::Effects: Compat<host>`, pretend that the - /// predicate that failed was `u32: Add`. Return the constness of such predicate to later - /// print as `u32: ~const Add`. - fn get_effects_trait_pred_override( - &self, - p: ty::PolyTraitPredicate<'tcx>, - leaf: ty::PolyTraitPredicate<'tcx>, - span: Span, - ) -> (ty::PolyTraitPredicate<'tcx>, ty::PolyTraitPredicate<'tcx>, Option<ty::BoundConstness>) - { - let trait_ref = p.to_poly_trait_ref(); - if !self.tcx.is_lang_item(trait_ref.def_id(), LangItem::EffectsCompat) { - return (p, leaf, None); - } - - let Some(ty::Alias(ty::AliasTyKind::Projection, projection)) = - trait_ref.self_ty().no_bound_vars().map(Ty::kind) - else { - return (p, leaf, None); - }; - - let constness = trait_ref.skip_binder().args.const_at(1); - - let constness = if constness == self.tcx.consts.true_ || constness.is_ct_infer() { - None - } else if constness == self.tcx.consts.false_ { - Some(ty::BoundConstness::Const) - } else if matches!(constness.kind(), ty::ConstKind::Param(_)) { - Some(ty::BoundConstness::ConstIfConst) - } else { - self.dcx().span_bug(span, format!("Unknown constness argument: {constness:?}")); - }; - - let new_pred = p.map_bound(|mut trait_pred| { - trait_pred.trait_ref = projection.trait_ref(self.tcx); - trait_pred - }); - - let new_leaf = leaf.map_bound(|mut trait_pred| { - trait_pred.trait_ref = projection.trait_ref(self.tcx); - trait_pred - }); - - (new_pred, new_leaf, constness) - } - fn add_tuple_trait_message( &self, obligation_cause_code: &ObligationCauseCode<'tcx>, diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index 12aeee0d02f..934fe9ec47c 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -806,7 +806,8 @@ impl<'tcx> AutoTraitFinder<'tcx> { | ty::PredicateKind::Subtype(..) // FIXME(generic_const_exprs): you can absolutely add this as a where clauses | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) - | ty::PredicateKind::Coerce(..) => {} + | ty::PredicateKind::Coerce(..) + | ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(..)) => {} ty::PredicateKind::Ambiguous => return false, }; } diff --git a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs index cc0450e0b05..a068f25fe35 100644 --- a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs +++ b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs @@ -245,6 +245,7 @@ fn predicate_references_self<'tcx>( | ty::ClauseKind::RegionOutlives(..) // FIXME(generic_const_exprs): this can mention `Self` | ty::ClauseKind::ConstEvaluatable(..) + | ty::ClauseKind::HostEffect(..) => None, } } @@ -284,7 +285,8 @@ fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool { | ty::ClauseKind::Projection(_) | ty::ClauseKind::ConstArgHasType(_, _) | ty::ClauseKind::WellFormed(_) - | ty::ClauseKind::ConstEvaluatable(_) => false, + | ty::ClauseKind::ConstEvaluatable(_) + | ty::ClauseKind::HostEffect(..) => false, }) } diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 2bdeb00bdac..1754418156d 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -372,7 +372,11 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { | ty::PredicateKind::Subtype(_) | ty::PredicateKind::Coerce(_) | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) - | ty::PredicateKind::ConstEquate(..) => { + | ty::PredicateKind::ConstEquate(..) + // FIXME(effects): We may need to do this using the higher-ranked + // pred instead of just instantiating it with placeholders b/c of + // higher-ranked implied bound issues in the old solver. + | ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(..)) => { let pred = ty::Binder::dummy(infcx.enter_forall_and_leak_universe(binder)); let mut obligations = PredicateObligations::with_capacity(1); obligations.push(obligation.with(infcx.tcx, pred)); @@ -398,6 +402,10 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { ) } + ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(..)) => { + ProcessResult::Changed(Default::default()) + } + ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(data)) => { if infcx.considering_regions { infcx.region_outlives_predicate(&obligation.cause, Binder::dummy(data)); @@ -450,7 +458,6 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { ty::ConstKind::Infer(var) => { let var = match var { ty::InferConst::Var(vid) => TyOrConstInferVar::Const(vid), - ty::InferConst::EffectVar(vid) => TyOrConstInferVar::Effect(vid), ty::InferConst::Fresh(_) => { bug!("encountered fresh const in fulfill") } diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs index dfd0cab6905..c6e41e57f0c 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs @@ -96,6 +96,7 @@ pub fn compute_implied_outlives_bounds_inner<'tcx>( // FIXME(const_generics): Make sure that `<'a, 'b, const N: &'a &'b u32>` is sound // if we ever support that ty::PredicateKind::Clause(ty::ClauseKind::Trait(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(..)) | ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..)) | ty::PredicateKind::Subtype(..) | ty::PredicateKind::Coerce(..) @@ -200,6 +201,7 @@ pub fn compute_implied_outlives_bounds_compat_inner<'tcx>( // FIXME(const_generics): Make sure that `<'a, 'b, const N: &'a &'b u32>` is sound // if we ever support that ty::PredicateKind::Clause(ty::ClauseKind::Trait(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(..)) | ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..)) | ty::PredicateKind::Subtype(..) | ty::PredicateKind::Coerce(..) diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index c0122d3d552..47601b0c18d 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -546,7 +546,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } // Provide an impl for suitable functions, rejecting `#[target_feature]` functions (RFC 2396). - ty::FnDef(def_id, _args) => { + ty::FnDef(def_id, _) => { let tcx = self.tcx(); if tcx.fn_sig(def_id).skip_binder().is_fn_trait_compatible() && tcx.codegen_fn_attrs(def_id).target_features.is_empty() diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index d5b1c5a97da..ec4114fd9d7 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -645,6 +645,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.evaluate_trait_predicate_recursively(previous_stack, obligation) } + ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(..)) => { + // FIXME(effects): It should be relatively straightforward to implement + // old trait solver support for `HostEffect` bounds; or at least basic + // support for them. + todo!() + } + ty::PredicateKind::Subtype(p) => { let p = bound_predicate.rebind(p); // Does this code ever run? @@ -1821,8 +1828,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { |cand: ty::PolyTraitPredicate<'tcx>| cand.is_global() && !cand.has_bound_vars(); // (*) Prefer `BuiltinCandidate { has_nested: false }`, `PointeeCandidate`, - // `DiscriminantKindCandidate`, `ConstDestructCandidate` - // to anything else. + // or `DiscriminantKindCandidate` to anything else. // // This is a fix for #53123 and prevents winnowing from accidentally extending the // lifetime of a variable. diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 8904a9a6858..437343b569c 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -170,6 +170,10 @@ pub fn clause_obligations<'tcx>( ty::ClauseKind::Trait(t) => { wf.compute_trait_pred(t, Elaborate::None); } + ty::ClauseKind::HostEffect(..) => { + // Technically the well-formedness of this predicate is implied by + // the corresponding trait predicate it should've been generated beside. + } ty::ClauseKind::RegionOutlives(..) => {} ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(ty, _reg)) => { wf.compute(ty.into()); @@ -1021,6 +1025,7 @@ pub(crate) fn required_region_bounds<'tcx>( } } ty::ClauseKind::Trait(_) + | ty::ClauseKind::HostEffect(..) | ty::ClauseKind::RegionOutlives(_) | ty::ClauseKind::Projection(_) | ty::ClauseKind::ConstArgHasType(_, _) diff --git a/compiler/rustc_traits/src/normalize_erasing_regions.rs b/compiler/rustc_traits/src/normalize_erasing_regions.rs index f01a12b0a00..3e2794f6489 100644 --- a/compiler/rustc_traits/src/normalize_erasing_regions.rs +++ b/compiler/rustc_traits/src/normalize_erasing_regions.rs @@ -55,6 +55,7 @@ fn not_outlives_predicate(p: ty::Predicate<'_>) -> bool { | ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(..)) => false, ty::PredicateKind::Clause(ty::ClauseKind::Trait(..)) | ty::PredicateKind::Clause(ty::ClauseKind::Projection(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(..)) | ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..)) | ty::PredicateKind::NormalizesTo(..) | ty::PredicateKind::AliasRelate(..) diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs index a3210dd80d7..16fd28201c2 100644 --- a/compiler/rustc_ty_utils/src/assoc.rs +++ b/compiler/rustc_ty_utils/src/assoc.rs @@ -4,9 +4,8 @@ use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId}; use rustc_hir::intravisit::{self, Visitor}; use rustc_middle::query::Providers; -use rustc_middle::ty::{self, ImplTraitInTraitData, Ty, TyCtxt}; +use rustc_middle::ty::{self, ImplTraitInTraitData, TyCtxt}; use rustc_middle::{bug, span_bug}; -use rustc_span::sym; use rustc_span::symbol::kw; pub(crate) fn provide(providers: &mut Providers) { @@ -15,7 +14,6 @@ pub(crate) fn provide(providers: &mut Providers) { associated_item_def_ids, associated_items, associated_types_for_impl_traits_in_associated_fn, - associated_type_for_effects, associated_type_for_impl_trait_in_trait, impl_item_implementor_ids, ..*providers @@ -46,8 +44,7 @@ fn associated_item_def_ids(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &[DefId] { ) }) .copied(), - ) - .chain(tcx.associated_type_for_effects(def_id)), + ), ) } hir::ItemKind::Impl(impl_) => { @@ -73,8 +70,7 @@ fn associated_item_def_ids(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &[DefId] { ) }) .copied() - })) - .chain(tcx.associated_type_for_effects(def_id)), + })), ) } _ => span_bug!(item.span, "associated_item_def_ids: not impl or trait"), @@ -171,134 +167,6 @@ fn associated_item_from_impl_item_ref(impl_item_ref: &hir::ImplItemRef) -> ty::A } } -/// Given an `def_id` of a trait or a trait impl: -/// -/// If `def_id` is a trait that has `#[const_trait]`, then it synthesizes -/// a new def id corresponding to a new associated type for the effects. -/// -/// If `def_id` is an impl, then synthesize the associated type according -/// to the constness of the impl. -fn associated_type_for_effects(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<DefId> { - // don't synthesize the associated type even if the user has written `const_trait` - // if the effects feature is disabled. - if !tcx.features().effects() { - return None; - } - let (feed, parent_did) = match tcx.def_kind(def_id) { - DefKind::Trait => { - let trait_def_id = def_id; - 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); - - let local_def_id = trait_assoc_ty.def_id(); - let def_id = local_def_id.to_def_id(); - - // Copy span of the attribute. - trait_assoc_ty.def_ident_span(Some(span)); - - trait_assoc_ty.associated_item(ty::AssocItem { - name: kw::Empty, - kind: ty::AssocKind::Type, - def_id, - trait_item_def_id: None, - container: ty::TraitContainer, - fn_has_self_parameter: false, - opt_rpitit_info: None, - is_effects_desugaring: true, - }); - - // No default type - trait_assoc_ty.defaultness(hir::Defaultness::Default { has_value: false }); - - trait_assoc_ty.is_type_alias_impl_trait(false); - - (trait_assoc_ty, trait_def_id) - } - DefKind::Impl { .. } => { - let impl_def_id = def_id; - 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 trait_assoc_id = tcx.associated_type_for_effects(trait_id)?; - - // FIXME(effects): span - let span = tcx.def_ident_span(def_id).unwrap(); - - let impl_assoc_ty = tcx.at(span).create_def(def_id, kw::Empty, DefKind::AssocTy); - - let local_def_id = impl_assoc_ty.def_id(); - let def_id = local_def_id.to_def_id(); - - impl_assoc_ty.def_ident_span(Some(span)); - - impl_assoc_ty.associated_item(ty::AssocItem { - name: kw::Empty, - kind: ty::AssocKind::Type, - def_id, - trait_item_def_id: Some(trait_assoc_id), - container: ty::ImplContainer, - fn_has_self_parameter: false, - opt_rpitit_info: None, - is_effects_desugaring: true, - }); - - // no default value. - impl_assoc_ty.defaultness(hir::Defaultness::Final); - - // set the type of the associated type! If this is a const impl, - // we set to Maybe, otherwise we set to `Runtime`. - let type_def_id = if tcx.is_const_trait_impl_raw(impl_def_id.to_def_id()) { - tcx.require_lang_item(hir::LangItem::EffectsMaybe, Some(span)) - } else { - tcx.require_lang_item(hir::LangItem::EffectsRuntime, Some(span)) - }; - // FIXME(effects): make impls use `Min` for their effect types - impl_assoc_ty.type_of(ty::EarlyBinder::bind(Ty::new_adt( - tcx, - tcx.adt_def(type_def_id), - ty::GenericArgs::empty(), - ))); - - (impl_assoc_ty, impl_def_id) - } - def_kind => 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: /// /// if `fn_def_id` is a function defined inside a trait, then it synthesizes @@ -494,7 +362,6 @@ fn associated_type_for_impl_trait_in_impl( param_def_id_to_index, has_self: false, has_late_bound_regions: trait_assoc_generics.has_late_bound_regions, - host_effect_index: parent_generics.host_effect_index, } }); diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index 28a81b1b062..aa499995bcb 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -150,6 +150,16 @@ fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> { }); } + // We extend the param-env of our item with the const conditions of the item, + // since we're allowed to assume `~const` bounds hold within the item itself. + if tcx.is_conditionally_const(def_id) { + predicates.extend( + tcx.const_conditions(def_id).instantiate_identity(tcx).into_iter().map( + |(trait_ref, _)| trait_ref.to_host_effect_clause(tcx, ty::HostPolarity::Maybe), + ), + ); + } + let local_did = def_id.as_local(); let unnormalized_env = diff --git a/compiler/rustc_type_ir/src/canonical.rs b/compiler/rustc_type_ir/src/canonical.rs index 07cb8b037ec..3fb7d87bcc4 100644 --- a/compiler/rustc_type_ir/src/canonical.rs +++ b/compiler/rustc_type_ir/src/canonical.rs @@ -108,7 +108,6 @@ impl<I: Interner> CanonicalVarInfo<I> { CanonicalVarKind::PlaceholderRegion(..) => false, CanonicalVarKind::Const(_) => true, CanonicalVarKind::PlaceholderConst(_) => false, - CanonicalVarKind::Effect => true, } } @@ -118,17 +117,15 @@ impl<I: Interner> CanonicalVarInfo<I> { CanonicalVarKind::Ty(_) | CanonicalVarKind::PlaceholderTy(_) | CanonicalVarKind::Const(_) - | CanonicalVarKind::PlaceholderConst(_) - | CanonicalVarKind::Effect => false, + | CanonicalVarKind::PlaceholderConst(_) => false, } } pub fn expect_placeholder_index(self) -> usize { match self.kind { - CanonicalVarKind::Ty(_) - | CanonicalVarKind::Region(_) - | CanonicalVarKind::Const(_) - | CanonicalVarKind::Effect => panic!("expected placeholder: {self:?}"), + CanonicalVarKind::Ty(_) | CanonicalVarKind::Region(_) | CanonicalVarKind::Const(_) => { + panic!("expected placeholder: {self:?}") + } CanonicalVarKind::PlaceholderRegion(placeholder) => placeholder.var().as_usize(), CanonicalVarKind::PlaceholderTy(placeholder) => placeholder.var().as_usize(), @@ -161,9 +158,6 @@ pub enum CanonicalVarKind<I: Interner> { /// Some kind of const inference variable. Const(UniverseIndex), - /// Effect variable `'?E`. - Effect, - /// A "placeholder" that represents "any const". PlaceholderConst(I::PlaceholderConst), } @@ -180,7 +174,6 @@ impl<I: Interner> CanonicalVarKind<I> { CanonicalVarKind::Ty(CanonicalTyVarKind::Float | CanonicalTyVarKind::Int) => { UniverseIndex::ROOT } - CanonicalVarKind::Effect => UniverseIndex::ROOT, } } @@ -205,8 +198,7 @@ impl<I: Interner> CanonicalVarKind<I> { CanonicalVarKind::PlaceholderConst(placeholder) => { CanonicalVarKind::PlaceholderConst(placeholder.with_updated_universe(ui)) } - CanonicalVarKind::Ty(CanonicalTyVarKind::Int | CanonicalTyVarKind::Float) - | CanonicalVarKind::Effect => { + CanonicalVarKind::Ty(CanonicalTyVarKind::Int | CanonicalTyVarKind::Float) => { assert_eq!(ui, UniverseIndex::ROOT); self } @@ -311,10 +303,6 @@ impl<I: Interner> CanonicalVarValues<I> { Region::new_anon_bound(cx, ty::INNERMOST, ty::BoundVar::from_usize(i)) .into() } - CanonicalVarKind::Effect => { - Const::new_anon_bound(cx, ty::INNERMOST, ty::BoundVar::from_usize(i)) - .into() - } CanonicalVarKind::Const(_) | CanonicalVarKind::PlaceholderConst(_) => { Const::new_anon_bound(cx, ty::INNERMOST, ty::BoundVar::from_usize(i)) .into() diff --git a/compiler/rustc_type_ir/src/const_kind.rs b/compiler/rustc_type_ir/src/const_kind.rs index 7a8c612057f..03dfe547ced 100644 --- a/compiler/rustc_type_ir/src/const_kind.rs +++ b/compiler/rustc_type_ir/src/const_kind.rs @@ -84,32 +84,12 @@ rustc_index::newtype_index! { pub struct ConstVid {} } -rustc_index::newtype_index! { - /// An **effect** **v**ariable **ID**. - /// - /// Handling effect infer variables happens separately from const infer variables - /// because we do not want to reuse any of the const infer machinery. If we try to - /// relate an effect variable with a normal one, we would ICE, which can catch bugs - /// where we are not correctly using the effect var for an effect param. Fallback - /// is also implemented on top of having separate effect and normal const variables. - #[encodable] - #[orderable] - #[debug_format = "?{}e"] - #[gate_rustc_only] - pub struct EffectVid {} -} - /// An inference variable for a const, for use in const generics. #[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)] #[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable))] pub enum InferConst { /// Infer the value of the const. Var(ConstVid), - /// Infer the value of the effect. - /// - /// For why this is separate from the `Var` variant above, see the - /// documentation on `EffectVid`. - EffectVar(EffectVid), /// A fresh const variable. See `infer::freshen` for more details. Fresh(u32), } @@ -118,7 +98,6 @@ impl fmt::Debug for InferConst { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { InferConst::Var(var) => write!(f, "{var:?}"), - InferConst::EffectVar(var) => write!(f, "{var:?}"), InferConst::Fresh(var) => write!(f, "Fresh({var:?})"), } } @@ -128,7 +107,7 @@ impl fmt::Debug for InferConst { impl<CTX> HashStable<CTX> for InferConst { fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) { match self { - InferConst::Var(_) | InferConst::EffectVar(_) => { + InferConst::Var(_) => { panic!("const variables should not be hashed: {self:?}") } InferConst::Fresh(i) => i.hash_stable(hcx, hasher), diff --git a/compiler/rustc_type_ir/src/effects.rs b/compiler/rustc_type_ir/src/effects.rs deleted file mode 100644 index ab43533dd86..00000000000 --- a/compiler/rustc_type_ir/src/effects.rs +++ /dev/null @@ -1,59 +0,0 @@ -use crate::Interner; -use crate::inherent::*; -use crate::lang_items::TraitSolverLangItem::{EffectsMaybe, EffectsNoRuntime, EffectsRuntime}; - -#[derive(Clone, Copy, PartialEq, Eq)] -pub enum EffectKind { - Maybe, - Runtime, - NoRuntime, -} - -impl EffectKind { - pub fn try_from_def_id<I: Interner>(cx: I, def_id: I::DefId) -> Option<EffectKind> { - if cx.is_lang_item(def_id, EffectsMaybe) { - Some(EffectKind::Maybe) - } else if cx.is_lang_item(def_id, EffectsRuntime) { - Some(EffectKind::Runtime) - } else if cx.is_lang_item(def_id, EffectsNoRuntime) { - Some(EffectKind::NoRuntime) - } else { - None - } - } - - pub fn to_def_id<I: Interner>(self, cx: I) -> I::DefId { - let lang_item = match self { - EffectKind::Maybe => EffectsMaybe, - EffectKind::NoRuntime => EffectsNoRuntime, - EffectKind::Runtime => EffectsRuntime, - }; - - cx.require_lang_item(lang_item) - } - - pub fn try_from_ty<I: Interner>(cx: I, ty: I::Ty) -> Option<EffectKind> { - if let crate::Adt(def, _) = ty.kind() { - Self::try_from_def_id(cx, def.def_id()) - } else { - None - } - } - - pub fn to_ty<I: Interner>(self, cx: I) -> I::Ty { - I::Ty::new_adt(cx, cx.adt_def(self.to_def_id(cx)), Default::default()) - } - - /// 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<Self> { - use EffectKind::*; - match (a, b) { - (Maybe, x) | (x, Maybe) => Some(x), - (Runtime, Runtime) => Some(Runtime), - (NoRuntime, NoRuntime) => Some(NoRuntime), - (Runtime, NoRuntime) | (NoRuntime, Runtime) => None, - } - } -} diff --git a/compiler/rustc_type_ir/src/elaborate.rs b/compiler/rustc_type_ir/src/elaborate.rs index dac45ff2aba..72d392ecd7b 100644 --- a/compiler/rustc_type_ir/src/elaborate.rs +++ b/compiler/rustc_type_ir/src/elaborate.rs @@ -4,7 +4,6 @@ use smallvec::smallvec; use crate::data_structures::HashSet; use crate::inherent::*; -use crate::lang_items::TraitSolverLangItem; use crate::outlives::{Component, push_outlives_components}; use crate::{self as ty, Interner, Upcast as _}; @@ -130,70 +129,6 @@ impl<I: Interner, O: Elaboratable<I>> Elaborator<I, O> { return; } - // HACK(effects): The following code is required to get implied bounds for effects associated - // types to work with super traits. - // - // Suppose `data` is a trait predicate with the form `<T as Tr>::Fx: EffectsCompat<somebool>` - // and we know that `trait Tr: ~const SuperTr`, we need to elaborate this predicate into - // `<T as SuperTr>::Fx: EffectsCompat<somebool>`. - // - // Since the semantics for elaborating bounds about effects is equivalent to elaborating - // bounds about super traits (elaborate `T: Tr` into `T: SuperTr`), we place effects elaboration - // next to super trait elaboration. - if cx.is_lang_item(data.def_id(), TraitSolverLangItem::EffectsCompat) - && matches!(self.mode, Filter::All) - { - // first, ensure that the predicate we've got looks like a `<T as Tr>::Fx: EffectsCompat<somebool>`. - if let ty::Alias(ty::AliasTyKind::Projection, alias_ty) = data.self_ty().kind() - { - // look for effects-level bounds that look like `<Self as Tr>::Fx: TyCompat<<Self as SuperTr>::Fx>` - // on the trait, which is proof to us that `Tr: ~const SuperTr`. We're looking for bounds on the - // associated trait, so we use `explicit_implied_predicates_of` since it gives us more than just - // `Self: SuperTr` bounds. - let bounds = cx.explicit_implied_predicates_of(cx.parent(alias_ty.def_id)); - - // instantiate the implied bounds, so we get `<T as Tr>::Fx` and not `<Self as Tr>::Fx`. - let elaborated = bounds.iter_instantiated(cx, alias_ty.args).filter_map( - |(clause, _)| { - let ty::ClauseKind::Trait(tycompat_bound) = - clause.kind().skip_binder() - else { - return None; - }; - if !cx.is_lang_item( - tycompat_bound.def_id(), - TraitSolverLangItem::EffectsTyCompat, - ) { - return None; - } - - // extract `<T as SuperTr>::Fx` from the `TyCompat` bound. - let supertrait_effects_ty = - tycompat_bound.trait_ref.args.type_at(1); - let ty::Alias(ty::AliasTyKind::Projection, supertrait_alias_ty) = - supertrait_effects_ty.kind() - else { - return None; - }; - - // The self types (`T`) must be equal for `<T as Tr>::Fx` and `<T as SuperTr>::Fx`. - if supertrait_alias_ty.self_ty() != alias_ty.self_ty() { - return None; - }; - - // replace the self type in the original bound `<T as Tr>::Fx: EffectsCompat<somebool>` - // to the effects type of the super trait. (`<T as SuperTr>::Fx`) - let elaborated_bound = data.with_self_ty(cx, supertrait_effects_ty); - Some( - elaboratable - .child(bound_clause.rebind(elaborated_bound).upcast(cx)), - ) - }, - ); - self.extend_deduped(elaborated); - } - } - let map_to_child_clause = |(index, (clause, span)): (usize, (I::Clause, I::Span))| { elaboratable.child_with_derived_cause( @@ -220,6 +155,16 @@ impl<I: Interner, O: Elaboratable<I>> Elaborator<I, O> { ), }; } + // `T: ~const Trait` implies `T: ~const Supertrait`. + ty::ClauseKind::HostEffect(data) => self.extend_deduped( + cx.implied_const_bounds(data.def_id()).iter_identity().map(|trait_ref| { + elaboratable.child( + trait_ref + .to_host_effect_clause(cx, data.host) + .instantiate_supertrait(cx, bound_clause.rebind(data.trait_ref)), + ) + }), + ), ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(ty_max, r_min)) => { // We know that `T: 'a` for some type `T`. We can // often elaborate this. For example, if we know that diff --git a/compiler/rustc_type_ir/src/infer_ctxt.rs b/compiler/rustc_type_ir/src/infer_ctxt.rs index b9f5cde653e..7c6a3c65ebf 100644 --- a/compiler/rustc_type_ir/src/infer_ctxt.rs +++ b/compiler/rustc_type_ir/src/infer_ctxt.rs @@ -38,10 +38,6 @@ pub trait InferCtxtLike: Sized { &self, vid: ty::ConstVid, ) -> <Self::Interner as Interner>::Const; - fn opportunistic_resolve_effect_var( - &self, - vid: ty::EffectVid, - ) -> <Self::Interner as Interner>::Const; fn opportunistic_resolve_lt_var( &self, vid: ty::RegionVid, @@ -71,7 +67,6 @@ pub trait InferCtxtLike: Sized { fn equate_int_vids_raw(&self, a: ty::IntVid, b: ty::IntVid); fn equate_float_vids_raw(&self, a: ty::FloatVid, b: ty::FloatVid); fn equate_const_vids_raw(&self, a: ty::ConstVid, b: ty::ConstVid); - fn equate_effect_vids_raw(&self, a: ty::EffectVid, b: ty::EffectVid); fn instantiate_ty_var_raw<R: PredicateEmittingRelation<Self>>( &self, @@ -83,11 +78,6 @@ pub trait InferCtxtLike: Sized { ) -> RelateResult<Self::Interner, ()>; fn instantiate_int_var_raw(&self, vid: ty::IntVid, value: ty::IntVarValue); fn instantiate_float_var_raw(&self, vid: ty::FloatVid, value: ty::FloatVarValue); - fn instantiate_effect_var_raw( - &self, - vid: ty::EffectVid, - value: <Self::Interner as Interner>::Const, - ); fn instantiate_const_var_raw<R: PredicateEmittingRelation<Self>>( &self, relation: &mut R, diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index 02ec29a7f3d..5af1aa2f8fa 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -468,6 +468,14 @@ pub trait Clause<I: Interner<Clause = Self>>: .transpose() } + fn as_host_effect_clause(self) -> Option<ty::Binder<I, ty::HostEffectPredicate<I>>> { + self.kind() + .map_bound( + |clause| if let ty::ClauseKind::HostEffect(t) = clause { Some(t) } else { None }, + ) + .transpose() + } + fn as_projection_clause(self) -> Option<ty::Binder<I, ty::ProjectionPredicate<I>>> { self.kind() .map_bound( diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index 4184e9e313f..6a8113b38b7 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -24,6 +24,7 @@ pub trait Interner: + IrPrint<ty::AliasTerm<Self>> + IrPrint<ty::TraitRef<Self>> + IrPrint<ty::TraitPredicate<Self>> + + IrPrint<ty::HostEffectPredicate<Self>> + IrPrint<ty::ExistentialTraitRef<Self>> + IrPrint<ty::ExistentialProjection<Self>> + IrPrint<ty::ProjectionPredicate<Self>> @@ -228,6 +229,16 @@ pub trait Interner: def_id: Self::DefId, ) -> ty::EarlyBinder<Self, impl IntoIterator<Item = (Self::Clause, Self::Span)>>; + fn is_const_impl(self, def_id: Self::DefId) -> bool; + fn const_conditions( + self, + def_id: Self::DefId, + ) -> ty::EarlyBinder<Self, impl IntoIterator<Item = ty::Binder<Self, ty::TraitRef<Self>>>>; + fn implied_const_bounds( + self, + def_id: Self::DefId, + ) -> ty::EarlyBinder<Self, impl IntoIterator<Item = ty::Binder<Self, ty::TraitRef<Self>>>>; + fn has_target_features(self, def_id: Self::DefId) -> bool; fn require_lang_item(self, lang_item: TraitSolverLangItem) -> Self::DefId; diff --git a/compiler/rustc_type_ir/src/ir_print.rs b/compiler/rustc_type_ir/src/ir_print.rs index d57d0816680..0c71f3a3df2 100644 --- a/compiler/rustc_type_ir/src/ir_print.rs +++ b/compiler/rustc_type_ir/src/ir_print.rs @@ -2,8 +2,8 @@ use std::fmt; use crate::{ AliasTerm, AliasTy, Binder, CoercePredicate, ExistentialProjection, ExistentialTraitRef, FnSig, - Interner, NormalizesTo, OutlivesPredicate, ProjectionPredicate, SubtypePredicate, - TraitPredicate, TraitRef, + HostEffectPredicate, Interner, NormalizesTo, OutlivesPredicate, ProjectionPredicate, + SubtypePredicate, TraitPredicate, TraitRef, }; pub trait IrPrint<T> { @@ -53,6 +53,7 @@ define_display_via_print!( NormalizesTo, SubtypePredicate, CoercePredicate, + HostEffectPredicate, AliasTy, AliasTerm, FnSig, diff --git a/compiler/rustc_type_ir/src/lang_items.rs b/compiler/rustc_type_ir/src/lang_items.rs index c680c844746..d6ca22a90a4 100644 --- a/compiler/rustc_type_ir/src/lang_items.rs +++ b/compiler/rustc_type_ir/src/lang_items.rs @@ -20,13 +20,6 @@ pub enum TraitSolverLangItem { Destruct, DiscriminantKind, DynMetadata, - EffectsCompat, - EffectsIntersection, - EffectsIntersectionOutput, - EffectsMaybe, - EffectsNoRuntime, - EffectsRuntime, - EffectsTyCompat, Fn, FnMut, FnOnce, diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index 9e6d1f424ba..e7ca24178cb 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -43,7 +43,6 @@ mod macros; mod binder; mod canonical; mod const_kind; -mod effects; mod flags; mod generic_arg; mod infer_ctxt; @@ -67,7 +66,6 @@ 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 infer_ctxt::*; diff --git a/compiler/rustc_type_ir/src/predicate.rs b/compiler/rustc_type_ir/src/predicate.rs index e8ce39be3e5..c3164550348 100644 --- a/compiler/rustc_type_ir/src/predicate.rs +++ b/compiler/rustc_type_ir/src/predicate.rs @@ -111,6 +111,13 @@ impl<I: Interner> ty::Binder<I, TraitRef<I>> { pub fn def_id(&self) -> I::DefId { self.skip_binder().def_id } + + pub fn to_host_effect_clause(self, cx: I, host: HostPolarity) -> I::Clause { + self.map_bound(|trait_ref| { + ty::ClauseKind::HostEffect(HostEffectPredicate { trait_ref, host }) + }) + .upcast(cx) + } } #[derive_where(Clone, Copy, Hash, PartialEq, Eq; I: Interner)] @@ -745,6 +752,64 @@ impl<I: Interner> fmt::Debug for NormalizesTo<I> { } } +#[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)] +#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] +#[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))] +pub struct HostEffectPredicate<I: Interner> { + pub trait_ref: ty::TraitRef<I>, + pub host: HostPolarity, +} + +impl<I: Interner> HostEffectPredicate<I> { + pub fn self_ty(self) -> I::Ty { + self.trait_ref.self_ty() + } + + pub fn with_self_ty(self, interner: I, self_ty: I::Ty) -> Self { + Self { trait_ref: self.trait_ref.with_self_ty(interner, self_ty), ..self } + } + + pub fn def_id(self) -> I::DefId { + self.trait_ref.def_id + } +} + +impl<I: Interner> ty::Binder<I, HostEffectPredicate<I>> { + pub fn def_id(self) -> I::DefId { + // Ok to skip binder since trait `DefId` does not care about regions. + self.skip_binder().def_id() + } + + pub fn self_ty(self) -> ty::Binder<I, I::Ty> { + self.map_bound(|trait_ref| trait_ref.self_ty()) + } + + #[inline] + pub fn host(self) -> HostPolarity { + self.skip_binder().host + } +} + +#[derive(Clone, Copy, Hash, PartialEq, Eq, Debug)] +#[derive(TypeVisitable_Generic, TypeFoldable_Generic)] +#[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))] +pub enum HostPolarity { + /// May be called in const environments if the callee is const. + Maybe, + /// Always allowed to be called in const environments. + Const, +} + +impl HostPolarity { + pub fn satisfies(self, goal: HostPolarity) -> bool { + match (self, goal) { + (HostPolarity::Const, HostPolarity::Const | HostPolarity::Maybe) => true, + (HostPolarity::Maybe, HostPolarity::Maybe) => true, + (HostPolarity::Maybe, HostPolarity::Const) => false, + } + } +} + /// Encodes that `a` must be a subtype of `b`. The `a_is_expected` flag indicates /// whether the `a` type is the type that we should label as "expected" when /// presenting user diagnostics. diff --git a/compiler/rustc_type_ir/src/predicate_kind.rs b/compiler/rustc_type_ir/src/predicate_kind.rs index 46202dbb0f2..21f4456abd1 100644 --- a/compiler/rustc_type_ir/src/predicate_kind.rs +++ b/compiler/rustc_type_ir/src/predicate_kind.rs @@ -37,6 +37,12 @@ pub enum ClauseKind<I: Interner> { /// Constant initializer must evaluate successfully. ConstEvaluatable(I::Const), + + /// Enforces the constness of the predicate we're calling. Like a projection + /// goal from a where clause, it's always going to be paired with a + /// corresponding trait clause; this just enforces the *constness* of that + /// implementation. + HostEffect(ty::HostEffectPredicate<I>), } #[derive_where(Clone, Copy, Hash, PartialEq, Eq; I: Interner)] @@ -110,6 +116,7 @@ impl<I: Interner> fmt::Debug for ClauseKind<I> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { ClauseKind::ConstArgHasType(ct, ty) => write!(f, "ConstArgHasType({ct:?}, {ty:?})"), + ClauseKind::HostEffect(data) => data.fmt(f), ClauseKind::Trait(a) => a.fmt(f), ClauseKind::RegionOutlives(pair) => pair.fmt(f), ClauseKind::TypeOutlives(pair) => pair.fmt(f), diff --git a/compiler/rustc_type_ir/src/relate/combine.rs b/compiler/rustc_type_ir/src/relate/combine.rs index 60a953801a4..17a3912730f 100644 --- a/compiler/rustc_type_ir/src/relate/combine.rs +++ b/compiler/rustc_type_ir/src/relate/combine.rs @@ -179,23 +179,9 @@ where Ok(a) } - ( - ty::ConstKind::Infer(ty::InferConst::EffectVar(a_vid)), - ty::ConstKind::Infer(ty::InferConst::EffectVar(b_vid)), - ) => { - infcx.equate_effect_vids_raw(a_vid, b_vid); - Ok(a) - } - // All other cases of inference with other variables are errors. - ( - ty::ConstKind::Infer(ty::InferConst::Var(_) | ty::InferConst::EffectVar(_)), - ty::ConstKind::Infer(_), - ) - | ( - ty::ConstKind::Infer(_), - ty::ConstKind::Infer(ty::InferConst::Var(_) | ty::InferConst::EffectVar(_)), - ) => { + (ty::ConstKind::Infer(ty::InferConst::Var(_)), ty::ConstKind::Infer(_)) + | (ty::ConstKind::Infer(_), ty::ConstKind::Infer(ty::InferConst::Var(_))) => { panic!( "tried to combine ConstKind::Infer/ConstKind::Infer(InferConst::Var): {a:?} and {b:?}" ) @@ -211,16 +197,6 @@ where Ok(a) } - (ty::ConstKind::Infer(ty::InferConst::EffectVar(vid)), _) => { - infcx.instantiate_effect_var_raw(vid, b); - Ok(b) - } - - (_, ty::ConstKind::Infer(ty::InferConst::EffectVar(vid))) => { - infcx.instantiate_effect_var_raw(vid, a); - Ok(a) - } - (ty::ConstKind::Unevaluated(..), _) | (_, ty::ConstKind::Unevaluated(..)) if infcx.cx().features().generic_const_exprs() || infcx.next_trait_solver() => { diff --git a/compiler/stable_mir/src/ty.rs b/compiler/stable_mir/src/ty.rs index 9e6fbc8ea0c..8db1258b65f 100644 --- a/compiler/stable_mir/src/ty.rs +++ b/compiler/stable_mir/src/ty.rs @@ -1393,7 +1393,6 @@ pub struct Generics { pub param_def_id_to_index: Vec<(GenericDef, u32)>, pub has_self: bool, pub has_late_bound_regions: Option<Span>, - pub host_effect_index: Option<usize>, } #[derive(Clone, Debug, Eq, PartialEq, Serialize)] |
