Rollup merge of #119894 - fmease:tilde-const-assoc-ty-bounds, r=compiler-errors
Allow `~const` on associated type bounds again This follows from [this Zulip discussion](https://rust-lang.zulipchat.com/#narrow/stream/419616-t-compiler.2Fproject-const-traits/topic/projections.20on.20.28~.29const.20Trait.20.26.20.28~.29const.20assoc.20ty.20bounds). Basically in my opinion, it makes sense to allow `~const` on associated type bounds again since they're quite useful even though we haven't implemented the proposed syntax `<Ty as ~const Trait>::Proj`/`<Ty as const Trait>::Proj` yet; that can happen as a follow-up. This already allows more code to compile since `T::Assoc` where `T` is a type parameter and where the predicate `<T as ~const Trait>` is in the environment gets elaborated to (pseudo) `<T as ~const Trait>::Assoc`. ```rs #[const_trait] trait Trait { type Assoc: ~const Trait; fn func() -> i32; } const fn function<T: ~const Trait>() -> i32 { T::Assoc::func() } ``` `~const` associated type bounds also work together with `const` bounds: ```rs struct Type<const N: i32>; fn procedure<T: const Trait>() -> Type<{ T::Assoc::func() }> { // `Trait` comes from above Type } ``` NB: This PR also starts allowing `~const` bounds in the generics and the where-clause of trait associated types since it's trivial to support them. However, I don't know if those bounds are actually useful. Maybe we should continue to reject them? For reference, it wouldn't make any sense to allow `~const Trait` in GACs (generic associated constants, `generic_const_items`) because they'd be absolutely useless (contrary to `const Trait`). ~~[``@]rustbot`` ping project-const-traits~~ r? project-const-traits
This commit is contained in:
commit
2c7ce1c453
13 changed files with 202 additions and 64 deletions
|
@ -37,12 +37,17 @@ enum SelfSemantic {
|
|||
}
|
||||
|
||||
/// What is the context that prevents using `~const`?
|
||||
// FIXME(effects): Consider getting rid of this in favor of `errors::TildeConstReason`, they're
|
||||
// almost identical. This gets rid of an abstraction layer which might be considered bad.
|
||||
enum DisallowTildeConstContext<'a> {
|
||||
TraitObject,
|
||||
Fn(FnKind<'a>),
|
||||
Trait(Span),
|
||||
TraitImpl(Span),
|
||||
Impl(Span),
|
||||
TraitAssocTy(Span),
|
||||
TraitImplAssocTy(Span),
|
||||
InherentAssocTy(Span),
|
||||
Item,
|
||||
}
|
||||
|
||||
|
@ -316,6 +321,7 @@ impl<'a> AstValidator<'a> {
|
|||
constness: Const::No,
|
||||
polarity: ImplPolarity::Positive,
|
||||
trait_ref,
|
||||
..
|
||||
} = parent
|
||||
{
|
||||
Some(trait_ref.path.span.shrink_to_lo())
|
||||
|
@ -1286,6 +1292,15 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
// suggestion for moving such bounds to the assoc const fns if available.
|
||||
errors::TildeConstReason::Impl { span }
|
||||
}
|
||||
&DisallowTildeConstContext::TraitAssocTy(span) => {
|
||||
errors::TildeConstReason::TraitAssocTy { span }
|
||||
}
|
||||
&DisallowTildeConstContext::TraitImplAssocTy(span) => {
|
||||
errors::TildeConstReason::TraitImplAssocTy { span }
|
||||
}
|
||||
&DisallowTildeConstContext::InherentAssocTy(span) => {
|
||||
errors::TildeConstReason::InherentAssocTy { span }
|
||||
}
|
||||
DisallowTildeConstContext::TraitObject => {
|
||||
errors::TildeConstReason::TraitObject
|
||||
}
|
||||
|
@ -1483,13 +1498,12 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
self.check_item_named(item.ident, "const");
|
||||
}
|
||||
|
||||
let parent_is_const =
|
||||
self.outer_trait_or_trait_impl.as_ref().and_then(TraitOrTraitImpl::constness).is_some();
|
||||
|
||||
match &item.kind {
|
||||
AssocItemKind::Fn(box Fn { sig, generics, body, .. })
|
||||
if self
|
||||
.outer_trait_or_trait_impl
|
||||
.as_ref()
|
||||
.and_then(TraitOrTraitImpl::constness)
|
||||
.is_some()
|
||||
if parent_is_const
|
||||
|| ctxt == AssocCtxt::Trait
|
||||
|| matches!(sig.header.constness, Const::Yes(_)) =>
|
||||
{
|
||||
|
@ -1505,6 +1519,20 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
);
|
||||
self.visit_fn(kind, item.span, item.id);
|
||||
}
|
||||
AssocItemKind::Type(_) => {
|
||||
let disallowed = (!parent_is_const).then(|| match self.outer_trait_or_trait_impl {
|
||||
Some(TraitOrTraitImpl::Trait { .. }) => {
|
||||
DisallowTildeConstContext::TraitAssocTy(item.span)
|
||||
}
|
||||
Some(TraitOrTraitImpl::TraitImpl { .. }) => {
|
||||
DisallowTildeConstContext::TraitImplAssocTy(item.span)
|
||||
}
|
||||
None => DisallowTildeConstContext::InherentAssocTy(item.span),
|
||||
});
|
||||
self.with_tilde_const(disallowed, |this| {
|
||||
this.with_in_trait_impl(None, |this| visit::walk_assoc_item(this, item, ctxt))
|
||||
})
|
||||
}
|
||||
_ => self.with_in_trait_impl(None, |this| visit::walk_assoc_item(this, item, ctxt)),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -565,6 +565,8 @@ pub struct ConstBoundTraitObject {
|
|||
pub span: Span,
|
||||
}
|
||||
|
||||
// FIXME(effects): Consider making the note/reason the message of the diagnostic.
|
||||
// FIXME(effects): Provide structured suggestions (e.g., add `const` / `#[const_trait]` here).
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_tilde_const_disallowed)]
|
||||
pub struct TildeConstDisallowed {
|
||||
|
@ -598,6 +600,21 @@ pub enum TildeConstReason {
|
|||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
#[note(ast_passes_trait_assoc_ty)]
|
||||
TraitAssocTy {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
#[note(ast_passes_trait_impl_assoc_ty)]
|
||||
TraitImplAssocTy {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
#[note(ast_passes_inherent_assoc_ty)]
|
||||
InherentAssocTy {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
#[note(ast_passes_object)]
|
||||
TraitObject,
|
||||
#[note(ast_passes_item)]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue