implement new effects desugaring

This commit is contained in:
Deadbeef 2024-06-14 12:16:15 +00:00
parent 99f77a2eda
commit 72e8244e64
50 changed files with 636 additions and 228 deletions

View File

@ -103,7 +103,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
ParamMode::Optional,
ParenthesizedGenericArgs::Err,
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
None,
// Method calls can't have bound modifiers
None,
));

View File

@ -56,7 +56,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);
let mut lctx = LoweringContext::new(self.tcx, self.resolver, self.ast_index);
lctx.with_hir_id_owner(owner, |lctx| f(lctx));
for (def_id, info) in lctx.children {
@ -190,6 +190,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
let (generics, (ty, body_id)) = self.lower_generics(
generics,
Const::No,
false,
id,
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|this| {
@ -221,7 +222,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
let itctx = ImplTraitContext::Universal;
let (generics, decl) =
this.lower_generics(generics, header.constness, id, itctx, |this| {
this.lower_generics(generics, header.constness, false, id, itctx, |this| {
this.lower_fn_decl(
decl,
id,
@ -265,6 +266,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
let (generics, ty) = self.lower_generics(
&generics,
Const::No,
false,
id,
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|this| match ty {
@ -293,6 +295,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
let (generics, variants) = self.lower_generics(
generics,
Const::No,
false,
id,
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|this| {
@ -307,6 +310,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
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),
@ -317,6 +321,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
let (generics, vdata) = self.lower_generics(
generics,
Const::No,
false,
id,
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|this| this.lower_variant_data(hir_id, vdata),
@ -348,12 +353,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
// parent lifetime.
let itctx = ImplTraitContext::Universal;
let (generics, (trait_ref, lowered_ty)) =
self.lower_generics(ast_generics, *constness, id, itctx, |this| {
self.lower_generics(ast_generics, Const::No, false, id, itctx, |this| {
let modifiers = TraitBoundModifiers {
constness: match *constness {
Const::Yes(span) => BoundConstness::Maybe(span),
Const::No => BoundConstness::Never,
},
constness: BoundConstness::Never,
asyncness: BoundAsyncness::Normal,
// we don't use this in bound lowering
polarity: BoundPolarity::Positive,
@ -389,6 +391,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
ImplPolarity::Negative(s) => ImplPolarity::Negative(self.lower_span(*s)),
};
hir::ItemKind::Impl(self.arena.alloc(hir::Impl {
constness: self.lower_constness(*constness),
safety: self.lower_safety(*safety, hir::Safety::Safe),
polarity,
defaultness,
@ -400,15 +403,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
}))
}
ItemKind::Trait(box Trait { is_auto, safety, generics, bounds, items }) => {
// FIXME(const_trait_impl, effects, fee1-dead) this should be simplified if possible
let constness = attrs
.unwrap_or(&[])
.iter()
.find(|x| x.has_name(sym::const_trait))
.map_or(Const::No, |x| Const::Yes(x.span));
let (generics, (safety, items, bounds)) = self.lower_generics(
generics,
constness,
Const::No,
false,
id,
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|this| {
@ -429,6 +427,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
let (generics, bounds) = self.lower_generics(
generics,
Const::No,
false,
id,
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|this| {
@ -609,30 +608,45 @@ impl<'hir> LoweringContext<'_, 'hir> {
// This is used to track which lifetimes have already been defined,
// and which need to be replicated when lowering an async fn.
let generics = match parent_hir.node().expect_item().kind {
let parent_item = parent_hir.node().expect_item();
let constness = match parent_item.kind {
hir::ItemKind::Impl(impl_) => {
self.is_in_trait_impl = impl_.of_trait.is_some();
&impl_.generics
// 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,
}
hir::ItemKind::Trait(_, _, generics, _, _) => generics,
} else {
self.tcx
.get_attr(def_id, sym::const_trait)
.map_or(Const::No, |attr| Const::Yes(attr.span))
}
} 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)),
kind => {
span_bug!(item.span, "assoc item has unexpected kind of parent: {}", kind.descr())
}
};
if self.tcx.features().effects {
self.host_param_id = generics
.params
.iter()
.find(|param| {
matches!(param.kind, hir::GenericParamKind::Const { is_host_effect: true, .. })
})
.map(|param| param.def_id);
}
match ctxt {
AssocCtxt::Trait => hir::OwnerNode::TraitItem(self.lower_trait_item(item)),
AssocCtxt::Impl => hir::OwnerNode::ImplItem(self.lower_impl_item(item)),
AssocCtxt::Trait => hir::OwnerNode::TraitItem(self.lower_trait_item(item, constness)),
AssocCtxt::Impl => hir::OwnerNode::ImplItem(self.lower_impl_item(item, constness)),
}
}
@ -648,7 +662,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
let fdec = &sig.decl;
let itctx = ImplTraitContext::Universal;
let (generics, (fn_dec, fn_args)) =
self.lower_generics(generics, Const::No, i.id, itctx, |this| {
self.lower_generics(generics, Const::No, false, i.id, itctx, |this| {
(
// Disallow `impl Trait` in foreign items.
this.lower_fn_decl(
@ -765,7 +779,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
}
}
fn lower_trait_item(&mut self, i: &AssocItem) -> &'hir hir::TraitItem<'hir> {
fn lower_trait_item(
&mut self,
i: &AssocItem,
trait_constness: Const,
) -> &'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();
@ -775,6 +793,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
let (generics, kind) = self.lower_generics(
generics,
Const::No,
false,
i.id,
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|this| {
@ -795,6 +814,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
i.id,
FnDeclKind::Trait,
sig.header.coroutine_kind,
trait_constness,
);
(generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Required(names)), false)
}
@ -813,6 +833,7 @@ 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)
}
@ -822,6 +843,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
let (generics, kind) = self.lower_generics(
&generics,
Const::No,
false,
i.id,
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|this| {
@ -894,7 +916,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
self.expr(span, hir::ExprKind::Err(guar))
}
fn lower_impl_item(&mut self, i: &AssocItem) -> &'hir hir::ImplItem<'hir> {
fn lower_impl_item(
&mut self,
i: &AssocItem,
constness_of_trait: Const,
) -> &'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);
@ -905,6 +931,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
AssocItemKind::Const(box ConstItem { generics, ty, expr, .. }) => self.lower_generics(
generics,
Const::No,
false,
i.id,
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|this| {
@ -930,6 +957,7 @@ 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))
@ -940,6 +968,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
self.lower_generics(
&generics,
Const::No,
false,
i.id,
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|this| match ty {
@ -1352,13 +1381,16 @@ 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);
// 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 { Const::No };
let constness =
if kind == FnDeclKind::Inherent { sig.header.constness } else { parent_constness };
let itctx = ImplTraitContext::Universal;
let (generics, decl) = self.lower_generics(generics, constness, id, itctx, |this| {
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)
});
(generics, hir::FnSig { header, decl, span: self.lower_span(sig.span) })
@ -1436,6 +1468,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
&mut self,
generics: &Generics,
constness: Const,
force_append_constness: bool,
parent_node_id: NodeId,
itctx: ImplTraitContext,
f: impl FnOnce(&mut Self) -> T,
@ -1496,7 +1529,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
// 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
&& self.tcx.features().effects
// 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();
@ -1609,6 +1644,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
}),
)),
)),
// FIXME(effects) we might not need a default.
default: Some(self.arena.alloc(hir::AnonConst {
def_id: anon_const,
hir_id: const_id,
@ -1616,6 +1652,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
span,
})),
is_host_effect: true,
synthetic: true,
},
colon_span: None,
pure_wrt_drop: false,

View File

@ -142,14 +142,19 @@ struct LoweringContext<'a, 'hir> {
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) -> Self {
fn new(
tcx: TyCtxt<'hir>,
resolver: &'a mut ResolverAstLowering,
ast_index: &'a IndexSlice<LocalDefId, AstOwner<'a>>,
) -> Self {
Self {
// Pseudo-globals.
tcx,
resolver: resolver,
resolver,
arena: tcx.hir_arena,
// HirId handling.
@ -185,6 +190,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
allow_async_iterator: [sym::gen_future, sym::async_iterator].into(),
generics_def_id_map: Default::default(),
host_param_id: None,
ast_index,
}
}
@ -2135,7 +2141,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
param: &GenericParam,
source: hir::GenericParamSource,
) -> hir::GenericParam<'hir> {
let (name, kind) = self.lower_generic_param_kind(param, source);
let (name, kind) = self.lower_generic_param_kind(
param,
source,
attr::contains_name(&param.attrs, sym::rustc_runtime),
);
let hir_id = self.lower_node_id(param.id);
self.lower_attrs(hir_id, &param.attrs);
@ -2155,6 +2165,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
&mut self,
param: &GenericParam,
source: hir::GenericParamSource,
is_host_effect: bool,
) -> (hir::ParamName, hir::GenericParamKind<'hir>) {
match &param.kind {
GenericParamKind::Lifetime => {
@ -2220,7 +2231,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
(
hir::ParamName::Plain(self.lower_ident(param.ident)),
hir::GenericParamKind::Const { ty, default, is_host_effect: false },
hir::GenericParamKind::Const { ty, default, is_host_effect, synthetic: false },
)
}
}
@ -2607,78 +2618,6 @@ struct GenericArgsCtor<'hir> {
}
impl<'hir> GenericArgsCtor<'hir> {
fn push_constness(
&mut self,
lcx: &mut LoweringContext<'_, 'hir>,
constness: ast::BoundConstness,
) {
if !lcx.tcx.features().effects {
return;
}
let (span, body) = match constness {
BoundConstness::Never => return,
BoundConstness::Always(span) => {
let span = lcx.lower_span(span);
let body = hir::ExprKind::Lit(
lcx.arena.alloc(hir::Lit { node: LitKind::Bool(false), span }),
);
(span, body)
}
BoundConstness::Maybe(span) => {
let span = lcx.lower_span(span);
let Some(host_param_id) = lcx.host_param_id else {
lcx.dcx().span_delayed_bug(
span,
"no host param id for call in const yet no errors reported",
);
return;
};
let hir_id = lcx.next_id();
let res = Res::Def(DefKind::ConstParam, host_param_id.to_def_id());
let body = hir::ExprKind::Path(hir::QPath::Resolved(
None,
lcx.arena.alloc(hir::Path {
span,
res,
segments: arena_vec![
lcx;
hir::PathSegment::new(
Ident { name: sym::host, span },
hir_id,
res
)
],
}),
));
(span, body)
}
};
let body = lcx.lower_body(|lcx| (&[], lcx.expr(span, body)));
let id = lcx.next_node_id();
let hir_id = lcx.next_id();
let def_id = lcx.create_def(
lcx.current_hir_id_owner.def_id,
id,
kw::Empty,
DefKind::AnonConst,
span,
);
lcx.children.push((def_id, hir::MaybeOwner::NonOwner(hir_id)));
self.args.push(hir::GenericArg::Const(hir::ConstArg {
value: lcx.arena.alloc(hir::AnonConst { def_id, hir_id, body, span }),
is_desugared_from_effects: true,
}))
}
fn is_empty(&self) -> bool {
self.args.is_empty()
&& self.constraints.is_empty()

View File

@ -107,8 +107,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
param_mode,
parenthesized_generic_args,
itctx,
// if this is the last segment, add constness to the trait path
if i == proj_start - 1 { modifiers.map(|m| m.constness) } else { None },
bound_modifier_allowed_features.clone(),
)
},
@ -165,7 +163,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
ParenthesizedGenericArgs::Err,
itctx,
None,
None,
));
let qpath = hir::QPath::TypeRelative(ty, hir_segment);
@ -208,7 +205,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
ParenthesizedGenericArgs::Err,
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
None,
None,
)
})),
span: self.lower_span(p.span),
@ -222,7 +218,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
param_mode: ParamMode,
parenthesized_generic_args: ParenthesizedGenericArgs,
itctx: ImplTraitContext,
constness: Option<ast::BoundConstness>,
// Additional features ungated with a bound modifier like `async`.
// This is passed down to the implicit associated type binding in
// parenthesized bounds.
@ -289,10 +284,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
)
};
if let Some(constness) = constness {
generic_args.push_constness(self, constness);
}
let has_lifetimes =
generic_args.args.iter().any(|arg| matches!(arg, GenericArg::Lifetime(_)));

View File

@ -42,10 +42,7 @@ fn constness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::Constness {
| hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Const(..), .. }) => {
hir::Constness::Const
}
hir::Node::Item(hir::Item { kind: hir::ItemKind::Impl(_), .. }) => tcx
.generics_of(def_id)
.host_effect_index
.map_or(hir::Constness::NotConst, |_| hir::Constness::Const),
hir::Node::Item(hir::Item { kind: hir::ItemKind::Impl(impl_), .. }) => impl_.constness,
hir::Node::ForeignItem(hir::ForeignItem { kind: hir::ForeignItemKind::Fn(..), .. }) => {
// Intrinsics use `rustc_const_{un,}stable` attributes to indicate constness. All other
// foreign items cannot be evaluated at compile-time.

View File

@ -833,6 +833,10 @@ 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:

View File

@ -526,6 +526,7 @@ pub enum GenericParamKind<'hir> {
/// Optional default value for the const generic param
default: Option<&'hir AnonConst>,
is_host_effect: bool,
synthetic: bool,
},
}
@ -3364,6 +3365,7 @@ pub enum ItemKind<'hir> {
/// Refer to [`ImplItem`] for an associated item within an impl block.
#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub struct Impl<'hir> {
pub constness: Constness,
pub safety: Safety,
pub polarity: ImplPolarity,
pub defaultness: Defaultness,

View File

@ -543,6 +543,7 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V::
try_visit!(visitor.visit_enum_def(enum_definition, item.hir_id()));
}
ItemKind::Impl(Impl {
constness: _,
safety: _,
defaultness: _,
polarity: _,
@ -915,7 +916,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: _ } => {
GenericParamKind::Const { ref ty, ref default, is_host_effect: _, synthetic: _ } => {
try_visit!(visitor.visit_ty(ty));
if let Some(ref default) = default {
try_visit!(visitor.visit_const_param_default(param.hir_id, default));

View File

@ -393,6 +393,14 @@ 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;
EffectsMin, sym::EffectsMin, effects_min, Target::Trait, GenericRequirement::None;
EffectsMinOutput, sym::EffectsMinOutput, effects_min_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 {

View File

@ -1,9 +1,13 @@
//! Bounds are restrictions applied to some types after they've been lowered from the HIR to the
//! [`rustc_middle::ty`] form.
use rustc_data_structures::fx::FxIndexMap;
use rustc_hir::def::DefKind;
use rustc_hir::LangItem;
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 rustc_span::{sym, Span};
/// Collects together a list of type bounds. These lists of bounds occur in many places
/// in Rust's syntax:
@ -24,6 +28,7 @@ use rustc_span::Span;
#[derive(Default, PartialEq, Eq, Clone, Debug)]
pub struct Bounds<'tcx> {
clauses: Vec<(ty::Clause<'tcx>, Span)>,
effects_min_tys: FxIndexMap<Ty<'tcx>, Span>,
}
impl<'tcx> Bounds<'tcx> {
@ -40,12 +45,14 @@ impl<'tcx> Bounds<'tcx> {
pub fn push_trait_bound(
&mut self,
tcx: TyCtxt<'tcx>,
trait_ref: ty::PolyTraitRef<'tcx>,
defining_def_id: DefId,
bound_trait_ref: ty::PolyTraitRef<'tcx>,
span: Span,
polarity: ty::PredicatePolarity,
constness: ty::BoundConstness,
) {
let clause = (
trait_ref
bound_trait_ref
.map_bound(|trait_ref| {
ty::ClauseKind::Trait(ty::TraitPredicate { trait_ref, polarity })
})
@ -53,11 +60,88 @@ impl<'tcx> Bounds<'tcx> {
span,
);
// FIXME(-Znext-solver): We can likely remove this hack once the new trait solver lands.
if tcx.is_lang_item(trait_ref.def_id(), LangItem::Sized) {
if tcx.is_lang_item(bound_trait_ref.def_id(), LangItem::Sized) {
self.clauses.insert(0, clause);
} else {
self.clauses.push(clause);
}
// 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.
if let Some(compat_val) = match (tcx.def_kind(defining_def_id), constness) {
// TODO: do we need `T: const Trait` anymore?
(_, ty::BoundConstness::Const) => Some(tcx.consts.false_),
// body owners that can have trait bounds
(DefKind::Const | DefKind::Fn | DefKind::AssocFn, ty::BoundConstness::ConstIfConst) => {
Some(tcx.expected_host_effect_param_for_body(defining_def_id))
}
(_, ty::BoundConstness::NotConst) => {
tcx.has_attr(bound_trait_ref.def_id(), sym::const_trait).then_some(tcx.consts.true_)
}
(
DefKind::Trait | DefKind::Impl { of_trait: true },
ty::BoundConstness::ConstIfConst,
) => {
// this is either a where clause on an impl/trait header or on a trait.
// 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));
// Replace the binder with dummy types/lifetimes. This should work for any
// binder as long as they don't have any bounds e.g. `for<T: Trait>`.
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, ty::BoundConstness::ConstIfConst) => {
// TODO write the actual impl
return;
}
// probably illegal in this position.
(_, 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 fn push_projection_bound(
@ -79,7 +163,15 @@ impl<'tcx> Bounds<'tcx> {
self.clauses.insert(0, (trait_ref.upcast(tcx), span));
}
pub fn clauses(&self) -> impl Iterator<Item = (ty::Clause<'tcx>, Span)> + '_ {
pub fn clauses(
&self,
// TODO remove tcx
_tcx: TyCtxt<'tcx>,
) -> impl Iterator<Item = (ty::Clause<'tcx>, Span)> + '_ {
self.clauses.iter().cloned()
}
pub fn effects_min_tys(&self) -> impl Iterator<Item = Ty<'tcx>> + '_ {
self.effects_min_tys.keys().copied()
}
}

View File

@ -879,7 +879,7 @@ pub(super) fn check_specialization_validity<'tcx>(
let result = opt_result.unwrap_or(Ok(()));
if let Err(parent_impl) = result {
if !tcx.is_impl_trait_in_trait(impl_item) {
if !tcx.is_impl_trait_in_trait(impl_item) && !tcx.is_effects_desugared_assoc_ty(impl_item) {
report_forbidden_specialization(tcx, impl_item, parent_impl);
} else {
tcx.dcx().delayed_bug(format!("parent item: {parent_impl:?} not marked as default"));

View File

@ -1985,10 +1985,10 @@ pub(super) fn check_type_bounds<'tcx>(
let infcx = tcx.infer_ctxt().build();
let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
// A synthetic impl Trait for RPITIT desugaring has no HIR, which we currently use to get the
// span for an impl's associated type. Instead, for these, use the def_span for the synthesized
// associated type.
let impl_ty_span = if impl_ty.is_impl_trait_in_trait() {
// A synthetic impl Trait for RPITIT desugaring or assoc type for effects desugaring has no HIR,
// which we currently use to get the span for an impl's associated type. Instead, for these,
// use the def_span for the synthesized associated type.
let impl_ty_span = if impl_ty.is_impl_trait_in_trait() || impl_ty.is_effects_desugaring {
tcx.def_span(impl_ty_def_id)
} else {
match tcx.hir_node_by_def_id(impl_ty_def_id) {

View File

@ -913,7 +913,12 @@ 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: _ } => {
hir::GenericParamKind::Const {
ty: hir_ty,
default: _,
is_host_effect: _,
synthetic: _,
} => {
let ty = tcx.type_of(param.def_id).instantiate_identity();
if tcx.features().adt_const_params {

View File

@ -1638,42 +1638,17 @@ fn impl_trait_header(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<ty::ImplTrai
let icx = ItemCtxt::new(tcx, def_id);
let item = tcx.hir().expect_item(def_id);
let impl_ = item.expect_impl();
impl_
.of_trait
.as_ref()
.map(|hir_trait_ref| {
let self_ty = tcx.type_of(def_id).instantiate_identity();
impl_.of_trait.as_ref().map(|ast_trait_ref| {
let selfty = tcx.type_of(def_id).instantiate_identity();
check_impl_constness(tcx, tcx.is_const_trait_impl_raw(def_id.to_def_id()), ast_trait_ref);
let trait_ref = icx.lowerer().lower_impl_trait_ref(ast_trait_ref, selfty);
let trait_ref = if let Some(ErrorGuaranteed { .. }) = check_impl_constness(
tcx,
tcx.is_const_trait_impl_raw(def_id.to_def_id()),
hir_trait_ref,
) {
// we have a const impl, but for a trait without `#[const_trait]`, so
// without the host param. If we continue with the HIR trait ref, we get
// ICEs for generic arg count mismatch. We do a little HIR editing to
// make HIR ty lowering happy.
let mut path_segments = hir_trait_ref.path.segments.to_vec();
let last_segment = path_segments.len() - 1;
let mut args = *path_segments[last_segment].args();
let last_arg = args.args.len() - 1;
assert!(matches!(args.args[last_arg], hir::GenericArg::Const(anon_const) if anon_const.is_desugared_from_effects));
args.args = &args.args[..args.args.len() - 1];
path_segments[last_segment].args = Some(tcx.hir_arena.alloc(args));
let path = hir::Path {
span: hir_trait_ref.path.span,
res: hir_trait_ref.path.res,
segments: tcx.hir_arena.alloc_slice(&path_segments),
};
let trait_ref = tcx.hir_arena.alloc(hir::TraitRef { path: tcx.hir_arena.alloc(path), hir_ref_id: hir_trait_ref.hir_ref_id });
icx.lowerer().lower_impl_trait_ref(trait_ref, self_ty)
} else {
icx.lowerer().lower_impl_trait_ref(hir_trait_ref, self_ty)
};
ty::ImplTraitHeader {
trait_ref: ty::EarlyBinder::bind(trait_ref),
safety: impl_.safety,
polarity: polarity_of_impl(tcx, def_id, impl_, item.span)
polarity: polarity_of_impl(tcx, def_id, impl_, item.span),
}
})
}

View File

@ -354,7 +354,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
kind,
})
}
GenericParamKind::Const { ty: _, default, is_host_effect } => {
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.
@ -388,6 +388,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
kind: ty::GenericParamDefKind::Const {
has_default: default.is_some(),
is_host_effect,
synthetic,
},
})
}
@ -541,7 +542,8 @@ struct AnonConstInParamTyDetector {
impl<'v> Visitor<'v> for AnonConstInParamTyDetector {
fn visit_generic_param(&mut self, p: &'v hir::GenericParam<'v>) {
if let GenericParamKind::Const { ty, default: _, is_host_effect: _ } = p.kind {
if let GenericParamKind::Const { ty, default: _, is_host_effect: _, synthetic: _ } = p.kind
{
let prev = self.in_param_ty;
self.in_param_ty = true;
self.visit_ty(ty);

View File

@ -46,7 +46,7 @@ fn associated_type_bounds<'tcx>(
}
});
let all_bounds = tcx.arena.alloc_from_iter(bounds.clauses().chain(bounds_from_parent));
let all_bounds = tcx.arena.alloc_from_iter(bounds.clauses(tcx).chain(bounds_from_parent));
debug!(
"associated_type_bounds({}) = {:?}",
tcx.def_path_str(assoc_item_def_id.to_def_id()),
@ -75,7 +75,7 @@ fn opaque_type_bounds<'tcx>(
icx.lowerer().add_sized_bound(&mut bounds, item_ty, hir_bounds, None, span);
debug!(?bounds);
tcx.arena.alloc_from_iter(bounds.clauses())
tcx.arena.alloc_from_iter(bounds.clauses(tcx))
})
}

View File

@ -57,6 +57,7 @@ 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; // to override hir::Ty
match tcx.opt_rpitit_info(def_id.to_def_id()) {
Some(ImplTraitInTraitData::Trait { fn_def_id, .. }) => {
@ -84,6 +85,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
return ty::GenericPredicates {
parent: Some(tcx.parent(def_id.to_def_id())),
predicates: tcx.arena.alloc_from_iter(predicates),
effects_min_tys: ty::List::empty(),
};
}
@ -105,12 +107,43 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
return ty::GenericPredicates {
parent: Some(impl_def_id),
predicates: tcx.arena.alloc_from_iter(impl_predicates),
effects_min_tys: ty::List::empty(),
};
}
None => {}
}
if tcx.is_effects_desugared_assoc_ty(def_id.to_def_id()) {
let mut predicates = Vec::new();
// Inherit predicates of parent (impl or trait)
let parent = tcx.local_parent(def_id);
let identity_args = ty::GenericArgs::identity_for_item(tcx, def_id);
let preds = tcx.explicit_predicates_of(parent);
predicates.extend(preds.instantiate_own(tcx, identity_args));
if let ty::AssocItemContainer::TraitContainer = tcx.associated_item(def_id).container {
// for traits, emit `type Effects: TyCompat<<(T1::Effects, ..) as Min>::Output>`
// TODO do the same for impls
let tup = Ty::new(tcx, ty::Tuple(preds.effects_min_tys));
// TODO span
let span = tcx.def_span(def_id);
let assoc = tcx.require_lang_item(LangItem::EffectsMinOutput, Some(span));
let proj = Ty::new_projection(tcx, assoc, [tup]);
// TODO this is bad
let self_proj = Ty::new_projection(tcx, def_id.to_def_id(), identity_args);
let trait_ = tcx.require_lang_item(LangItem::EffectsTyCompat, Some(span));
let trait_ref = ty::TraitRef::new(tcx, trait_, [self_proj, proj]);
predicates.push((ty::Binder::dummy(trait_ref).upcast(tcx), span));
}
return ty::GenericPredicates {
parent: Some(parent.to_def_id()),
predicates: tcx.arena.alloc_from_iter(predicates),
effects_min_tys: ty::List::empty(),
};
}
let hir_id = tcx.local_def_id_to_hir_id(def_id);
let node = tcx.hir_node(hir_id);
@ -124,6 +157,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
// We use an `IndexSet` to preserve order of insertion.
// Preserving the order of insertion is important here so as not to break UI tests.
let mut predicates: FxIndexSet<(ty::Clause<'_>, Span)> = FxIndexSet::default();
let mut effects_min_tys = Vec::new();
let hir_generics = node.generics().unwrap_or(NO_GENERICS);
if let Node::Item(item) = node {
@ -150,11 +184,13 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
// on a trait we must also consider the bounds that follow the trait's name,
// like `trait Foo: A + B + C`.
if let Some(self_bounds) = is_trait {
predicates.extend(
icx.lowerer()
.lower_mono_bounds(tcx.types.self_param, self_bounds, PredicateFilter::All)
.clauses(),
let bounds = icx.lowerer().lower_mono_bounds(
tcx.types.self_param,
self_bounds,
PredicateFilter::All,
);
predicates.extend(bounds.clauses(tcx));
effects_min_tys.extend(bounds.effects_min_tys());
}
// In default impls, we can assume that the self type implements
@ -187,7 +223,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
param.span,
);
trace!(?bounds);
predicates.extend(bounds.clauses());
predicates.extend(bounds.clauses(tcx));
trace!(?predicates);
}
hir::GenericParamKind::Const { .. } => {
@ -238,7 +274,8 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
bound_vars,
OnlySelfBounds(false),
);
predicates.extend(bounds.clauses());
predicates.extend(bounds.clauses(tcx));
effects_min_tys.extend(bounds.effects_min_tys());
}
hir::WherePredicate::RegionPredicate(region_pred) => {
@ -297,7 +334,8 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
// and the duplicated parameter, to ensure that they do not get out of sync.
if let Node::Item(&Item { kind: ItemKind::OpaqueTy(..), .. }) = node {
let opaque_ty_node = tcx.parent_hir_node(hir_id);
let Node::Ty(&Ty { kind: TyKind::OpaqueDef(_, lifetimes, _), .. }) = opaque_ty_node else {
let Node::Ty(&hir::Ty { kind: TyKind::OpaqueDef(_, lifetimes, _), .. }) = opaque_ty_node
else {
bug!("unexpected {opaque_ty_node:?}")
};
debug!(?lifetimes);
@ -309,6 +347,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
ty::GenericPredicates {
parent: generics.parent,
predicates: tcx.arena.alloc_from_iter(predicates),
effects_min_tys: tcx.mk_type_list(&effects_min_tys),
}
}
@ -459,6 +498,7 @@ pub(super) fn explicit_predicates_of<'tcx>(
ty::GenericPredicates {
parent: predicates_and_bounds.parent,
predicates: tcx.arena.alloc_slice(&predicates),
effects_min_tys: predicates_and_bounds.effects_min_tys,
}
}
} else {
@ -510,6 +550,7 @@ pub(super) fn explicit_predicates_of<'tcx>(
return GenericPredicates {
parent: parent_preds.parent,
predicates: { tcx.arena.alloc_from_iter(filtered_predicates) },
effects_min_tys: parent_preds.effects_min_tys,
};
}
gather_explicit_predicates_of(tcx, def_id)
@ -587,7 +628,7 @@ pub(super) fn implied_predicates_with_filter(
// Combine the two lists to form the complete set of superbounds:
let implied_bounds =
&*tcx.arena.alloc_from_iter(superbounds.clauses().chain(where_bounds_that_match));
&*tcx.arena.alloc_from_iter(superbounds.clauses(tcx).chain(where_bounds_that_match));
debug!(?implied_bounds);
// Now require that immediate supertraits are lowered, which will, in
@ -618,7 +659,11 @@ pub(super) fn implied_predicates_with_filter(
_ => {}
}
ty::GenericPredicates { parent: None, predicates: implied_bounds }
ty::GenericPredicates {
parent: None,
predicates: implied_bounds,
effects_min_tys: ty::List::empty(),
}
}
/// Returns the predicates defined on `item_def_id` of the form
@ -744,7 +789,7 @@ impl<'tcx> ItemCtxt<'tcx> {
);
}
bounds.clauses().collect()
bounds.clauses(self.tcx).collect()
}
#[instrument(level = "trace", skip(self))]

View File

@ -951,7 +951,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
self.visit_ty(ty);
}
}
GenericParamKind::Const { ty, default, is_host_effect: _ } => {
GenericParamKind::Const { ty, default, .. } => {
self.visit_ty(ty);
if let Some(default) = default {
self.visit_body(self.tcx.hir().body(default.body));

View File

@ -256,6 +256,7 @@ pub fn lower_generic_args<'tcx: 'a, 'a>(
| GenericParamDefKind::Lifetime,
_,
) => {
// TODO: this should be removed
// SPECIAL CASE FOR DESUGARED EFFECT PARAMS
// This comes from the following example:
//
@ -445,7 +446,7 @@ pub(crate) fn check_generic_arg_count(
.own_params
.iter()
.filter(|param| {
matches!(param.kind, ty::GenericParamDefKind::Const { is_host_effect: true, .. })
matches!(param.kind, ty::GenericParamDefKind::Const { synthetic: true, .. })
})
.count();
let named_const_param_count = param_counts.consts - synth_const_param_count;

View File

@ -698,7 +698,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
);
debug!(?poly_trait_ref);
bounds.push_trait_bound(tcx, poly_trait_ref, span, polarity);
bounds.push_trait_bound(
tcx,
self.item_def_id().to_def_id(),
poly_trait_ref,
span,
polarity,
constness,
);
let mut dup_constraints = FxIndexMap::default();
for constraint in trait_segment.args().constraints {

View File

@ -59,7 +59,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let mut trait_bounds = vec![];
let mut projection_bounds = vec![];
for (pred, span) in bounds.clauses() {
for (pred, span) in bounds.clauses(tcx) {
let bound_pred = pred.kind();
match bound_pred.skip_binder() {
ty::ClauseKind::Trait(trait_pred) => {
@ -133,7 +133,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
tcx.associated_items(pred.def_id())
.in_definition_order()
.filter(|item| item.kind == ty::AssocKind::Type)
.filter(|item| !item.is_impl_trait_in_trait())
.filter(|item| {
!item.is_impl_trait_in_trait() && !item.is_effects_desugaring
})
.map(|item| item.def_id),
);
}

View File

@ -585,6 +585,7 @@ impl<'a> State<'a> {
self.print_struct(struct_def, generics, item.ident.name, item.span, true);
}
hir::ItemKind::Impl(&hir::Impl {
constness,
safety,
polarity,
defaultness,
@ -599,6 +600,10 @@ impl<'a> State<'a> {
self.print_safety(safety);
self.word_nbsp("impl");
if let hir::Constness::Const = constness {
self.word_nbsp("const");
}
if !generics.params.is_empty() {
self.print_generic_params(generics.params);
self.space();
@ -2144,7 +2149,7 @@ impl<'a> State<'a> {
self.print_type(default);
}
}
GenericParamKind::Const { ty, ref default, is_host_effect: _ } => {
GenericParamKind::Const { ty, ref default, is_host_effect: _, synthetic: _ } => {
self.word_space(":");
self.print_type(ty);
if let Some(default) = default {

View File

@ -1304,7 +1304,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.fcx.ty_infer(Some(param), inf.span).into()
}
(
&GenericParamDefKind::Const { has_default, is_host_effect },
&GenericParamDefKind::Const { has_default, is_host_effect, .. },
GenericArg::Infer(inf),
) => {
if has_default && is_host_effect {
@ -1346,7 +1346,7 @@ 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, is_host_effect, .. } => {
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`

View File

@ -274,6 +274,7 @@ impl<'tcx> HirTyLowerer<'tcx> for FnCtxt<'_, 'tcx> {
}
}),
),
effects_min_tys: ty::List::empty(),
}
}

View File

@ -21,7 +21,7 @@ use rustc_middle::ty::{self, GenericParamDefKind, Ty, TypeVisitableExt};
use rustc_middle::ty::{GenericArgs, GenericArgsRef};
use rustc_middle::{bug, span_bug};
use rustc_span::symbol::Ident;
use rustc_span::Span;
use rustc_span::{sym, Span};
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
use rustc_trait_selection::traits::{self, NormalizeExt};
@ -356,6 +356,17 @@ 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.has_attr(trait_def_id, sym::const_trait) {
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)
}
@ -393,6 +404,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
debug!("lookup_in_trait_adjusted: method_item={:?}", method_item);
let mut obligations = vec![];
// TODO there is something wrong here because now methods for binops may get `const host: bool`
// Instantiate late-bound regions and instantiate the trait
// parameters into the method type to get the actual method type.
//

View File

@ -1279,6 +1279,7 @@ impl<'tcx> Pick<'tcx> {
trait_item_def_id: _,
fn_has_self_parameter: _,
opt_rpitit_info: _,
is_effects_desugaring: _,
},
kind: _,
import_ids: _,

View File

@ -1348,7 +1348,9 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
}
fn get_associated_item(self, id: DefIndex, sess: &'a Session) -> ty::AssocItem {
let name = if self.root.tables.opt_rpitit_info.get(self, id).is_some() {
let name = if self.root.tables.opt_rpitit_info.get(self, id).is_some()
|| self.root.tables.is_effects_desugaring.get(self, id)
{
kw::Empty
} else {
self.item_name(id)
@ -1371,6 +1373,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
container,
fn_has_self_parameter: has_self,
opt_rpitit_info,
is_effects_desugaring: self.root.tables.is_effects_desugaring.get(self, id),
}
}

View File

@ -279,6 +279,9 @@ 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) }

View File

@ -1454,6 +1454,9 @@ 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 def_kind == DefKind::Closure
&& let Some(coroutine_kind) = self.tcx.coroutine_kind(def_id)
@ -1634,6 +1637,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
);
}
}
if item.is_effects_desugaring {
self.tables.is_effects_desugaring.set(def_id.index, true);
}
}
fn encode_mir(&mut self) {

View File

@ -391,7 +391,9 @@ define_tables! {
inferred_outlives_of: Table<DefIndex, LazyArray<(ty::Clause<'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>,
// Reexported names are not associated with individual `DefId`s,
// e.g. a glob import can introduce a lot of names, all with the same `DefId`.

View File

@ -368,6 +368,7 @@ rustc_queries! {
desc { |tcx| "finding item bounds for `{}`", tcx.def_path_str(key) }
cache_on_disk_if { key.is_local() }
separate_provide_extern
feedable
}
/// The set of item bounds (see [`TyCtxt::explicit_item_bounds`]) that
@ -378,6 +379,7 @@ rustc_queries! {
desc { |tcx| "finding item bounds for `{}`", tcx.def_path_str(key) }
cache_on_disk_if { key.is_local() }
separate_provide_extern
feedable
}
/// Elaborated version of the predicates from `explicit_item_bounds`.
@ -847,6 +849,12 @@ 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 {

View File

@ -34,6 +34,8 @@ pub struct AssocItem {
/// return-position `impl Trait` in trait desugaring. The `ImplTraitInTraitData`
/// provides additional information about its source.
pub opt_rpitit_info: Option<ty::ImplTraitInTraitData>,
pub is_effects_desugaring: bool,
}
impl AssocItem {

View File

@ -3095,9 +3095,9 @@ impl<'tcx> TyCtxt<'tcx> {
matches!(
node,
hir::Node::Item(hir::Item {
kind: hir::ItemKind::Impl(hir::Impl { generics, .. }),
kind: hir::ItemKind::Impl(hir::Impl { constness, .. }),
..
}) if generics.params.iter().any(|p| matches!(p.kind, hir::GenericParamKind::Const { is_host_effect: true, .. }))
}) if matches!(constness, hir::Constness::Const)
)
}

View File

@ -14,7 +14,7 @@ use super::{Clause, InstantiatedPredicates, ParamConst, ParamTy, Ty, TyCtxt};
pub enum GenericParamDefKind {
Lifetime,
Type { has_default: bool, synthetic: bool },
Const { has_default: bool, is_host_effect: bool },
Const { has_default: bool, is_host_effect: bool, synthetic: bool },
}
impl GenericParamDefKind {
@ -371,6 +371,7 @@ impl<'tcx> Generics {
pub struct GenericPredicates<'tcx> {
pub parent: Option<DefId>,
pub predicates: &'tcx [(Clause<'tcx>, Span)],
pub effects_min_tys: &'tcx ty::List<Ty<'tcx>>,
}
impl<'tcx> GenericPredicates<'tcx> {

View File

@ -1608,7 +1608,7 @@ impl<'tcx> TyCtxt<'tcx> {
}
}
/// If the def-id is an associated type that was desugared from a
/// If the `def_id` is an associated type that was desugared from a
/// return-position `impl Trait` from a trait, then provide the source info
/// about where that RPITIT came from.
pub fn opt_rpitit_info(self, def_id: DefId) -> Option<ImplTraitInTraitData> {
@ -1619,6 +1619,16 @@ impl<'tcx> TyCtxt<'tcx> {
}
}
/// Whether the `def_id` is an associated type that was desugared from a
/// `#[const_trait]` or `impl_const`.
pub fn is_effects_desugared_assoc_ty(self, def_id: DefId) -> bool {
if let DefKind::AssocTy = self.def_kind(def_id) {
self.associated_item(def_id).is_effects_desugaring
} else {
false
}
}
pub fn find_field_index(self, ident: Ident, variant: &VariantDef) -> Option<FieldIdx> {
variant.fields.iter_enumerated().find_map(|(i, field)| {
self.hygienic_eq(ident, field.ident(self), variant.def_id).then_some(i)

View File

@ -160,7 +160,8 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
fn predicates_of(&self, def_id: stable_mir::DefId) -> stable_mir::ty::GenericPredicates {
let mut tables = self.0.borrow_mut();
let def_id = tables[def_id];
let GenericPredicates { parent, predicates } = tables.tcx.predicates_of(def_id);
let GenericPredicates { parent, predicates, effects_min_tys: _ } =
tables.tcx.predicates_of(def_id);
stable_mir::ty::GenericPredicates {
parent: parent.map(|did| tables.trait_def(did)),
predicates: predicates
@ -181,7 +182,8 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
) -> stable_mir::ty::GenericPredicates {
let mut tables = self.0.borrow_mut();
let def_id = tables[def_id];
let GenericPredicates { parent, predicates } = tables.tcx.explicit_predicates_of(def_id);
let GenericPredicates { parent, predicates, effects_min_tys: _ } =
tables.tcx.explicit_predicates_of(def_id);
stable_mir::ty::GenericPredicates {
parent: parent.map(|did| tables.trait_def(did)),
predicates: predicates

View File

@ -600,7 +600,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: _ } => {
ty::GenericParamDefKind::Const { has_default, is_host_effect: _, synthetic: _ } => {
GenericParamDefKind::Const { has_default: *has_default }
}
}

View File

@ -194,6 +194,14 @@ symbols! {
Display,
DoubleEndedIterator,
Duration,
EffectsCompat,
EffectsMaybe,
EffectsMin,
EffectsMinOutput,
EffectsNoRuntime,
EffectsRuntime,
EffectsTyCompat,
Effects__,
Encodable,
Encoder,
Enumerate,
@ -1658,6 +1666,7 @@ symbols! {
rustc_reallocator,
rustc_regions,
rustc_reservation_impl,
rustc_runtime,
rustc_safe_intrinsic,
rustc_serialize,
rustc_skip_during_method_dispatch,

View File

@ -4995,6 +4995,12 @@ fn point_at_assoc_type_restriction<G: EmissionGuarantee>(
let ty::ClauseKind::Projection(proj) = clause else {
return;
};
// avoid ICEing since effects desugared associated types don't have names.
// this path should only be hit for `~const` on invalid places, so they
// will have an informative error already.
if tcx.is_effects_desugared_assoc_ty(proj.projection_term.def_id) {
return;
}
let name = tcx.item_name(proj.projection_term.def_id);
let mut predicates = generics.predicates.iter().peekable();
let mut prev: Option<&hir::WhereBoundPredicate<'_>> = None;

View File

@ -4,8 +4,9 @@ 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, TyCtxt};
use rustc_middle::ty::{self, ImplTraitInTraitData, Ty, TyCtxt};
use rustc_middle::{bug, span_bug};
use rustc_span::sym;
use rustc_span::symbol::kw;
pub(crate) fn provide(providers: &mut Providers) {
@ -14,6 +15,7 @@ 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
@ -44,7 +46,8 @@ fn associated_item_def_ids(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &[DefId] {
)
})
.copied(),
),
)
.chain(tcx.associated_type_for_effects(def_id)),
)
}
hir::ItemKind::Impl(impl_) => {
@ -70,7 +73,8 @@ 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"),
@ -143,6 +147,7 @@ fn associated_item_from_trait_item_ref(trait_item_ref: &hir::TraitItemRef) -> ty
container: ty::TraitContainer,
fn_has_self_parameter: has_self,
opt_rpitit_info: None,
is_effects_desugaring: false,
}
}
@ -162,6 +167,161 @@ fn associated_item_from_impl_item_ref(impl_item_ref: &hir::ImplItemRef) -> ty::A
container: ty::ImplContainer,
fn_has_self_parameter: has_self,
opt_rpitit_info: None,
is_effects_desugaring: false,
}
}
/// 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> {
match tcx.def_kind(def_id) {
DefKind::Trait => {
let trait_def_id = def_id;
let Some(attr) = tcx.get_attr(def_id, sym::const_trait) else {
return None;
};
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();
trait_assoc_ty.feed_hir();
// 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,
});
// visibility is public.
trait_assoc_ty.visibility(ty::Visibility::Public);
// No default type
trait_assoc_ty.defaultness(hir::Defaultness::Default { has_value: false });
trait_assoc_ty.is_type_alias_impl_trait(false);
// Copy generics_of of the trait, making the trait as parent.
trait_assoc_ty.generics_of({
let parent_generics = tcx.generics_of(trait_def_id);
let parent_count = parent_generics.parent_count + parent_generics.own_params.len();
ty::Generics {
parent: Some(trait_def_id.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,
}
});
trait_assoc_ty.explicit_item_bounds(ty::EarlyBinder::bind(&[]));
trait_assoc_ty.explicit_item_super_predicates(ty::EarlyBinder::bind(&[]));
// There are no inferred outlives for the synthesized associated type.
trait_assoc_ty.inferred_outlives_of(&[]);
Some(def_id)
}
DefKind::Impl { .. } => {
let impl_def_id = def_id;
let Some(trait_id) = tcx.trait_id_of_impl(def_id.to_def_id()) else { return None };
// first get the DefId of the assoc type on the trait, if there is not,
// then we don't need to generate it on the impl.
let Some(trait_assoc_id) = tcx.associated_type_for_effects(trait_id) else {
return None;
};
// TODO span is bad
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.feed_hir();
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,
});
// visibility is public.
impl_assoc_ty.visibility(ty::Visibility::Public);
// 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))
};
// TODO this is wrong
impl_assoc_ty.type_of(ty::EarlyBinder::bind(Ty::new_adt(
tcx,
tcx.adt_def(type_def_id),
ty::GenericArgs::empty(),
)));
// Copy generics_of of the impl, making the impl as parent.
impl_assoc_ty.generics_of({
let parent_generics = tcx.generics_of(impl_def_id);
let parent_count = parent_generics.parent_count + parent_generics.own_params.len();
ty::Generics {
parent: Some(impl_def_id.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,
}
});
impl_assoc_ty.explicit_item_bounds(ty::EarlyBinder::bind(&[]));
impl_assoc_ty.explicit_item_super_predicates(ty::EarlyBinder::bind(&[]));
// There are no inferred outlives for the synthesized associated type.
impl_assoc_ty.inferred_outlives_of(&[]);
Some(def_id)
}
def_kind => bug!(
"associated_type_for_effects: {:?} should be Trait or Impl but is {:?}",
def_id,
def_kind
),
}
}
@ -275,6 +435,7 @@ fn associated_type_for_impl_trait_in_trait(
fn_def_id: fn_def_id.to_def_id(),
opaque_def_id: opaque_ty_def_id.to_def_id(),
}),
is_effects_desugaring: false,
});
// Copy visility of the containing function.
@ -326,6 +487,7 @@ fn associated_type_for_impl_trait_in_impl(
container: ty::ImplContainer,
fn_has_self_parameter: false,
opt_rpitit_info: Some(ImplTraitInTraitData::Impl { fn_def_id: impl_fn_def_id.to_def_id() }),
is_effects_desugaring: false,
});
// Copy visility of the containing function.

View File

@ -231,6 +231,7 @@
#![feature(let_chains)]
#![feature(link_llvm_intrinsics)]
#![feature(macro_metavar_expr)]
#![feature(marker_trait_attr)]
#![feature(min_exhaustive_patterns)]
#![feature(min_specialization)]
#![feature(multiple_supertrait_upcastable)]

View File

@ -1027,3 +1027,41 @@ pub trait FnPtr: Copy + Clone {
pub macro SmartPointer($item:item) {
/* compiler built-in */
}
#[doc(hidden)]
#[unstable(
feature = "effect_types",
issue = "none",
reason = "internal module for implementing effects"
)]
#[allow(missing_debug_implementations)] // these unit structs don't need `Debug` impls.
#[cfg(not(bootstrap))]
// TODO docs
pub mod effects {
#[lang = "EffectsNoRuntime"]
pub struct NoRuntime;
#[lang = "EffectsMaybe"]
pub struct Maybe;
#[lang = "EffectsRuntime"]
pub struct Runtime;
#[lang = "EffectsCompat"]
pub trait Compat<#[rustc_runtime] const RUNTIME: bool> {}
impl Compat<false> for NoRuntime {}
impl Compat<true> for Runtime {}
impl<#[rustc_runtime] const RUNTIME: bool> Compat<RUNTIME> for Maybe {}
#[lang = "EffectsTyCompat"]
#[marker]
pub trait TyCompat<T> {}
impl<T> TyCompat<T> for T {}
impl<T> TyCompat<T> for Maybe {}
#[lang = "EffectsMin"]
pub trait Min {
#[lang = "EffectsMinOutput"]
type Output;
}
}

View File

@ -549,7 +549,7 @@ fn clean_generic_param_def<'tcx>(
},
)
}
ty::GenericParamDefKind::Const { has_default, is_host_effect } => (
ty::GenericParamDefKind::Const { has_default, synthetic, is_host_effect: _ } => (
def.name,
GenericParamDefKind::Const {
ty: Box::new(clean_middle_ty(
@ -572,7 +572,7 @@ fn clean_generic_param_def<'tcx>(
} else {
None
},
is_host_effect,
synthetic,
},
),
};
@ -628,13 +628,13 @@ fn clean_generic_param<'tcx>(
},
)
}
hir::GenericParamKind::Const { ty, default, is_host_effect } => (
hir::GenericParamKind::Const { ty, default, synthetic, is_host_effect: _ } => (
param.name.ident().name,
GenericParamDefKind::Const {
ty: Box::new(clean_ty(ty, cx)),
default: default
.map(|ct| Box::new(ty::Const::from_anon_const(cx.tcx, ct.def_id).to_string())),
is_host_effect,
synthetic,
},
),
};
@ -1411,7 +1411,11 @@ pub(crate) fn clean_middle_assoc_item<'tcx>(
let mut generics = clean_ty_generics(
cx,
tcx.generics_of(assoc_item.def_id),
ty::GenericPredicates { parent: None, predicates },
ty::GenericPredicates {
parent: None,
predicates,
effects_min_tys: ty::List::empty(),
},
);
simplify::move_bounds_to_generic_parameters(&mut generics);

View File

@ -1321,7 +1321,7 @@ pub(crate) enum GenericParamDefKind {
Lifetime { outlives: ThinVec<Lifetime> },
Type { bounds: ThinVec<GenericBound>, default: Option<Box<Type>>, synthetic: bool },
// Option<Box<String>> makes this type smaller than `Option<String>` would.
Const { ty: Box<Type>, default: Option<Box<String>>, is_host_effect: bool },
Const { ty: Box<Type>, default: Option<Box<String>>, synthetic: bool },
}
impl GenericParamDefKind {
@ -1345,7 +1345,7 @@ impl GenericParamDef {
pub(crate) fn is_synthetic_param(&self) -> bool {
match self.kind {
GenericParamDefKind::Lifetime { .. } => false,
GenericParamDefKind::Const { is_host_effect, .. } => is_host_effect,
GenericParamDefKind::Const { synthetic: is_host_effect, .. } => is_host_effect,
GenericParamDefKind::Type { synthetic, .. } => synthetic,
}
}

View File

@ -466,7 +466,7 @@ impl FromWithTcx<clean::GenericParamDefKind> for GenericParamDefKind {
default: default.map(|x| (*x).into_tcx(tcx)),
synthetic,
},
Const { ty, default, is_host_effect: _ } => GenericParamDefKind::Const {
Const { ty, default, synthetic: _ } => GenericParamDefKind::Const {
type_: (*ty).into_tcx(tcx),
default: default.map(|x| *x),
},
@ -501,14 +501,12 @@ impl FromWithTcx<clean::WherePredicate> for WherePredicate {
synthetic,
}
}
clean::GenericParamDefKind::Const {
ty,
default,
is_host_effect: _,
} => GenericParamDefKind::Const {
clean::GenericParamDefKind::Const { ty, default, synthetic: _ } => {
GenericParamDefKind::Const {
type_: (*ty).into_tcx(tcx),
default: default.map(|d| *d),
},
}
}
};
GenericParamDef { name, kind }
})

View File

@ -1,4 +1,5 @@
//@ build-pass
//@ compile-flags: -Znext-solver
#![feature(const_trait_impl, effects)] //~ WARN the feature `effects` is incomplete

View File

@ -0,0 +1,14 @@
//@ check-pass
use std::ops::Add;
pub trait GroupOpsOwned<Rhs = Self, Output = Self>: for<'r> Add<&'r Rhs, Output = Output> {}
pub trait Curve: Sized + GroupOpsOwned<Self::AffineRepr> {
type AffineRepr;
}
pub trait CofactorCurve: Curve<AffineRepr = <Self as CofactorCurve>::Affine> {
type Affine;
}
fn main() {}

View File

@ -1,8 +1,9 @@
// Regression test for #92230.
//
//@ check-pass
//@ compile-flags: -Znext-solver
#![feature(const_trait_impl)]
#![feature(const_trait_impl, effects)]
#[const_trait]
pub trait Super {}

View File

@ -282,12 +282,21 @@ help: wrap the field type in `ManuallyDrop<...>`
LL | union Union<T: ~const Trait> { field: std::mem::ManuallyDrop<T> }
| +++++++++++++++++++++++ +
error[E0275]: overflow evaluating the requirement `(): Trait`
error[E0275]: overflow evaluating the requirement `Trait::{opaque#0} == _`
--> $DIR/tilde-const-invalid-places.rs:34:34
|
LL | type Type<T: ~const Trait> = ();
| ^^
|
note: required for `()` to implement `Trait`
--> $DIR/tilde-const-invalid-places.rs:56:23
|
LL | impl<T: ~const Trait> Trait for T {}
| ------------ ^^^^^ ^
| |
| unsatisfied trait bound introduced here
= note: 1 redundant requirement hidden
= note: required for `()` to implement `Trait`
note: required by a bound in `NonConstTrait::Type`
--> $DIR/tilde-const-invalid-places.rs:25:33
|

View File

@ -1,4 +1,5 @@
// Ensure that we print unsatisfied always-const trait bounds as `const Trait` in diagnostics.
//@ compile-flags: -Znext-solver
#![feature(const_trait_impl, effects, generic_const_exprs)]
#![allow(incomplete_features)]