misc nameres changes for anon consts
This commit is contained in:
parent
4a18324a4d
commit
442617c046
7 changed files with 202 additions and 133 deletions
|
@ -120,6 +120,12 @@ impl Path {
|
||||||
pub fn is_global(&self) -> bool {
|
pub fn is_global(&self) -> bool {
|
||||||
!self.segments.is_empty() && self.segments[0].ident.name == kw::PathRoot
|
!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.
|
/// 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
|
/// If this is not the case, name resolution does not resolve `N` when using
|
||||||
/// `min_const_generics` as more complex expressions are not supported.
|
/// `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
|
let this = if let ExprKind::Block(block, None) = &self.kind
|
||||||
&& block.stmts.len() == 1
|
&& block.stmts.len() == 1
|
||||||
&& let StmtKind::Expr(expr) = &block.stmts[0].kind
|
&& let StmtKind::Expr(expr) = &block.stmts[0].kind
|
||||||
|
@ -1165,8 +1173,7 @@ impl Expr {
|
||||||
};
|
};
|
||||||
|
|
||||||
if let ExprKind::Path(None, path) = &this.kind
|
if let ExprKind::Path(None, path) = &this.kind
|
||||||
&& path.segments.len() == 1
|
&& path.is_potential_trivial_const_arg()
|
||||||
&& path.segments[0].args.is_none()
|
|
||||||
{
|
{
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -188,6 +188,9 @@ pub trait Visitor<'ast>: Sized {
|
||||||
fn visit_variant(&mut self, v: &'ast Variant) {
|
fn visit_variant(&mut self, v: &'ast Variant) {
|
||||||
walk_variant(self, v)
|
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) {
|
fn visit_label(&mut self, label: &'ast Label) {
|
||||||
walk_label(self, label)
|
walk_label(self, label)
|
||||||
}
|
}
|
||||||
|
@ -380,7 +383,7 @@ where
|
||||||
visitor.visit_ident(variant.ident);
|
visitor.visit_ident(variant.ident);
|
||||||
visitor.visit_vis(&variant.vis);
|
visitor.visit_vis(&variant.vis);
|
||||||
visitor.visit_variant_data(&variant.data);
|
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);
|
walk_list!(visitor, visit_attribute, &variant.attrs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1190,13 +1190,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
// parsing. We try to resolve that ambiguity by attempting resolution in both the
|
// 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
|
// type and value namespaces. If we resolved the path in the value namespace, we
|
||||||
// transform it into a generic const argument.
|
// transform it into a generic const argument.
|
||||||
TyKind::Path(qself, path) => {
|
TyKind::Path(None, path) => {
|
||||||
if let Some(res) = self
|
if let Some(res) = self
|
||||||
.resolver
|
.resolver
|
||||||
.get_partial_res(ty.id)
|
.get_partial_res(ty.id)
|
||||||
.and_then(|partial_res| partial_res.full_res())
|
.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!(
|
debug!(
|
||||||
"lower_generic_arg: Lowering type argument as const argument: {:?}",
|
"lower_generic_arg: Lowering type argument as const argument: {:?}",
|
||||||
ty,
|
ty,
|
||||||
|
@ -1218,7 +1220,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
|
|
||||||
let path_expr = Expr {
|
let path_expr = Expr {
|
||||||
id: ty.id,
|
id: ty.id,
|
||||||
kind: ExprKind::Path(qself.clone(), path.clone()),
|
kind: ExprKind::Path(None, path.clone()),
|
||||||
span,
|
span,
|
||||||
attrs: AttrVec::new(),
|
attrs: AttrVec::new(),
|
||||||
tokens: None,
|
tokens: None,
|
||||||
|
|
|
@ -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
|
A non-`'static` lifetime was used in a const generic. This is currently not
|
||||||
allowed.
|
allowed.
|
||||||
|
|
||||||
Erroneous code example:
|
Erroneous code example:
|
||||||
|
|
||||||
```compile_fail,E0771
|
```compile_fail,E0770
|
||||||
#![feature(adt_const_params)]
|
#![feature(adt_const_params)]
|
||||||
|
|
||||||
fn function_with_str<'a, const STRING: &'a str>() {} // error!
|
fn function_with_str<'a, const STRING: &'a str>() {} // error!
|
||||||
|
|
|
@ -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.
|
// of a const parameter type, e.g. `struct Foo<const N: usize, const M: [u8; N]>` is not allowed.
|
||||||
None
|
None
|
||||||
} else if tcx.lazy_normalization() {
|
} 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:
|
// If the def_id we are calling generics_of on is an anon ct default i.e:
|
||||||
//
|
//
|
||||||
// struct Foo<const N: usize = { .. }>;
|
// 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_self: generics.has_self,
|
||||||
has_late_bound_regions: generics.has_late_bound_regions,
|
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 {
|
} else {
|
||||||
let parent_node = tcx.hir().get_parent(hir_id);
|
let parent_node = tcx.hir().get_parent(hir_id);
|
||||||
match parent_node {
|
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())
|
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(_), .. }) => {
|
Node::Expr(&Expr { kind: ExprKind::ConstBlock(_), .. }) => {
|
||||||
Some(tcx.typeck_root_def_id(def_id.to_def_id()))
|
Some(tcx.typeck_root_def_id(def_id.to_def_id()))
|
||||||
}
|
}
|
||||||
|
|
|
@ -1188,11 +1188,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
RibKind::ConstantItem(trivial, _) => {
|
RibKind::ConstantItem(trivial, _) => {
|
||||||
let features = self.tcx.sess.features_untracked();
|
if let ConstantHasGenerics::No(cause) = trivial {
|
||||||
// HACK(min_const_generics): We currently only allow `N` or `{ N }`.
|
|
||||||
if !(trivial == ConstantHasGenerics::Yes
|
|
||||||
|| features.generic_const_exprs)
|
|
||||||
{
|
|
||||||
// HACK(min_const_generics): If we encounter `Self` in an anonymous
|
// 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
|
// 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
|
// 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::ForwardGenericParamBan => continue,
|
||||||
|
|
||||||
RibKind::ConstantItem(trivial, _) => {
|
RibKind::ConstantItem(trivial, _) => {
|
||||||
let features = self.tcx.sess.features_untracked();
|
if let ConstantHasGenerics::No(cause) = trivial {
|
||||||
// HACK(min_const_generics): We currently only allow `N` or `{ N }`.
|
|
||||||
if !(trivial == ConstantHasGenerics::Yes
|
|
||||||
|| features.generic_const_exprs)
|
|
||||||
{
|
|
||||||
if let Some(span) = finalize {
|
if let Some(span) = finalize {
|
||||||
self.report_error(
|
self.report_error(
|
||||||
span,
|
span,
|
||||||
|
|
|
@ -66,6 +66,15 @@ enum IsRepeatExpr {
|
||||||
Yes,
|
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 {
|
impl PatternSource {
|
||||||
fn descr(self) -> &'static str {
|
fn descr(self) -> &'static str {
|
||||||
match self {
|
match self {
|
||||||
|
@ -105,7 +114,7 @@ pub(crate) enum HasGenericParams {
|
||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||||
pub(crate) enum ConstantHasGenerics {
|
pub(crate) enum ConstantHasGenerics {
|
||||||
Yes,
|
Yes,
|
||||||
No,
|
No(NoConstantGenericsReason),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ConstantHasGenerics {
|
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)]
|
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||||
pub(crate) enum ConstantItemKind {
|
pub(crate) enum ConstantItemKind {
|
||||||
Const,
|
Const,
|
||||||
|
@ -273,15 +303,18 @@ enum LifetimeRibKind {
|
||||||
/// Signal we cannot find which should be the anonymous lifetime.
|
/// Signal we cannot find which should be the anonymous lifetime.
|
||||||
ElisionFailure,
|
ElisionFailure,
|
||||||
|
|
||||||
/// FIXME(const_generics): This patches over an ICE caused by non-'static lifetimes in const
|
/// This rib forbids usage of generic parameters inside of const parameter types.
|
||||||
/// 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.
|
/// While this is desirable to support eventually, it is difficult to do and so is
|
||||||
ConstGeneric,
|
/// 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`.
|
/// Usage of generic parameters is forbidden in various positions for anon consts:
|
||||||
/// This function will emit an error if `generic_const_exprs` is not enabled, the body
|
/// - const arguments when `generic_const_exprs` is not enabled
|
||||||
/// identified by `body_id` is an anonymous constant and `lifetime_ref` is non-static.
|
/// - enum discriminant values
|
||||||
AnonConst,
|
///
|
||||||
|
/// 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.
|
/// This rib acts as a barrier to forbid reference to lifetimes of a parent item.
|
||||||
Item,
|
Item,
|
||||||
|
@ -648,13 +681,8 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
|
||||||
self.resolve_block(block);
|
self.resolve_block(block);
|
||||||
self.parent_scope.macro_rules = old_macro_rules;
|
self.parent_scope.macro_rules = old_macro_rules;
|
||||||
}
|
}
|
||||||
fn visit_anon_const(&mut self, constant: &'ast AnonConst) {
|
fn visit_anon_const(&mut self, _constant: &'ast AnonConst) {
|
||||||
// We deal with repeat expressions explicitly in `resolve_expr`.
|
bug!("encountered anon const without a manual call to `resolve_anon_const`");
|
||||||
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_expr(&mut self, expr: &'ast Expr) {
|
fn visit_expr(&mut self, expr: &'ast Expr) {
|
||||||
self.resolve_expr(expr, None);
|
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) {
|
fn visit_ty(&mut self, ty: &'ast Ty) {
|
||||||
let prev = self.diagnostic_metadata.current_trait_object;
|
let prev = self.diagnostic_metadata.current_trait_object;
|
||||||
let prev_ty = self.diagnostic_metadata.current_type_path;
|
let prev_ty = self.diagnostic_metadata.current_type_path;
|
||||||
match ty.kind {
|
match &ty.kind {
|
||||||
TyKind::Ref(None, _) => {
|
TyKind::Ref(None, _) => {
|
||||||
// Elided lifetime in reference: we resolve as if there was some lifetime `'_` with
|
// Elided lifetime in reference: we resolve as if there was some lifetime `'_` with
|
||||||
// NodeId `ty.id`.
|
// 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);
|
self.resolve_elided_lifetime(ty.id, span);
|
||||||
visit::walk_ty(self, ty);
|
visit::walk_ty(self, ty);
|
||||||
}
|
}
|
||||||
TyKind::Path(ref qself, ref path) => {
|
TyKind::Path(qself, path) => {
|
||||||
self.diagnostic_metadata.current_type_path = Some(ty);
|
self.diagnostic_metadata.current_type_path = Some(ty);
|
||||||
self.smart_resolve_path(ty.id, &qself, path, PathSource::Type);
|
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);
|
visit::walk_ty(self, ty);
|
||||||
self.lifetime_elision_candidates = candidates;
|
self.lifetime_elision_candidates = candidates;
|
||||||
}
|
}
|
||||||
TyKind::TraitObject(ref bounds, ..) => {
|
TyKind::TraitObject(bounds, ..) => {
|
||||||
self.diagnostic_metadata.current_trait_object = Some(&bounds[..]);
|
self.diagnostic_metadata.current_trait_object = Some(&bounds[..]);
|
||||||
visit::walk_ty(self, ty)
|
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());
|
let span = ty.span.shrink_to_lo().to(bare_fn.decl_span.shrink_to_lo());
|
||||||
self.with_generic_param_rib(
|
self.with_generic_param_rib(
|
||||||
&bare_fn.generic_params,
|
&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),
|
_ => visit::walk_ty(self, ty),
|
||||||
}
|
}
|
||||||
self.diagnostic_metadata.current_trait_object = prev;
|
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
|
// 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
|
// resolution in the value namespace succeeds, we have an generic const argument on
|
||||||
// our hands.
|
// 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
|
// We cannot disambiguate multi-segment paths right now as that requires type
|
||||||
// checking.
|
// checking.
|
||||||
if path.segments.len() == 1 && path.segments[0].args.is_none() {
|
if path.is_potential_trivial_const_arg() {
|
||||||
let mut check_ns = |ns| {
|
let mut check_ns = |ns| {
|
||||||
self.maybe_resolve_ident_in_lexical_scope(path.segments[0].ident, ns)
|
self.maybe_resolve_ident_in_lexical_scope(path.segments[0].ident, ns)
|
||||||
.is_some()
|
.is_some()
|
||||||
};
|
};
|
||||||
if !check_ns(TypeNS) && check_ns(ValueNS) {
|
if !check_ns(TypeNS) && check_ns(ValueNS) {
|
||||||
// This must be equivalent to `visit_anon_const`, but we cannot call it
|
self.resolve_anon_const_manual(
|
||||||
// directly due to visitor lifetimes so we have to copy-paste some code.
|
true,
|
||||||
//
|
AnonConstKind::ConstArg(IsRepeatExpr::No),
|
||||||
// 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,
|
|
||||||
|this| {
|
|this| {
|
||||||
this.smart_resolve_path(
|
this.smart_resolve_path(
|
||||||
ty.id,
|
ty.id,
|
||||||
qself,
|
&None,
|
||||||
path,
|
path,
|
||||||
PathSource::Expr(None),
|
PathSource::Expr(None),
|
||||||
);
|
);
|
||||||
|
|
||||||
if let Some(ref qself) = *qself {
|
|
||||||
this.visit_ty(&qself.ty);
|
|
||||||
}
|
|
||||||
this.visit_path(path, ty.id);
|
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);
|
self.visit_ty(ty);
|
||||||
}
|
}
|
||||||
GenericArg::Lifetime(lt) => self.visit_lifetime(lt, visit::LifetimeCtxt::GenericArg),
|
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;
|
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 {
|
match constraint.kind {
|
||||||
AssocConstraintKind::Equality { ref term } => match term {
|
AssocConstraintKind::Equality { ref term } => match term {
|
||||||
Term::Ty(ty) => self.visit_ty(ty),
|
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 } => {
|
AssocConstraintKind::Bound { ref bounds } => {
|
||||||
walk_list!(self, visit_param_bound, bounds, BoundKind::Bound);
|
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::AnonymousReportError
|
||||||
| LifetimeRibKind::Elided(_)
|
| LifetimeRibKind::Elided(_)
|
||||||
| LifetimeRibKind::ElisionFailure
|
| LifetimeRibKind::ElisionFailure
|
||||||
| LifetimeRibKind::AnonConst
|
| LifetimeRibKind::ConcreteAnonConst(_)
|
||||||
| LifetimeRibKind::ConstGeneric => {}
|
| LifetimeRibKind::ConstParamTy => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1164,7 +1192,7 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
|
||||||
InlineAsmOperand::Const { anon_const, .. } => {
|
InlineAsmOperand::Const { anon_const, .. } => {
|
||||||
// Although this is `DefKind::AnonConst`, it is allowed to reference outer
|
// Although this is `DefKind::AnonConst`, it is allowed to reference outer
|
||||||
// generic parameters like an inline const.
|
// 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),
|
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)
|
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) {
|
fn visit_field_def(&mut self, f: &'ast FieldDef) {
|
||||||
self.resolve_doc_links(&f.attrs, MaybeExported::Ok(f.id));
|
self.resolve_doc_links(&f.attrs, MaybeExported::Ok(f.id));
|
||||||
visit::walk_field_def(self, f)
|
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[TypeNS].push(Rib::new(RibKind::ConstParamTy));
|
||||||
this.ribs[ValueNS].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.visit_ty(ty)
|
||||||
});
|
});
|
||||||
this.ribs[TypeNS].pop().unwrap();
|
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 {
|
if let Some(ref expr) = default {
|
||||||
this.ribs[TypeNS].push(forward_ty_ban_rib);
|
this.ribs[TypeNS].push(forward_ty_ban_rib);
|
||||||
this.ribs[ValueNS].push(forward_const_ban_rib);
|
this.ribs[ValueNS].push(forward_const_ban_rib);
|
||||||
this.with_lifetime_rib(LifetimeRibKind::ConstGeneric, |this| {
|
this.resolve_anon_const(
|
||||||
this.resolve_anon_const(expr, IsRepeatExpr::No)
|
expr,
|
||||||
});
|
AnonConstKind::ConstArg(IsRepeatExpr::No),
|
||||||
|
);
|
||||||
forward_const_ban_rib = this.ribs[ValueNS].pop().unwrap();
|
forward_const_ban_rib = this.ribs[ValueNS].pop().unwrap();
|
||||||
forward_ty_ban_rib = this.ribs[TypeNS].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
|
LifetimeUseSet::Many
|
||||||
}),
|
}),
|
||||||
LifetimeRibKind::Generics { .. }
|
LifetimeRibKind::Generics { .. }
|
||||||
| LifetimeRibKind::ConstGeneric => None,
|
| LifetimeRibKind::ConstParamTy => None,
|
||||||
LifetimeRibKind::AnonConst => {
|
LifetimeRibKind::ConcreteAnonConst(_) => {
|
||||||
span_bug!(ident.span, "unexpected rib kind: {:?}", rib.kind)
|
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 {
|
match rib.kind {
|
||||||
LifetimeRibKind::Item => break,
|
LifetimeRibKind::Item => break,
|
||||||
LifetimeRibKind::ConstGeneric => {
|
LifetimeRibKind::ConstParamTy => {
|
||||||
self.emit_non_static_lt_in_const_generic_error(lifetime);
|
self.emit_non_static_lt_in_const_generic_error(lifetime);
|
||||||
self.record_lifetime_res(
|
self.record_lifetime_res(
|
||||||
lifetime.id,
|
lifetime.id,
|
||||||
|
@ -1504,7 +1537,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
LifetimeRibKind::AnonConst => {
|
LifetimeRibKind::ConcreteAnonConst(cause) => {
|
||||||
self.maybe_emit_forbidden_non_static_lifetime_error(lifetime);
|
self.maybe_emit_forbidden_non_static_lifetime_error(lifetime);
|
||||||
self.record_lifetime_res(
|
self.record_lifetime_res(
|
||||||
lifetime.id,
|
lifetime.id,
|
||||||
|
@ -1604,9 +1637,9 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
LifetimeRibKind::Item => break,
|
LifetimeRibKind::Item => break,
|
||||||
LifetimeRibKind::Generics { .. } | LifetimeRibKind::ConstGeneric => {}
|
LifetimeRibKind::Generics { .. } | LifetimeRibKind::ConstParamTy => {}
|
||||||
LifetimeRibKind::AnonConst => {
|
LifetimeRibKind::ConcreteAnonConst(_) => {
|
||||||
// There is always an `Elided(LifetimeRes::Static)` inside an `AnonConst`.
|
// There is always an `Elided(LifetimeRes::Infer)` inside an `AnonConst`.
|
||||||
span_bug!(lifetime.ident.span, "unexpected rib kind: {:?}", rib.kind)
|
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);
|
self.report_missing_lifetime_specifiers(vec![missing_lifetime], None);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
LifetimeRibKind::Generics { .. } | LifetimeRibKind::ConstGeneric => {}
|
LifetimeRibKind::Generics { .. } | LifetimeRibKind::ConstParamTy => {}
|
||||||
LifetimeRibKind::AnonConst => {
|
LifetimeRibKind::ConcreteAnonConst(_) => {
|
||||||
// There is always an `Elided(LifetimeRes::Static)` inside an `AnonConst`.
|
// There is always an `Elided(LifetimeRes::Infer)` inside an `AnonConst`.
|
||||||
span_bug!(elided_lifetime_span, "unexpected rib kind: {:?}", rib.kind)
|
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))
|
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>()]`
|
// want to keep allowing `[0; std::mem::size_of::<*mut T>()]`
|
||||||
// with a future compat lint for now. We do this by adding an
|
// with a future compat lint for now. We do this by adding an
|
||||||
// additional special case for repeat expressions.
|
// 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)>,
|
item: Option<(Ident, ConstantItemKind)>,
|
||||||
f: impl FnOnce(&mut Self),
|
f: impl FnOnce(&mut Self),
|
||||||
) {
|
) {
|
||||||
self.with_rib(ValueNS, RibKind::ConstantItem(may_use_generics, item), |this| {
|
let f = |this: &mut Self| {
|
||||||
this.with_rib(
|
this.with_rib(ValueNS, RibKind::ConstantItem(may_use_generics, item), |this| {
|
||||||
TypeNS,
|
this.with_rib(
|
||||||
RibKind::ConstantItem(
|
TypeNS,
|
||||||
may_use_generics.force_yes_if(is_repeat == IsRepeatExpr::Yes),
|
RibKind::ConstantItem(
|
||||||
item,
|
may_use_generics.force_yes_if(is_repeat == IsRepeatExpr::Yes),
|
||||||
),
|
item,
|
||||||
|this| {
|
),
|
||||||
this.with_label_rib(RibKind::ConstantItem(may_use_generics, item), f);
|
|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 {
|
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");
|
debug!("(resolving block) leaving block");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_anon_const(&mut self, constant: &'ast AnonConst, is_repeat: IsRepeatExpr) {
|
fn resolve_anon_const(&mut self, constant: &'ast AnonConst, anon_const_kind: AnonConstKind) {
|
||||||
debug!("resolve_anon_const {:?} is_repeat: {:?}", constant, is_repeat);
|
debug!(
|
||||||
self.with_constant_rib(
|
"resolve_anon_const(constant: {:?}, anon_const_kind: {:?})",
|
||||||
is_repeat,
|
constant, anon_const_kind
|
||||||
if constant.value.is_potential_trivial_const_param() {
|
|
||||||
ConstantHasGenerics::Yes
|
|
||||||
} else {
|
|
||||||
ConstantHasGenerics::No
|
|
||||||
},
|
|
||||||
None,
|
|
||||||
|this| visit::walk_anon_const(this, constant),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
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) {
|
/// There are a few places that we need to resolve an anon const but we did not parse an
|
||||||
debug!("resolve_anon_const {constant:?}");
|
/// anon const so cannot provide an `&'ast AnonConst`. Right now this is just unbraced
|
||||||
self.with_constant_rib(IsRepeatExpr::No, ConstantHasGenerics::Yes, None, |this| {
|
/// const arguments that were parsed as type arguments, and `legact_const_generics` which
|
||||||
visit::walk_anon_const(this, constant)
|
/// 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
|
// Constant arguments need to be treated as AnonConst since
|
||||||
// that is how they will be later lowered to HIR.
|
// that is how they will be later lowered to HIR.
|
||||||
if const_args.contains(&idx) {
|
if const_args.contains(&idx) {
|
||||||
self.with_constant_rib(
|
self.resolve_anon_const_manual(
|
||||||
IsRepeatExpr::No,
|
argument.is_potential_trivial_const_arg(),
|
||||||
if argument.is_potential_trivial_const_param() {
|
AnonConstKind::ConstArg(IsRepeatExpr::No),
|
||||||
ConstantHasGenerics::Yes
|
|this| this.resolve_expr(argument, None),
|
||||||
} else {
|
|
||||||
ConstantHasGenerics::No
|
|
||||||
},
|
|
||||||
None,
|
|
||||||
|this| {
|
|
||||||
this.resolve_expr(argument, None);
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
self.resolve_expr(argument, None);
|
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) => {
|
ExprKind::Repeat(ref elem, ref ct) => {
|
||||||
self.visit_expr(elem);
|
self.visit_expr(elem);
|
||||||
self.with_lifetime_rib(LifetimeRibKind::AnonConst, |this| {
|
self.resolve_anon_const(ct, AnonConstKind::ConstArg(IsRepeatExpr::Yes));
|
||||||
this.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Infer), |this| {
|
|
||||||
this.resolve_anon_const(ct, IsRepeatExpr::Yes)
|
|
||||||
})
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
ExprKind::ConstBlock(ref ct) => {
|
ExprKind::ConstBlock(ref ct) => {
|
||||||
self.resolve_inline_const(ct);
|
self.resolve_anon_const(ct, AnonConstKind::InlineConst);
|
||||||
}
|
}
|
||||||
ExprKind::Index(ref elem, ref idx) => {
|
ExprKind::Index(ref elem, ref idx) => {
|
||||||
self.resolve_expr(elem, Some(expr));
|
self.resolve_expr(elem, Some(expr));
|
||||||
|
|
Loading…
Add table
Reference in a new issue