Resolve generic const items

This commit is contained in:
León Orell Valerian Liehr 2023-07-02 18:48:24 +02:00
parent 9213aec762
commit da17134be0
No known key found for this signature in database
GPG Key ID: D17A07215F68E713
2 changed files with 109 additions and 69 deletions

View File

@ -337,6 +337,7 @@ enum LifetimeBinderKind {
PolyTrait,
WhereBound,
Item,
ConstItem,
Function,
Closure,
ImplBlock,
@ -349,7 +350,7 @@ fn descr(self) -> &'static str {
BareFnType => "type",
PolyTrait => "bound",
WhereBound => "bound",
Item => "item",
Item | ConstItem => "item",
ImplBlock => "impl block",
Function => "function",
Closure => "closure",
@ -2404,30 +2405,44 @@ fn resolve_item(&mut self, item: &'ast Item) {
});
}
ItemKind::Static(box ast::StaticItem { ref ty, ref expr, .. })
| ItemKind::Const(box ast::ConstItem { ref ty, ref expr, .. }) => {
ItemKind::Static(box ast::StaticItem { ref ty, ref expr, .. }) => {
self.with_static_rib(|this| {
this.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Static), |this| {
this.visit_ty(ty);
});
this.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Infer), |this| {
if let Some(expr) = expr {
// We already forbid generic params because of the above item rib,
// so it doesn't matter whether this is a trivial constant.
this.resolve_const_body(expr, Some((item.ident, ConstantItemKind::Static)));
}
});
}
ItemKind::Const(box ast::ConstItem { ref generics, ref ty, ref expr, .. }) => {
self.with_generic_param_rib(
&generics.params,
RibKind::Item(HasGenericParams::Yes(generics.span)),
LifetimeRibKind::Generics {
binder: item.id,
kind: LifetimeBinderKind::ConstItem,
span: generics.span,
},
|this| {
this.visit_generics(generics);
this.with_lifetime_rib(
LifetimeRibKind::Elided(LifetimeRes::Static),
|this| this.visit_ty(ty),
);
if let Some(expr) = expr {
let constant_item_kind = match item.kind {
ItemKind::Const(..) => ConstantItemKind::Const,
ItemKind::Static(..) => ConstantItemKind::Static,
_ => unreachable!(),
};
// We already forbid generic params because of the above item rib,
// so it doesn't matter whether this is a trivial constant.
this.with_constant_rib(
IsRepeatExpr::No,
ConstantHasGenerics::Yes,
Some((item.ident, constant_item_kind)),
|this| this.visit_expr(expr),
this.resolve_const_body(
expr,
Some((item.ident, ConstantItemKind::Const)),
);
}
});
});
},
);
}
ItemKind::Use(ref use_tree) => {
@ -2700,28 +2715,31 @@ fn resolve_trait_items(&mut self, trait_items: &'ast [P<AssocItem>]) {
for item in trait_items {
self.resolve_doc_links(&item.attrs, MaybeExported::Ok(item.id));
match &item.kind {
AssocItemKind::Const(box ast::ConstItem { ty, expr, .. }) => {
self.visit_ty(ty);
// Only impose the restrictions of `ConstRibKind` for an
// actual constant expression in a provided default.
if let Some(expr) = expr {
// We allow arbitrary const expressions inside of associated consts,
// even if they are potentially not const evaluatable.
//
// Type parameters can already be used and as associated consts are
// not used as part of the type system, this is far less surprising.
self.with_lifetime_rib(
LifetimeRibKind::Elided(LifetimeRes::Infer),
|this| {
this.with_constant_rib(
IsRepeatExpr::No,
ConstantHasGenerics::Yes,
None,
|this| this.visit_expr(expr),
)
},
);
}
AssocItemKind::Const(box ast::ConstItem { generics, ty, expr, .. }) => {
self.with_generic_param_rib(
&generics.params,
RibKind::AssocItem,
LifetimeRibKind::Generics {
binder: item.id,
span: generics.span,
kind: LifetimeBinderKind::ConstItem,
},
|this| {
this.visit_generics(generics);
this.visit_ty(ty);
// Only impose the restrictions of `ConstRibKind` for an
// actual constant expression in a provided default.
if let Some(expr) = expr {
// We allow arbitrary const expressions inside of associated consts,
// even if they are potentially not const evaluatable.
//
// Type parameters can already be used and as associated consts are
// not used as part of the type system, this is far less surprising.
this.resolve_const_body(expr, None);
}
},
);
}
AssocItemKind::Fn(box Fn { generics, .. }) => {
walk_assoc_item(self, generics, LifetimeBinderKind::Function, item);
@ -2876,36 +2894,42 @@ fn resolve_impl_item(
use crate::ResolutionError::*;
self.resolve_doc_links(&item.attrs, MaybeExported::ImplItem(trait_id.ok_or(&item.vis)));
match &item.kind {
AssocItemKind::Const(box ast::ConstItem { ty, expr, .. }) => {
AssocItemKind::Const(box ast::ConstItem { generics, ty, expr, .. }) => {
debug!("resolve_implementation AssocItemKind::Const");
// If this is a trait impl, ensure the const
// exists in trait
self.check_trait_item(
item.id,
item.ident,
&item.kind,
ValueNS,
item.span,
seen_trait_items,
|i, s, c| ConstNotMemberOfTrait(i, s, c),
);
self.visit_ty(ty);
if let Some(expr) = expr {
// We allow arbitrary const expressions inside of associated consts,
// even if they are potentially not const evaluatable.
//
// Type parameters can already be used and as associated consts are
// not used as part of the type system, this is far less surprising.
self.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Infer), |this| {
this.with_constant_rib(
IsRepeatExpr::No,
ConstantHasGenerics::Yes,
None,
|this| this.visit_expr(expr),
)
});
}
self.with_generic_param_rib(
&generics.params,
RibKind::AssocItem,
LifetimeRibKind::Generics {
binder: item.id,
span: generics.span,
kind: LifetimeBinderKind::ConstItem,
},
|this| {
// If this is a trait impl, ensure the const
// exists in trait
this.check_trait_item(
item.id,
item.ident,
&item.kind,
ValueNS,
item.span,
seen_trait_items,
|i, s, c| ConstNotMemberOfTrait(i, s, c),
);
this.visit_generics(generics);
this.visit_ty(ty);
if let Some(expr) = expr {
// We allow arbitrary const expressions inside of associated consts,
// even if they are potentially not const evaluatable.
//
// Type parameters can already be used and as associated consts are
// not used as part of the type system, this is far less surprising.
this.resolve_const_body(expr, None);
}
},
);
}
AssocItemKind::Fn(box Fn { generics, .. }) => {
debug!("resolve_implementation AssocItemKind::Fn");
@ -3063,6 +3087,14 @@ fn check_trait_item<F>(
);
}
fn resolve_const_body(&mut self, expr: &'ast Expr, item: Option<(Ident, ConstantItemKind)>) {
self.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Infer), |this| {
this.with_constant_rib(IsRepeatExpr::No, ConstantHasGenerics::Yes, item, |this| {
this.visit_expr(expr)
});
})
}
fn resolve_params(&mut self, params: &'ast [Param]) {
let mut bindings = smallvec![(PatBoundCtx::Product, Default::default())];
self.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Infer), |this| {
@ -4448,6 +4480,7 @@ impl<'ast> Visitor<'ast> for LifetimeCountVisitor<'_, '_, '_> {
fn visit_item(&mut self, item: &'ast Item) {
match &item.kind {
ItemKind::TyAlias(box TyAlias { ref generics, .. })
| ItemKind::Const(box ConstItem { ref generics, .. })
| ItemKind::Fn(box Fn { ref generics, .. })
| ItemKind::Enum(_, ref generics)
| ItemKind::Struct(_, ref generics)
@ -4467,7 +4500,6 @@ fn visit_item(&mut self, item: &'ast Item) {
ItemKind::Mod(..)
| ItemKind::ForeignMod(..)
| ItemKind::Static(..)
| ItemKind::Const(..)
| ItemKind::Use(..)
| ItemKind::ExternCrate(..)
| ItemKind::MacroDef(..)

View File

@ -2348,6 +2348,14 @@ fn suggest_introducing_lifetime(
let mut should_continue = true;
match rib.kind {
LifetimeRibKind::Generics { binder: _, span, kind } => {
// Avoid suggesting placing lifetime parameters on constant items unless the relevant
// feature is enabled. Suggest the parent item as a possible location if applicable.
if let LifetimeBinderKind::ConstItem = kind
&& !self.r.tcx().features().generic_const_items
{
continue;
}
if !span.can_be_used_for_suggestions() && suggest_note && let Some(name) = name {
suggest_note = false; // Avoid displaying the same help multiple times.
err.span_label(