misc nameres changes for anon consts

This commit is contained in:
Boxy 2023-05-05 21:31:00 +01:00
parent 4a18324a4d
commit 442617c046
7 changed files with 202 additions and 133 deletions

View File

@ -120,6 +120,12 @@ impl Path {
pub fn is_global(&self) -> bool {
!self.segments.is_empty() && self.segments[0].ident.name == kw::PathRoot
}
/// If this path is a single identifier with no arguments, does not ensure
/// that the path resolves to a const param, the caller should check this.
pub fn is_potential_trivial_const_arg(&self) -> bool {
self.segments.len() == 1 && self.segments[0].args.is_none()
}
}
/// A segment of a path: an identifier, an optional lifetime, and a set of types.
@ -1154,7 +1160,9 @@ impl Expr {
///
/// If this is not the case, name resolution does not resolve `N` when using
/// `min_const_generics` as more complex expressions are not supported.
pub fn is_potential_trivial_const_param(&self) -> bool {
///
/// Does not ensure that the path resolves to a const param, the caller should check this.
pub fn is_potential_trivial_const_arg(&self) -> bool {
let this = if let ExprKind::Block(block, None) = &self.kind
&& block.stmts.len() == 1
&& let StmtKind::Expr(expr) = &block.stmts[0].kind
@ -1165,8 +1173,7 @@ impl Expr {
};
if let ExprKind::Path(None, path) = &this.kind
&& path.segments.len() == 1
&& path.segments[0].args.is_none()
&& path.is_potential_trivial_const_arg()
{
true
} else {

View File

@ -188,6 +188,9 @@ pub trait Visitor<'ast>: Sized {
fn visit_variant(&mut self, v: &'ast Variant) {
walk_variant(self, v)
}
fn visit_variant_discr(&mut self, discr: &'ast AnonConst) {
self.visit_anon_const(discr);
}
fn visit_label(&mut self, label: &'ast Label) {
walk_label(self, label)
}
@ -380,7 +383,7 @@ where
visitor.visit_ident(variant.ident);
visitor.visit_vis(&variant.vis);
visitor.visit_variant_data(&variant.data);
walk_list!(visitor, visit_anon_const, &variant.disr_expr);
walk_list!(visitor, visit_variant_discr, &variant.disr_expr);
walk_list!(visitor, visit_attribute, &variant.attrs);
}

View File

@ -1190,13 +1190,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
// parsing. We try to resolve that ambiguity by attempting resolution in both the
// type and value namespaces. If we resolved the path in the value namespace, we
// transform it into a generic const argument.
TyKind::Path(qself, path) => {
TyKind::Path(None, path) => {
if let Some(res) = self
.resolver
.get_partial_res(ty.id)
.and_then(|partial_res| partial_res.full_res())
{
if !res.matches_ns(Namespace::TypeNS) {
if !res.matches_ns(Namespace::TypeNS)
&& path.is_potential_trivial_const_arg()
{
debug!(
"lower_generic_arg: Lowering type argument as const argument: {:?}",
ty,
@ -1218,7 +1220,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
let path_expr = Expr {
id: ty.id,
kind: ExprKind::Path(qself.clone(), path.clone()),
kind: ExprKind::Path(None, path.clone()),
span,
attrs: AttrVec::new(),
tokens: None,

View File

@ -1,9 +1,11 @@
#### Note: this error code is no longer emitted by the compiler
A non-`'static` lifetime was used in a const generic. This is currently not
allowed.
Erroneous code example:
```compile_fail,E0771
```compile_fail,E0770
#![feature(adt_const_params)]
fn function_with_str<'a, const STRING: &'a str>() {} // error!

View File

@ -51,7 +51,15 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
// of a const parameter type, e.g. `struct Foo<const N: usize, const M: [u8; N]>` is not allowed.
None
} else if tcx.lazy_normalization() {
if let Some(param_id) = tcx.hir().opt_const_param_default_param_def_id(hir_id) {
let parent_node = tcx.hir().get_parent(hir_id);
if let Node::Variant(Variant { disr_expr: Some(constant), .. }) = parent_node
&& constant.hir_id == hir_id
{
// enum variant discriminants are not allowed to use any kind of generics
None
} else if let Some(param_id) =
tcx.hir().opt_const_param_default_param_def_id(hir_id)
{
// If the def_id we are calling generics_of on is an anon ct default i.e:
//
// struct Foo<const N: usize = { .. }>;
@ -94,15 +102,15 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
has_self: generics.has_self,
has_late_bound_regions: generics.has_late_bound_regions,
};
} else {
// HACK(eddyb) this provides the correct generics when
// `feature(generic_const_expressions)` is enabled, so that const expressions
// used with const generics, e.g. `Foo<{N+1}>`, can work at all.
//
// Note that we do not supply the parent generics when using
// `min_const_generics`.
Some(parent_def_id.to_def_id())
}
// HACK(eddyb) this provides the correct generics when
// `feature(generic_const_expressions)` is enabled, so that const expressions
// used with const generics, e.g. `Foo<{N+1}>`, can work at all.
//
// Note that we do not supply the parent generics when using
// `min_const_generics`.
Some(parent_def_id.to_def_id())
} else {
let parent_node = tcx.hir().get_parent(hir_id);
match parent_node {
@ -115,11 +123,6 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
{
Some(parent_def_id.to_def_id())
}
Node::Variant(Variant { disr_expr: Some(constant), .. })
if constant.hir_id == hir_id =>
{
Some(parent_def_id.to_def_id())
}
Node::Expr(&Expr { kind: ExprKind::ConstBlock(_), .. }) => {
Some(tcx.typeck_root_def_id(def_id.to_def_id()))
}

View File

@ -1188,11 +1188,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
}
RibKind::ConstantItem(trivial, _) => {
let features = self.tcx.sess.features_untracked();
// HACK(min_const_generics): We currently only allow `N` or `{ N }`.
if !(trivial == ConstantHasGenerics::Yes
|| features.generic_const_exprs)
{
if let ConstantHasGenerics::No(cause) = trivial {
// HACK(min_const_generics): If we encounter `Self` in an anonymous
// constant we can't easily tell if it's generic at this stage, so
// we instead remember this and then enforce the self type to be
@ -1264,11 +1260,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
| RibKind::ForwardGenericParamBan => continue,
RibKind::ConstantItem(trivial, _) => {
let features = self.tcx.sess.features_untracked();
// HACK(min_const_generics): We currently only allow `N` or `{ N }`.
if !(trivial == ConstantHasGenerics::Yes
|| features.generic_const_exprs)
{
if let ConstantHasGenerics::No(cause) = trivial {
if let Some(span) = finalize {
self.report_error(
span,

View File

@ -66,6 +66,15 @@ enum IsRepeatExpr {
Yes,
}
/// Describes whether an `AnonConst` is a type level const arg or
/// some other form of anon const (i.e. inline consts or enum discriminants)
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
enum AnonConstKind {
EnumDiscriminant,
InlineConst,
ConstArg(IsRepeatExpr),
}
impl PatternSource {
fn descr(self) -> &'static str {
match self {
@ -105,7 +114,7 @@ pub(crate) enum HasGenericParams {
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub(crate) enum ConstantHasGenerics {
Yes,
No,
No(NoConstantGenericsReason),
}
impl ConstantHasGenerics {
@ -114,6 +123,27 @@ impl ConstantHasGenerics {
}
}
/// Reason for why an anon const is not allowed to reference generic parameters
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub(crate) enum NoConstantGenericsReason {
/// Const arguments are only allowed to use generic parameters when:
/// - `feature(generic_const_exprs)` is enabled
/// or
/// - the const argument is a sole const generic paramater, i.e. `foo::<{ N }>()`
///
/// If neither of the above are true then this is used as the cause.
NonTrivialConstArg,
/// Enum discriminants are not allowed to reference generic parameters ever, this
/// is used when an anon const is in the following position:
///
/// ```rust,compile_fail
/// enum Foo<const N: isize> {
/// Variant = { N }, // this anon const is not allowed to use generics
/// }
/// ```
IsEnumDiscriminant,
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub(crate) enum ConstantItemKind {
Const,
@ -273,15 +303,18 @@ enum LifetimeRibKind {
/// Signal we cannot find which should be the anonymous lifetime.
ElisionFailure,
/// FIXME(const_generics): This patches over an ICE caused by non-'static lifetimes in const
/// generics. We are disallowing this until we can decide on how we want to handle non-'static
/// lifetimes in const generics. See issue #74052 for discussion.
ConstGeneric,
/// This rib forbids usage of generic parameters inside of const parameter types.
///
/// While this is desirable to support eventually, it is difficult to do and so is
/// currently forbidden. See rust-lang/project-const-generics#28 for more info.
ConstParamTy,
/// Non-static lifetimes are prohibited in anonymous constants under `min_const_generics`.
/// This function will emit an error if `generic_const_exprs` is not enabled, the body
/// identified by `body_id` is an anonymous constant and `lifetime_ref` is non-static.
AnonConst,
/// Usage of generic parameters is forbidden in various positions for anon consts:
/// - const arguments when `generic_const_exprs` is not enabled
/// - enum discriminant values
///
/// This rib emits an error when a lifetime would resolve to a lifetime parameter.
ConcreteAnonConst(NoConstantGenericsReason),
/// This rib acts as a barrier to forbid reference to lifetimes of a parent item.
Item,
@ -648,13 +681,8 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
self.resolve_block(block);
self.parent_scope.macro_rules = old_macro_rules;
}
fn visit_anon_const(&mut self, constant: &'ast AnonConst) {
// We deal with repeat expressions explicitly in `resolve_expr`.
self.with_lifetime_rib(LifetimeRibKind::AnonConst, |this| {
this.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Infer), |this| {
this.resolve_anon_const(constant, IsRepeatExpr::No);
})
})
fn visit_anon_const(&mut self, _constant: &'ast AnonConst) {
bug!("encountered anon const without a manual call to `resolve_anon_const`");
}
fn visit_expr(&mut self, expr: &'ast Expr) {
self.resolve_expr(expr, None);
@ -676,7 +704,7 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
fn visit_ty(&mut self, ty: &'ast Ty) {
let prev = self.diagnostic_metadata.current_trait_object;
let prev_ty = self.diagnostic_metadata.current_type_path;
match ty.kind {
match &ty.kind {
TyKind::Ref(None, _) => {
// Elided lifetime in reference: we resolve as if there was some lifetime `'_` with
// NodeId `ty.id`.
@ -685,7 +713,7 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
self.resolve_elided_lifetime(ty.id, span);
visit::walk_ty(self, ty);
}
TyKind::Path(ref qself, ref path) => {
TyKind::Path(qself, path) => {
self.diagnostic_metadata.current_type_path = Some(ty);
self.smart_resolve_path(ty.id, &qself, path, PathSource::Type);
@ -730,11 +758,11 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
visit::walk_ty(self, ty);
self.lifetime_elision_candidates = candidates;
}
TyKind::TraitObject(ref bounds, ..) => {
TyKind::TraitObject(bounds, ..) => {
self.diagnostic_metadata.current_trait_object = Some(&bounds[..]);
visit::walk_ty(self, ty)
}
TyKind::BareFn(ref bare_fn) => {
TyKind::BareFn(bare_fn) => {
let span = ty.span.shrink_to_lo().to(bare_fn.decl_span.shrink_to_lo());
self.with_generic_param_rib(
&bare_fn.generic_params,
@ -769,6 +797,13 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
},
)
}
TyKind::Array(element_ty, length) => {
self.visit_ty(element_ty);
self.resolve_anon_const(length, AnonConstKind::ConstArg(IsRepeatExpr::No));
}
TyKind::Typeof(ct) => {
self.resolve_anon_const(ct, AnonConstKind::ConstArg(IsRepeatExpr::No))
}
_ => visit::walk_ty(self, ty),
}
self.diagnostic_metadata.current_trait_object = prev;
@ -994,36 +1029,25 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
// namespace first, and if that fails we try again in the value namespace. If
// resolution in the value namespace succeeds, we have an generic const argument on
// our hands.
if let TyKind::Path(ref qself, ref path) = ty.kind {
if let TyKind::Path(None, ref path) = ty.kind {
// We cannot disambiguate multi-segment paths right now as that requires type
// checking.
if path.segments.len() == 1 && path.segments[0].args.is_none() {
if path.is_potential_trivial_const_arg() {
let mut check_ns = |ns| {
self.maybe_resolve_ident_in_lexical_scope(path.segments[0].ident, ns)
.is_some()
};
if !check_ns(TypeNS) && check_ns(ValueNS) {
// This must be equivalent to `visit_anon_const`, but we cannot call it
// directly due to visitor lifetimes so we have to copy-paste some code.
//
// Note that we might not be inside of an repeat expression here,
// but considering that `IsRepeatExpr` is only relevant for
// non-trivial constants this is doesn't matter.
self.with_constant_rib(
IsRepeatExpr::No,
ConstantHasGenerics::Yes,
None,
self.resolve_anon_const_manual(
true,
AnonConstKind::ConstArg(IsRepeatExpr::No),
|this| {
this.smart_resolve_path(
ty.id,
qself,
&None,
path,
PathSource::Expr(None),
);
if let Some(ref qself) = *qself {
this.visit_ty(&qself.ty);
}
this.visit_path(path, ty.id);
},
);
@ -1037,7 +1061,9 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
self.visit_ty(ty);
}
GenericArg::Lifetime(lt) => self.visit_lifetime(lt, visit::LifetimeCtxt::GenericArg),
GenericArg::Const(ct) => self.visit_anon_const(ct),
GenericArg::Const(ct) => {
self.resolve_anon_const(ct, AnonConstKind::ConstArg(IsRepeatExpr::No))
}
}
self.diagnostic_metadata.currently_processing_generics = prev;
}
@ -1053,7 +1079,9 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
match constraint.kind {
AssocConstraintKind::Equality { ref term } => match term {
Term::Ty(ty) => self.visit_ty(ty),
Term::Const(c) => self.visit_anon_const(c),
Term::Const(c) => {
self.resolve_anon_const(c, AnonConstKind::ConstArg(IsRepeatExpr::No))
}
},
AssocConstraintKind::Bound { ref bounds } => {
walk_list!(self, visit_param_bound, bounds, BoundKind::Bound);
@ -1102,8 +1130,8 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
| LifetimeRibKind::AnonymousReportError
| LifetimeRibKind::Elided(_)
| LifetimeRibKind::ElisionFailure
| LifetimeRibKind::AnonConst
| LifetimeRibKind::ConstGeneric => {}
| LifetimeRibKind::ConcreteAnonConst(_)
| LifetimeRibKind::ConstParamTy => {}
}
}
}
@ -1164,7 +1192,7 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
InlineAsmOperand::Const { anon_const, .. } => {
// Although this is `DefKind::AnonConst`, it is allowed to reference outer
// generic parameters like an inline const.
self.resolve_inline_const(anon_const);
self.resolve_anon_const(anon_const, AnonConstKind::InlineConst);
}
InlineAsmOperand::Sym { sym } => self.visit_inline_asm_sym(sym),
}
@ -1188,6 +1216,10 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
visit::walk_variant(self, v)
}
fn visit_variant_discr(&mut self, discr: &'ast AnonConst) {
self.resolve_anon_const(discr, AnonConstKind::EnumDiscriminant);
}
fn visit_field_def(&mut self, f: &'ast FieldDef) {
self.resolve_doc_links(&f.attrs, MaybeExported::Ok(f.id));
visit::walk_field_def(self, f)
@ -1386,7 +1418,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
this.ribs[TypeNS].push(Rib::new(RibKind::ConstParamTy));
this.ribs[ValueNS].push(Rib::new(RibKind::ConstParamTy));
this.with_lifetime_rib(LifetimeRibKind::ConstGeneric, |this| {
this.with_lifetime_rib(LifetimeRibKind::ConstParamTy, |this| {
this.visit_ty(ty)
});
this.ribs[TypeNS].pop().unwrap();
@ -1395,9 +1427,10 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
if let Some(ref expr) = default {
this.ribs[TypeNS].push(forward_ty_ban_rib);
this.ribs[ValueNS].push(forward_const_ban_rib);
this.with_lifetime_rib(LifetimeRibKind::ConstGeneric, |this| {
this.resolve_anon_const(expr, IsRepeatExpr::No)
});
this.resolve_anon_const(
expr,
AnonConstKind::ConstArg(IsRepeatExpr::No),
);
forward_const_ban_rib = this.ribs[ValueNS].pop().unwrap();
forward_ty_ban_rib = this.ribs[TypeNS].pop().unwrap();
}
@ -1475,8 +1508,8 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
LifetimeUseSet::Many
}),
LifetimeRibKind::Generics { .. }
| LifetimeRibKind::ConstGeneric => None,
LifetimeRibKind::AnonConst => {
| LifetimeRibKind::ConstParamTy => None,
LifetimeRibKind::ConcreteAnonConst(_) => {
span_bug!(ident.span, "unexpected rib kind: {:?}", rib.kind)
}
})
@ -1495,7 +1528,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
match rib.kind {
LifetimeRibKind::Item => break,
LifetimeRibKind::ConstGeneric => {
LifetimeRibKind::ConstParamTy => {
self.emit_non_static_lt_in_const_generic_error(lifetime);
self.record_lifetime_res(
lifetime.id,
@ -1504,7 +1537,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
);
return;
}
LifetimeRibKind::AnonConst => {
LifetimeRibKind::ConcreteAnonConst(cause) => {
self.maybe_emit_forbidden_non_static_lifetime_error(lifetime);
self.record_lifetime_res(
lifetime.id,
@ -1604,9 +1637,9 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
return;
}
LifetimeRibKind::Item => break,
LifetimeRibKind::Generics { .. } | LifetimeRibKind::ConstGeneric => {}
LifetimeRibKind::AnonConst => {
// There is always an `Elided(LifetimeRes::Static)` inside an `AnonConst`.
LifetimeRibKind::Generics { .. } | LifetimeRibKind::ConstParamTy => {}
LifetimeRibKind::ConcreteAnonConst(_) => {
// There is always an `Elided(LifetimeRes::Infer)` inside an `AnonConst`.
span_bug!(lifetime.ident.span, "unexpected rib kind: {:?}", rib.kind)
}
}
@ -1826,9 +1859,9 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
self.report_missing_lifetime_specifiers(vec![missing_lifetime], None);
break;
}
LifetimeRibKind::Generics { .. } | LifetimeRibKind::ConstGeneric => {}
LifetimeRibKind::AnonConst => {
// There is always an `Elided(LifetimeRes::Static)` inside an `AnonConst`.
LifetimeRibKind::Generics { .. } | LifetimeRibKind::ConstParamTy => {}
LifetimeRibKind::ConcreteAnonConst(_) => {
// There is always an `Elided(LifetimeRes::Infer)` inside an `AnonConst`.
span_bug!(elided_lifetime_span, "unexpected rib kind: {:?}", rib.kind)
}
}
@ -2560,7 +2593,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
self.with_rib(ValueNS, kind, |this| this.with_rib(TypeNS, kind, f))
}
// HACK(min_const_generics,const_evaluatable_unchecked): We
// HACK(min_const_generics, generic_const_exprs): We
// want to keep allowing `[0; std::mem::size_of::<*mut T>()]`
// with a future compat lint for now. We do this by adding an
// additional special case for repeat expressions.
@ -2576,18 +2609,26 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
item: Option<(Ident, ConstantItemKind)>,
f: impl FnOnce(&mut Self),
) {
self.with_rib(ValueNS, RibKind::ConstantItem(may_use_generics, item), |this| {
this.with_rib(
TypeNS,
RibKind::ConstantItem(
may_use_generics.force_yes_if(is_repeat == IsRepeatExpr::Yes),
item,
),
|this| {
this.with_label_rib(RibKind::ConstantItem(may_use_generics, item), f);
},
)
});
let f = |this: &mut Self| {
this.with_rib(ValueNS, RibKind::ConstantItem(may_use_generics, item), |this| {
this.with_rib(
TypeNS,
RibKind::ConstantItem(
may_use_generics.force_yes_if(is_repeat == IsRepeatExpr::Yes),
item,
),
|this| {
this.with_label_rib(RibKind::ConstantItem(may_use_generics, item), f);
},
)
})
};
if let ConstantHasGenerics::No(cause) = may_use_generics {
self.with_lifetime_rib(LifetimeRibKind::ConcreteAnonConst(cause), f)
} else {
f(self)
}
}
fn with_current_self_type<T>(&mut self, self_type: &Ty, f: impl FnOnce(&mut Self) -> T) -> T {
@ -3924,24 +3965,54 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
debug!("(resolving block) leaving block");
}
fn resolve_anon_const(&mut self, constant: &'ast AnonConst, is_repeat: IsRepeatExpr) {
debug!("resolve_anon_const {:?} is_repeat: {:?}", constant, is_repeat);
self.with_constant_rib(
is_repeat,
if constant.value.is_potential_trivial_const_param() {
ConstantHasGenerics::Yes
} else {
ConstantHasGenerics::No
},
None,
|this| visit::walk_anon_const(this, constant),
fn resolve_anon_const(&mut self, constant: &'ast AnonConst, anon_const_kind: AnonConstKind) {
debug!(
"resolve_anon_const(constant: {:?}, anon_const_kind: {:?})",
constant, anon_const_kind
);
self.resolve_anon_const_manual(
constant.value.is_potential_trivial_const_arg(),
anon_const_kind,
|this| this.resolve_expr(&constant.value, None),
)
}
fn resolve_inline_const(&mut self, constant: &'ast AnonConst) {
debug!("resolve_anon_const {constant:?}");
self.with_constant_rib(IsRepeatExpr::No, ConstantHasGenerics::Yes, None, |this| {
visit::walk_anon_const(this, constant)
/// There are a few places that we need to resolve an anon const but we did not parse an
/// anon const so cannot provide an `&'ast AnonConst`. Right now this is just unbraced
/// const arguments that were parsed as type arguments, and `legact_const_generics` which
/// parse as normal function argument expressions. To avoid duplicating the code for resolving
/// an anon const we have this function which lets the caller manually call `resolve_expr` or
/// `smart_resolve_path`.
fn resolve_anon_const_manual(
&mut self,
is_trivial_const_arg: bool,
anon_const_kind: AnonConstKind,
resolve_expr: impl FnOnce(&mut Self),
) {
let is_repeat_expr = match anon_const_kind {
AnonConstKind::ConstArg(is_repeat_expr) => is_repeat_expr,
_ => IsRepeatExpr::No,
};
let may_use_generics = match anon_const_kind {
AnonConstKind::EnumDiscriminant => {
ConstantHasGenerics::No(NoConstantGenericsReason::IsEnumDiscriminant)
}
AnonConstKind::InlineConst => ConstantHasGenerics::Yes,
AnonConstKind::ConstArg(_) => {
if self.r.tcx.features().generic_const_exprs || is_trivial_const_arg {
ConstantHasGenerics::Yes
} else {
ConstantHasGenerics::No(NoConstantGenericsReason::NonTrivialConstArg)
}
}
};
self.with_constant_rib(is_repeat_expr, may_use_generics, None, |this| {
this.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Infer), |this| {
resolve_expr(this);
});
});
}
@ -4046,17 +4117,10 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
// Constant arguments need to be treated as AnonConst since
// that is how they will be later lowered to HIR.
if const_args.contains(&idx) {
self.with_constant_rib(
IsRepeatExpr::No,
if argument.is_potential_trivial_const_param() {
ConstantHasGenerics::Yes
} else {
ConstantHasGenerics::No
},
None,
|this| {
this.resolve_expr(argument, None);
},
self.resolve_anon_const_manual(
argument.is_potential_trivial_const_arg(),
AnonConstKind::ConstArg(IsRepeatExpr::No),
|this| this.resolve_expr(argument, None),
);
} else {
self.resolve_expr(argument, None);
@ -4115,14 +4179,10 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
}
ExprKind::Repeat(ref elem, ref ct) => {
self.visit_expr(elem);
self.with_lifetime_rib(LifetimeRibKind::AnonConst, |this| {
this.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Infer), |this| {
this.resolve_anon_const(ct, IsRepeatExpr::Yes)
})
});
self.resolve_anon_const(ct, AnonConstKind::ConstArg(IsRepeatExpr::Yes));
}
ExprKind::ConstBlock(ref ct) => {
self.resolve_inline_const(ct);
self.resolve_anon_const(ct, AnonConstKind::InlineConst);
}
ExprKind::Index(ref elem, ref idx) => {
self.resolve_expr(elem, Some(expr));