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 { 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, // We already forbid generic params because of the above item rib,
// so it doesn't matter whether this is a trivial constant. // so it doesn't matter whether this is a trivial constant.
this.with_constant_rib( this.resolve_const_body(expr, Some((item.ident, ConstantItemKind::Static)));
IsRepeatExpr::No,
ConstantHasGenerics::Yes,
Some((item.ident, constant_item_kind)),
|this| this.visit_expr(expr),
);
} }
}); });
}); }
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 {
this.resolve_const_body(
expr,
Some((item.ident, ConstantItemKind::Const)),
);
}
},
);
} }
ItemKind::Use(ref use_tree) => { ItemKind::Use(ref use_tree) => {
@ -2700,8 +2715,19 @@ 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(
&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 // Only impose the restrictions of `ConstRibKind` for an
// actual constant expression in a provided default. // actual constant expression in a provided default.
if let Some(expr) = expr { if let Some(expr) = expr {
@ -2710,19 +2736,11 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
// //
// Type parameters can already be used and as associated consts are // Type parameters can already be used and as associated consts are
// not used as part of the type system, this is far less surprising. // not used as part of the type system, this is far less surprising.
self.with_lifetime_rib( this.resolve_const_body(expr, None);
LifetimeRibKind::Elided(LifetimeRes::Infer), }
|this| {
this.with_constant_rib(
IsRepeatExpr::No,
ConstantHasGenerics::Yes,
None,
|this| this.visit_expr(expr),
)
}, },
); );
} }
}
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,11 +2894,21 @@ 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");
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 // If this is a trait impl, ensure the const
// exists in trait // exists in trait
self.check_trait_item( this.check_trait_item(
item.id, item.id,
item.ident, item.ident,
&item.kind, &item.kind,
@ -2890,22 +2918,18 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
|i, s, c| ConstNotMemberOfTrait(i, s, c), |i, s, c| ConstNotMemberOfTrait(i, s, c),
); );
self.visit_ty(ty); this.visit_generics(generics);
this.visit_ty(ty);
if let Some(expr) = expr { if let Some(expr) = expr {
// We allow arbitrary const expressions inside of associated consts, // We allow arbitrary const expressions inside of associated consts,
// even if they are potentially not const evaluatable. // even if they are potentially not const evaluatable.
// //
// Type parameters can already be used and as associated consts are // Type parameters can already be used and as associated consts are
// not used as part of the type system, this is far less surprising. // not used as part of the type system, this is far less surprising.
self.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Infer), |this| { this.resolve_const_body(expr, None);
this.with_constant_rib(
IsRepeatExpr::No,
ConstantHasGenerics::Yes,
None,
|this| this.visit_expr(expr),
)
});
} }
},
);
} }
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(