1
Fork 0

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

View file

@ -2348,6 +2348,14 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
let mut should_continue = true; let mut should_continue = true;
match rib.kind { match rib.kind {
LifetimeRibKind::Generics { binder: _, span, 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 { if !span.can_be_used_for_suggestions() && suggest_note && let Some(name) = name {
suggest_note = false; // Avoid displaying the same help multiple times. suggest_note = false; // Avoid displaying the same help multiple times.
err.span_label( err.span_label(