Auto merge of #119099 - fmease:always-const-trait-bounds, r=fee1-dead
Introduce `const Trait` (always-const trait bounds) Feature `const_trait_impl` currently lacks a way to express “always const” trait bounds. This makes it impossible to define generic items like fns or structs which contain types that depend on const method calls (\*). While the final design and esp. the syntax of effects / keyword generics isn't set in stone, some version of “always const” trait bounds will very likely form a part of it. Further, their implementation is trivial thanks to the `effects` backbone. Not sure if this needs t-lang sign-off though. (\*): ```rs #![feature(const_trait_impl, effects, generic_const_exprs)] fn compute<T: const Trait>() -> Type<{ T::generate() }> { /*…*/ } struct Store<T: const Trait> where Type<{ T::generate() }>:, { field: Type<{ T::generate() }>, } ``` Lastly, “always const” trait bounds are a perfect fit for `generic_const_items`. ```rs #![feature(const_trait_impl, effects, generic_const_items)] const DEFAULT<T: const Default>: T = T::default(); ``` Previously, we (oli, fee1-dead and I) wanted to reinterpret `~const Trait` as `const Trait` in generic const items which would've been quite surprising and not very generalizable. Supersedes #117530. --- cc `@oli-obk` As discussed r? fee1-dead (or compiler)
This commit is contained in:
commit
88d69b72b4
69 changed files with 505 additions and 223 deletions
|
@ -339,9 +339,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
let itctx = ImplTraitContext::Universal;
|
||||
let (generics, (trait_ref, lowered_ty)) =
|
||||
self.lower_generics(ast_generics, *constness, id, &itctx, |this| {
|
||||
let constness = match *constness {
|
||||
Const::Yes(span) => BoundConstness::Maybe(span),
|
||||
Const::No => BoundConstness::Never,
|
||||
};
|
||||
|
||||
let trait_ref = trait_ref.as_ref().map(|trait_ref| {
|
||||
this.lower_trait_ref(
|
||||
*constness,
|
||||
constness,
|
||||
trait_ref,
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Trait),
|
||||
)
|
||||
|
|
|
@ -1349,7 +1349,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
span: t.span,
|
||||
},
|
||||
itctx,
|
||||
ast::Const::No,
|
||||
ast::BoundConstness::Never,
|
||||
);
|
||||
let bounds = this.arena.alloc_from_iter([bound]);
|
||||
let lifetime_bound = this.elided_dyn_bound(t.span);
|
||||
|
@ -1460,7 +1460,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
polarity: BoundPolarity::Positive | BoundPolarity::Negative(_),
|
||||
constness,
|
||||
},
|
||||
) => Some(this.lower_poly_trait_ref(ty, itctx, (*constness).into())),
|
||||
) => Some(this.lower_poly_trait_ref(ty, itctx, *constness)),
|
||||
// We can safely ignore constness here, since AST validation
|
||||
// will take care of invalid modifier combinations.
|
||||
GenericBound::Trait(
|
||||
|
@ -2199,7 +2199,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
|
||||
fn lower_trait_ref(
|
||||
&mut self,
|
||||
constness: ast::Const,
|
||||
constness: ast::BoundConstness,
|
||||
p: &TraitRef,
|
||||
itctx: &ImplTraitContext,
|
||||
) -> hir::TraitRef<'hir> {
|
||||
|
@ -2222,7 +2222,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
&mut self,
|
||||
p: &PolyTraitRef,
|
||||
itctx: &ImplTraitContext,
|
||||
constness: ast::Const,
|
||||
constness: ast::BoundConstness,
|
||||
) -> hir::PolyTraitRef<'hir> {
|
||||
let bound_generic_params =
|
||||
self.lower_lifetime_binder(p.trait_ref.ref_id, &p.bound_generic_params);
|
||||
|
@ -2347,9 +2347,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
&mut self,
|
||||
modifiers: TraitBoundModifiers,
|
||||
) -> hir::TraitBoundModifier {
|
||||
// Invalid modifier combinations will cause an error during AST validation.
|
||||
// Arbitrarily pick a placeholder for them to make compilation proceed.
|
||||
match (modifiers.constness, modifiers.polarity) {
|
||||
(BoundConstness::Never, BoundPolarity::Positive) => hir::TraitBoundModifier::None,
|
||||
(BoundConstness::Never, BoundPolarity::Maybe(_)) => hir::TraitBoundModifier::Maybe,
|
||||
(_, BoundPolarity::Maybe(_)) => hir::TraitBoundModifier::Maybe,
|
||||
(BoundConstness::Never, BoundPolarity::Negative(_)) => {
|
||||
if self.tcx.features().negative_bounds {
|
||||
hir::TraitBoundModifier::Negative
|
||||
|
@ -2357,15 +2359,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
hir::TraitBoundModifier::None
|
||||
}
|
||||
}
|
||||
(BoundConstness::Maybe(_), BoundPolarity::Positive) => {
|
||||
hir::TraitBoundModifier::MaybeConst
|
||||
}
|
||||
// Invalid modifier combinations will cause an error during AST validation.
|
||||
// Arbitrarily pick a placeholder for compilation to proceed.
|
||||
(BoundConstness::Maybe(_), BoundPolarity::Maybe(_)) => hir::TraitBoundModifier::Maybe,
|
||||
(BoundConstness::Maybe(_), BoundPolarity::Negative(_)) => {
|
||||
hir::TraitBoundModifier::MaybeConst
|
||||
}
|
||||
(BoundConstness::Always(_), _) => hir::TraitBoundModifier::Const,
|
||||
(BoundConstness::Maybe(_), _) => hir::TraitBoundModifier::MaybeConst,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2583,45 +2578,62 @@ struct GenericArgsCtor<'hir> {
|
|||
}
|
||||
|
||||
impl<'hir> GenericArgsCtor<'hir> {
|
||||
fn push_constness(&mut self, lcx: &mut LoweringContext<'_, 'hir>, constness: ast::Const) {
|
||||
fn push_constness(
|
||||
&mut self,
|
||||
lcx: &mut LoweringContext<'_, 'hir>,
|
||||
constness: ast::BoundConstness,
|
||||
) {
|
||||
if !lcx.tcx.features().effects {
|
||||
return;
|
||||
}
|
||||
|
||||
// if bound is non-const, don't add host effect param
|
||||
let ast::Const::Yes(span) = constness else { return };
|
||||
let (span, body) = match constness {
|
||||
BoundConstness::Never => return,
|
||||
BoundConstness::Always(span) => {
|
||||
let span = lcx.lower_span(span);
|
||||
|
||||
let span = lcx.lower_span(span);
|
||||
let body = hir::ExprKind::Lit(
|
||||
lcx.arena.alloc(hir::Lit { node: LitKind::Bool(false), span }),
|
||||
);
|
||||
|
||||
let id = lcx.next_node_id();
|
||||
let hir_id = lcx.next_id();
|
||||
(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 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 body = lcx.lower_body(|lcx| {
|
||||
(&[], {
|
||||
let hir_id = lcx.next_id();
|
||||
let res = Res::Def(DefKind::ConstParam, host_param_id.to_def_id());
|
||||
let expr_kind = hir::ExprKind::Path(hir::QPath::Resolved(
|
||||
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)],
|
||||
segments: arena_vec![
|
||||
lcx;
|
||||
hir::PathSegment::new(
|
||||
Ident { name: sym::host, span },
|
||||
hir_id,
|
||||
res
|
||||
)
|
||||
],
|
||||
}),
|
||||
));
|
||||
lcx.expr(span, expr_kind)
|
||||
})
|
||||
});
|
||||
|
||||
(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,
|
||||
|
|
|
@ -25,7 +25,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
param_mode: ParamMode,
|
||||
itctx: &ImplTraitContext,
|
||||
// constness of the impl/bound if this is a trait path
|
||||
constness: Option<ast::Const>,
|
||||
constness: Option<ast::BoundConstness>,
|
||||
) -> hir::QPath<'hir> {
|
||||
let qself_position = qself.as_ref().map(|q| q.position);
|
||||
let qself = qself.as_ref().map(|q| self.lower_ty(&q.ty, itctx));
|
||||
|
@ -179,7 +179,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
param_mode: ParamMode,
|
||||
parenthesized_generic_args: ParenthesizedGenericArgs,
|
||||
itctx: &ImplTraitContext,
|
||||
constness: Option<ast::Const>,
|
||||
constness: Option<ast::BoundConstness>,
|
||||
) -> hir::PathSegment<'hir> {
|
||||
debug!("path_span: {:?}, lower_path_segment(segment: {:?})", path_span, segment);
|
||||
let (mut generic_args, infer_args) = if let Some(generic_args) = segment.args.as_deref() {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue