fix name resolution for param defaults
This commit is contained in:
parent
d7c3386414
commit
259a368e9e
15 changed files with 141 additions and 104 deletions
|
@ -472,17 +472,6 @@ impl<'a> Resolver<'a> {
|
|||
);
|
||||
err
|
||||
}
|
||||
ResolutionError::ParamInAnonConstInTyDefault(name) => {
|
||||
let mut err = self.session.struct_span_err(
|
||||
span,
|
||||
"constant values inside of type parameter defaults must not depend on generic parameters",
|
||||
);
|
||||
err.span_label(
|
||||
span,
|
||||
format!("the anonymous constant must not depend on the parameter `{}`", name),
|
||||
);
|
||||
err
|
||||
}
|
||||
ResolutionError::ParamInNonTrivialAnonConst { name, is_type } => {
|
||||
let mut err = self.session.struct_span_err(
|
||||
span,
|
||||
|
|
|
@ -555,18 +555,23 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
|
|||
// provide previous type parameters as they're built. We
|
||||
// put all the parameters on the ban list and then remove
|
||||
// them one by one as they are processed and become available.
|
||||
let mut default_ban_rib = Rib::new(ForwardGenericParamBanRibKind);
|
||||
let mut found_default = false;
|
||||
default_ban_rib.bindings.extend(generics.params.iter().filter_map(
|
||||
|param| match param.kind {
|
||||
GenericParamKind::Type { default: Some(_), .. }
|
||||
| GenericParamKind::Const { default: Some(_), .. } => {
|
||||
found_default = true;
|
||||
Some((Ident::with_dummy_span(param.ident.name), Res::Err))
|
||||
let mut forward_ty_ban_rib = Rib::new(ForwardGenericParamBanRibKind);
|
||||
let mut forward_const_ban_rib = Rib::new(ForwardGenericParamBanRibKind);
|
||||
for param in generics.params.iter() {
|
||||
match param.kind {
|
||||
GenericParamKind::Type { .. } => {
|
||||
forward_ty_ban_rib
|
||||
.bindings
|
||||
.insert(Ident::with_dummy_span(param.ident.name), Res::Err);
|
||||
}
|
||||
_ => None,
|
||||
},
|
||||
));
|
||||
GenericParamKind::Const { .. } => {
|
||||
forward_const_ban_rib
|
||||
.bindings
|
||||
.insert(Ident::with_dummy_span(param.ident.name), Res::Err);
|
||||
}
|
||||
GenericParamKind::Lifetime => {}
|
||||
}
|
||||
}
|
||||
|
||||
// rust-lang/rust#61631: The type `Self` is essentially
|
||||
// another type parameter. For ADTs, we consider it
|
||||
|
@ -579,7 +584,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
|
|||
// such as in the case of `trait Add<Rhs = Self>`.)
|
||||
if self.diagnostic_metadata.current_self_item.is_some() {
|
||||
// (`Some` if + only if we are in ADT's generics.)
|
||||
default_ban_rib.bindings.insert(Ident::with_dummy_span(kw::SelfUpper), Res::Err);
|
||||
forward_ty_ban_rib.bindings.insert(Ident::with_dummy_span(kw::SelfUpper), Res::Err);
|
||||
}
|
||||
|
||||
for param in &generics.params {
|
||||
|
@ -591,32 +596,38 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
|
|||
}
|
||||
|
||||
if let Some(ref ty) = default {
|
||||
self.ribs[TypeNS].push(default_ban_rib);
|
||||
self.with_rib(ValueNS, ForwardGenericParamBanRibKind, |this| {
|
||||
// HACK: We use an empty `ForwardGenericParamBanRibKind` here which
|
||||
// is only used to forbid the use of const parameters inside of
|
||||
// type defaults.
|
||||
//
|
||||
// While the rib name doesn't really fit here, it does allow us to use the same
|
||||
// code for both const and type parameters.
|
||||
this.visit_ty(ty);
|
||||
});
|
||||
default_ban_rib = self.ribs[TypeNS].pop().unwrap();
|
||||
self.ribs[TypeNS].push(forward_ty_ban_rib);
|
||||
self.ribs[ValueNS].push(forward_const_ban_rib);
|
||||
self.visit_ty(ty);
|
||||
forward_const_ban_rib = self.ribs[ValueNS].pop().unwrap();
|
||||
forward_ty_ban_rib = self.ribs[TypeNS].pop().unwrap();
|
||||
}
|
||||
|
||||
// Allow all following defaults to refer to this type parameter.
|
||||
default_ban_rib.bindings.remove(&Ident::with_dummy_span(param.ident.name));
|
||||
forward_ty_ban_rib.bindings.remove(&Ident::with_dummy_span(param.ident.name));
|
||||
}
|
||||
GenericParamKind::Const { ref ty, kw_span: _, default: _ } => {
|
||||
// FIXME(const_generics_defaults): handle `default` value here
|
||||
for bound in ¶m.bounds {
|
||||
self.visit_param_bound(bound);
|
||||
}
|
||||
GenericParamKind::Const { ref ty, kw_span: _, ref default } => {
|
||||
// Const parameters can't have param bounds.
|
||||
assert!(param.bounds.is_empty());
|
||||
|
||||
self.ribs[TypeNS].push(Rib::new(ConstParamTyRibKind));
|
||||
self.ribs[ValueNS].push(Rib::new(ConstParamTyRibKind));
|
||||
self.visit_ty(ty);
|
||||
self.ribs[TypeNS].pop().unwrap();
|
||||
self.ribs[ValueNS].pop().unwrap();
|
||||
|
||||
if let Some(ref expr) = default {
|
||||
self.ribs[TypeNS].push(forward_ty_ban_rib);
|
||||
self.ribs[ValueNS].push(forward_const_ban_rib);
|
||||
self.visit_anon_const(expr);
|
||||
forward_const_ban_rib = self.ribs[ValueNS].pop().unwrap();
|
||||
forward_ty_ban_rib = self.ribs[TypeNS].pop().unwrap();
|
||||
}
|
||||
|
||||
// Allow all following defaults to refer to this const parameter.
|
||||
forward_const_ban_rib
|
||||
.bindings
|
||||
.remove(&Ident::with_dummy_span(param.ident.name));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -239,8 +239,6 @@ enum ResolutionError<'a> {
|
|||
ForwardDeclaredTyParam, // FIXME(const_generics_defaults)
|
||||
/// ERROR E0770: the type of const parameters must not depend on other generic parameters.
|
||||
ParamInTyOfConstParam(Symbol),
|
||||
/// constant values inside of type parameter defaults must not depend on generic parameters.
|
||||
ParamInAnonConstInTyDefault(Symbol),
|
||||
/// generic parameters must not be used inside const evaluations.
|
||||
///
|
||||
/// This error is only emitted when using `min_const_generics`.
|
||||
|
@ -2672,26 +2670,18 @@ impl<'a> Resolver<'a> {
|
|||
}
|
||||
}
|
||||
Res::Def(DefKind::TyParam, _) | Res::SelfTy(..) => {
|
||||
let mut in_ty_param_default = false;
|
||||
for rib in ribs {
|
||||
let has_generic_params = match rib.kind {
|
||||
let has_generic_params: HasGenericParams = match rib.kind {
|
||||
NormalRibKind
|
||||
| ClosureOrAsyncRibKind
|
||||
| AssocItemRibKind
|
||||
| ModuleRibKind(..)
|
||||
| MacroDefinition(..) => {
|
||||
| MacroDefinition(..)
|
||||
| ForwardGenericParamBanRibKind => {
|
||||
// Nothing to do. Continue.
|
||||
continue;
|
||||
}
|
||||
|
||||
// We only forbid constant items if we are inside of type defaults,
|
||||
// for example `struct Foo<T, U = [u8; std::mem::size_of::<T>()]>`
|
||||
ForwardGenericParamBanRibKind => {
|
||||
// FIXME(const_generic_defaults): we may need to distinguish between
|
||||
// being in type parameter defaults and const parameter defaults
|
||||
in_ty_param_default = true;
|
||||
continue;
|
||||
}
|
||||
ConstantItemRibKind(trivial, _) => {
|
||||
let features = self.session.features_untracked();
|
||||
// HACK(min_const_generics): We currently only allow `N` or `{ N }`.
|
||||
|
@ -2720,19 +2710,7 @@ impl<'a> Resolver<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
if in_ty_param_default {
|
||||
if record_used {
|
||||
self.report_error(
|
||||
span,
|
||||
ResolutionError::ParamInAnonConstInTyDefault(
|
||||
rib_ident.name,
|
||||
),
|
||||
);
|
||||
}
|
||||
return Res::Err;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// This was an attempt to use a type parameter outside its scope.
|
||||
|
@ -2770,23 +2748,15 @@ impl<'a> Resolver<'a> {
|
|||
ribs.next();
|
||||
}
|
||||
|
||||
let mut in_ty_param_default = false;
|
||||
for rib in ribs {
|
||||
let has_generic_params = match rib.kind {
|
||||
NormalRibKind
|
||||
| ClosureOrAsyncRibKind
|
||||
| AssocItemRibKind
|
||||
| ModuleRibKind(..)
|
||||
| MacroDefinition(..) => continue,
|
||||
| MacroDefinition(..)
|
||||
| ForwardGenericParamBanRibKind => continue,
|
||||
|
||||
// We only forbid constant items if we are inside of type defaults,
|
||||
// for example `struct Foo<T, U = [u8; std::mem::size_of::<T>()]>`
|
||||
ForwardGenericParamBanRibKind => {
|
||||
// FIXME(const_generic_defaults): we may need to distinguish between
|
||||
// being in type parameter defaults and const parameter defaults
|
||||
in_ty_param_default = true;
|
||||
continue;
|
||||
}
|
||||
ConstantItemRibKind(trivial, _) => {
|
||||
let features = self.session.features_untracked();
|
||||
// HACK(min_const_generics): We currently only allow `N` or `{ N }`.
|
||||
|
@ -2808,19 +2778,7 @@ impl<'a> Resolver<'a> {
|
|||
return Res::Err;
|
||||
}
|
||||
|
||||
if in_ty_param_default {
|
||||
if record_used {
|
||||
self.report_error(
|
||||
span,
|
||||
ResolutionError::ParamInAnonConstInTyDefault(
|
||||
rib_ident.name,
|
||||
),
|
||||
);
|
||||
}
|
||||
return Res::Err;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
ItemRibKind(has_generic_params) => has_generic_params,
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
#![feature(const_generics, const_generics_defaults)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
struct Foo<const N: usize, const M: usize = { N + 1 }>;
|
||||
|
||||
struct Bar<T, const TYPE_SIZE: usize = { std::mem::size_of::<T>() }>(T);
|
||||
//~^ ERROR the size for values of type `T` cannot be known at compilation time
|
||||
|
||||
fn main() {}
|
|
@ -0,0 +1,16 @@
|
|||
error[E0277]: the size for values of type `T` cannot be known at compilation time
|
||||
--> $DIR/complex-generic-default-expr.rs:6:62
|
||||
|
|
||||
LL | struct Bar<T, const TYPE_SIZE: usize = { std::mem::size_of::<T>() }>(T);
|
||||
| - ^ doesn't have a size known at compile-time
|
||||
| |
|
||||
| this type parameter needs to be `std::marker::Sized`
|
||||
|
|
||||
::: $SRC_DIR/core/src/mem/mod.rs:LL:COL
|
||||
|
|
||||
LL | pub const fn size_of<T>() -> usize {
|
||||
| - required by this bound in `std::mem::size_of`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
9
src/test/ui/const-generics/defaults/default-on-impl.rs
Normal file
9
src/test/ui/const-generics/defaults/default-on-impl.rs
Normal file
|
@ -0,0 +1,9 @@
|
|||
#![feature(const_generics, const_generics_defaults)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
struct Foo<const N: usize>;
|
||||
|
||||
impl<const N: usize = 1> Foo<N> {}
|
||||
//~^ ERROR defaults for const parameters are only allowed
|
||||
|
||||
fn main() {}
|
|
@ -0,0 +1,8 @@
|
|||
error: defaults for const parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions
|
||||
--> $DIR/default-on-impl.rs:6:12
|
||||
|
|
||||
LL | impl<const N: usize = 1> Foo<N> {}
|
||||
| ^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
|
@ -10,4 +10,5 @@ trait Foo<const KIND: bool = true> {}
|
|||
|
||||
fn foo<const SIZE: usize = 5>() {}
|
||||
|
||||
struct Range<const FROM: usize = 0, const LEN: usize = 0, const TO: usize = {FROM + LEN}>;
|
||||
struct Range<const FROM: usize = 0, const LEN: usize = 0, const TO: usize = FROM>;
|
||||
|
||||
|
|
|
@ -17,4 +17,5 @@ trait Foo<const KIND : bool = true> { }
|
|||
fn foo<const SIZE : usize = 5>() { }
|
||||
|
||||
struct Range<const FROM : usize = 0, const LEN : usize = 0, const TO : usize =
|
||||
{ FROM + LEN }>;
|
||||
FROM>;
|
||||
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
// check-pass
|
||||
#![feature(const_generics, const_generics_defaults)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
struct N;
|
||||
|
||||
struct Foo<const N: usize = 1, T = N>(T);
|
||||
|
||||
impl Foo {
|
||||
fn new() -> Self {
|
||||
Foo(N)
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let Foo::<1, N>(N) = Foo::new();
|
||||
}
|
|
@ -6,17 +6,26 @@ LL | struct Bar<T = [u8; N], const N: usize>(T);
|
|||
|
|
||||
= note: using type defaults and const parameters in the same parameter list is currently not permitted
|
||||
|
||||
error: constant values inside of type parameter defaults must not depend on generic parameters
|
||||
--> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:6:44
|
||||
|
|
||||
LL | struct Foo<T, U = [u8; std::mem::size_of::<T>()]>(T, U);
|
||||
| ^ the anonymous constant must not depend on the parameter `T`
|
||||
|
||||
error: constant values inside of type parameter defaults must not depend on generic parameters
|
||||
error[E0128]: generic parameters with a default cannot use forward declared identifiers
|
||||
--> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:11:21
|
||||
|
|
||||
LL | struct Bar<T = [u8; N], const N: usize>(T);
|
||||
| ^ the anonymous constant must not depend on the parameter `N`
|
||||
| ^ defaulted generic parameters cannot be forward declared
|
||||
|
||||
error[E0277]: the size for values of type `T` cannot be known at compilation time
|
||||
--> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:6:44
|
||||
|
|
||||
LL | struct Foo<T, U = [u8; std::mem::size_of::<T>()]>(T, U);
|
||||
| - ^ doesn't have a size known at compile-time
|
||||
| |
|
||||
| this type parameter needs to be `std::marker::Sized`
|
||||
|
|
||||
::: $SRC_DIR/core/src/mem/mod.rs:LL:COL
|
||||
|
|
||||
LL | pub const fn size_of<T>() -> usize {
|
||||
| - required by this bound in `std::mem::size_of`
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0128, E0277.
|
||||
For more information about an error, try `rustc --explain E0128`.
|
||||
|
|
|
@ -15,11 +15,12 @@ LL | struct Foo<T, U = [u8; std::mem::size_of::<T>()]>(T, U);
|
|||
= note: type parameters may not be used in const expressions
|
||||
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
|
||||
|
||||
error: constant values inside of type parameter defaults must not depend on generic parameters
|
||||
error[E0128]: generic parameters with a default cannot use forward declared identifiers
|
||||
--> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:11:21
|
||||
|
|
||||
LL | struct Bar<T = [u8; N], const N: usize>(T);
|
||||
| ^ the anonymous constant must not depend on the parameter `N`
|
||||
| ^ defaulted generic parameters cannot be forward declared
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0128`.
|
||||
|
|
|
@ -4,12 +4,12 @@
|
|||
#![cfg_attr(full, allow(incomplete_features))]
|
||||
|
||||
struct Foo<T, U = [u8; std::mem::size_of::<T>()]>(T, U);
|
||||
//[full]~^ ERROR constant values inside of type parameter defaults
|
||||
//[full]~^ ERROR the size for values of type `T` cannot be known at compilation time
|
||||
//[min]~^^ ERROR generic parameters may not be used in const operations
|
||||
|
||||
// FIXME(const_generics_defaults): We still don't know how to deal with type defaults.
|
||||
struct Bar<T = [u8; N], const N: usize>(T);
|
||||
//~^ ERROR constant values inside of type parameter defaults
|
||||
//~^ ERROR generic parameters with a default cannot use forward declared identifiers
|
||||
//~| ERROR generic parameters with a default
|
||||
|
||||
fn main() {}
|
||||
|
|
|
@ -5,5 +5,6 @@ struct Vec<A = Heap, T>(A, T);
|
|||
|
||||
struct Foo<A, B = Vec<C>, C>(A, B, C);
|
||||
//~^ ERROR generic parameters with a default must be trailing
|
||||
//~| ERROR generic parameters with a default cannot use
|
||||
|
||||
fn main() {}
|
||||
|
|
|
@ -10,5 +10,12 @@ error: generic parameters with a default must be trailing
|
|||
LL | struct Foo<A, B = Vec<C>, C>(A, B, C);
|
||||
| ^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
error[E0128]: generic parameters with a default cannot use forward declared identifiers
|
||||
--> $DIR/generic-non-trailing-defaults.rs:6:23
|
||||
|
|
||||
LL | struct Foo<A, B = Vec<C>, C>(A, B, C);
|
||||
| ^ defaulted generic parameters cannot be forward declared
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0128`.
|
||||
|
|
Loading…
Add table
Reference in a new issue