supply substs to anon consts in defaults

This commit is contained in:
lcnr 2021-04-18 16:43:43 +02:00
parent 312b4fdfd2
commit d3e0d2f53d
11 changed files with 62 additions and 71 deletions

View File

@ -513,7 +513,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
GenericParamDefKind::Const { has_default } => { GenericParamDefKind::Const { has_default } => {
let ty = tcx.at(self.span).type_of(param.def_id); let ty = tcx.at(self.span).type_of(param.def_id);
if !infer_args && has_default { if !infer_args && has_default {
tcx.const_param_default(param.def_id).into() tcx.const_param_default(param.def_id)
.subst_spanned(tcx, substs.unwrap(), Some(self.span))
.into()
} else { } else {
if infer_args { if infer_args {
self.astconv.ct_infer(ty, Some(param), self.span).into() self.astconv.ct_infer(ty, Some(param), self.span).into()

View File

@ -1446,7 +1446,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} }
GenericParamDefKind::Const { has_default, .. } => { GenericParamDefKind::Const { has_default, .. } => {
if !infer_args && has_default { if !infer_args && has_default {
tcx.const_param_default(param.def_id).into() tcx.const_param_default(param.def_id)
.subst_spanned(tcx, substs.unwrap(), Some(self.span))
.into()
} else { } else {
self.fcx.var_for_def(self.span, param) self.fcx.var_for_def(self.span, param)
} }

View File

@ -1316,13 +1316,13 @@ fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option<S
} }
} }
struct AnonConstInParamListDetector { struct AnonConstInParamTyDetector {
in_param_list: bool, in_param_ty: bool,
found_anon_const_in_list: bool, found_anon_const_in_param_ty: bool,
ct: HirId, ct: HirId,
} }
impl<'v> Visitor<'v> for AnonConstInParamListDetector { impl<'v> Visitor<'v> for AnonConstInParamTyDetector {
type Map = intravisit::ErasedMap<'v>; type Map = intravisit::ErasedMap<'v>;
fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> { fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
@ -1330,15 +1330,17 @@ impl<'v> Visitor<'v> for AnonConstInParamListDetector {
} }
fn visit_generic_param(&mut self, p: &'v hir::GenericParam<'v>) { fn visit_generic_param(&mut self, p: &'v hir::GenericParam<'v>) {
let prev = self.in_param_list; if let GenericParamKind::Const { ref ty, default: _ } = p.kind {
self.in_param_list = true; let prev = self.in_param_ty;
intravisit::walk_generic_param(self, p); self.in_param_ty = true;
self.in_param_list = prev; self.visit_ty(ty);
self.in_param_ty = prev;
}
} }
fn visit_anon_const(&mut self, c: &'v hir::AnonConst) { fn visit_anon_const(&mut self, c: &'v hir::AnonConst) {
if self.in_param_list && self.ct == c.hir_id { if self.in_param_ty && self.ct == c.hir_id {
self.found_anon_const_in_list = true; self.found_anon_const_in_param_ty = true;
} else { } else {
intravisit::walk_anon_const(self, c) intravisit::walk_anon_const(self, c)
} }
@ -1366,27 +1368,24 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
let parent_id = tcx.hir().get_parent_item(hir_id); let parent_id = tcx.hir().get_parent_item(hir_id);
let parent_def_id = tcx.hir().local_def_id(parent_id); let parent_def_id = tcx.hir().local_def_id(parent_id);
let mut in_param_list = false; let mut in_param_ty = false;
for (_parent, node) in tcx.hir().parent_iter(hir_id) { for (_parent, node) in tcx.hir().parent_iter(hir_id) {
if let Some(generics) = node.generics() { if let Some(generics) = node.generics() {
let mut visitor = AnonConstInParamListDetector { let mut visitor = AnonConstInParamTyDetector {
in_param_list: false, in_param_ty: false,
found_anon_const_in_list: false, found_anon_const_in_param_ty: false,
ct: hir_id, ct: hir_id,
}; };
visitor.visit_generics(generics); visitor.visit_generics(generics);
in_param_list = visitor.found_anon_const_in_list; in_param_ty = visitor.found_anon_const_in_param_ty;
break; break;
} }
} }
if in_param_list { if in_param_ty {
// We do not allow generic parameters in anon consts if we are inside // We do not allow generic parameters in anon consts if we are inside
// of a param list. // of a const parameter type, e.g. `struct Foo<const N: usize, const M: [u8; N]>` is not allowed.
//
// This affects both default type bindings, e.g. `struct<T, U = [u8; std::mem::size_of::<T>()]>(T, U)`,
// and the types of const parameters, e.g. `struct V<const N: usize, const M: [u8; N]>();`.
None None
} else if tcx.lazy_normalization() { } else if tcx.lazy_normalization() {
// HACK(eddyb) this provides the correct generics when // HACK(eddyb) this provides the correct generics when

View File

@ -1,16 +1,18 @@
error[E0277]: the size for values of type `T` cannot be known at compilation time error: constant expression depends on a generic parameter
--> $DIR/complex-generic-default-expr.rs:9:62 --> $DIR/complex-generic-default-expr.rs:6:34
|
LL | struct Foo<const N: usize, const M: usize = { N + 1 }>;
| ^
|
= note: this may fail depending on what value the parameter takes
error: constant expression depends on a generic parameter
--> $DIR/complex-generic-default-expr.rs:10:21
| |
LL | struct Bar<T, const TYPE_SIZE: usize = { std::mem::size_of::<T>() }>(T); 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 { = note: this may fail depending on what value the parameter takes
| - required by this bound in `std::mem::size_of`
error: aborting due to previous error error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0277`.

View File

@ -1,5 +1,5 @@
error: generic parameters may not be used in const operations error: generic parameters may not be used in const operations
--> $DIR/complex-generic-default-expr.rs:10:47 --> $DIR/complex-generic-default-expr.rs:6:47
| |
LL | struct Foo<const N: usize, const M: usize = { N + 1 }>; LL | struct Foo<const N: usize, const M: usize = { N + 1 }>;
| ^ cannot perform const operation using `N` | ^ cannot perform const operation using `N`
@ -8,7 +8,7 @@ LL | struct Foo<const N: usize, const M: usize = { N + 1 }>;
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
error: generic parameters may not be used in const operations error: generic parameters may not be used in const operations
--> $DIR/complex-generic-default-expr.rs:13:62 --> $DIR/complex-generic-default-expr.rs:10:62
| |
LL | struct Bar<T, const TYPE_SIZE: usize = { std::mem::size_of::<T>() }>(T); LL | struct Bar<T, const TYPE_SIZE: usize = { std::mem::size_of::<T>() }>(T);
| ^ cannot perform const operation using `T` | ^ cannot perform const operation using `T`

View File

@ -1,17 +1,14 @@
// revisions: min // revisions: full min
// FIXME(const_generics): add the `full` revision,
// currently causes an ICE as we don't supply substs to
// anon consts in the parameter listing, as that would
// cause that anon const to reference itself.
#![cfg_attr(full, feature(const_generics))] #![cfg_attr(full, feature(const_generics))]
#![feature(const_generics_defaults)] #![feature(const_generics_defaults)]
#![allow(incomplete_features)] #![allow(incomplete_features)]
struct Foo<const N: usize, const M: usize = { N + 1 }>; struct Foo<const N: usize, const M: usize = { N + 1 }>;
//[min]~^ ERROR generic parameters may not be used in const operations //[full]~^ ERROR constant expression depends on a generic parameter
//[min]~^^ ERROR generic parameters may not be used in const operations
struct Bar<T, const TYPE_SIZE: usize = { std::mem::size_of::<T>() }>(T); struct Bar<T, const TYPE_SIZE: usize = { std::mem::size_of::<T>() }>(T);
//[min]~^ ERROR generic parameters may not be used in const operations //[full]~^ ERROR constant expression depends on a generic parameter
//[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
fn main() {} fn main() {}

View File

@ -8,7 +8,16 @@ fn foo<const N: usize>() -> Foo<N> {
Foo(x, x) Foo(x, x)
} }
// To check that we actually apply the correct substs for const param defaults.
fn concrete_foo() -> Foo<13> {
Foo(Default::default(), Default::default())
}
fn main() { fn main() {
let val = foo::<13>(); let val = foo::<13>();
assert_eq!(val.0, val.1); assert_eq!(val.0, val.1);
let val = concrete_foo();
assert_eq!(val.0, val.1);
} }

View File

@ -1,10 +1,6 @@
// run-pass // run-pass
#![feature(const_generics_defaults)] #![feature(const_generics_defaults)]
#![allow(incomplete_features)] #![allow(incomplete_features)]
// FIXME(const_generics_defaults): while we can allow this,
// we probably won't easily allow this with more complex const operations.
//
// So we have to make a conscious decision here when stabilizing a relaxed parameter ordering.
struct Foo<const N: usize, T = [u8; N]>(T); struct Foo<const N: usize, T = [u8; N]>(T);
impl<const N: usize> Foo<N> { impl<const N: usize> Foo<N> {

View File

@ -1,5 +1,5 @@
error: generic parameters with a default must be trailing error: generic parameters with a default must be trailing
--> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:10:12 --> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:8:12
| |
LL | struct Bar<T = [u8; N], const N: usize>(T); LL | struct Bar<T = [u8; N], const N: usize>(T);
| ^ | ^
@ -7,25 +7,11 @@ 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 = note: using type defaults and const parameters in the same parameter list is currently not permitted
error[E0128]: generic parameters with a default cannot use forward declared identifiers error[E0128]: generic parameters with a default cannot use forward declared identifiers
--> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:10:21 --> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:8:21
| |
LL | struct Bar<T = [u8; N], const N: usize>(T); LL | struct Bar<T = [u8; N], const N: usize>(T);
| ^ defaulted generic parameters cannot be forward declared | ^ defaulted generic parameters cannot be forward declared
error[E0277]: the size for values of type `T` cannot be known at compilation time error: aborting due to 2 previous errors
--> $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 For more information about this error, try `rustc --explain E0128`.
Some errors have detailed explanations: E0128, E0277.
For more information about an error, try `rustc --explain E0128`.

View File

@ -1,5 +1,5 @@
error: generic parameters with a default must be trailing error: generic parameters with a default must be trailing
--> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:10:12 --> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:8:12
| |
LL | struct Bar<T = [u8; N], const N: usize>(T); LL | struct Bar<T = [u8; N], const N: usize>(T);
| ^ | ^
@ -7,7 +7,7 @@ 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 = note: using type defaults and const parameters in the same parameter list is currently not permitted
error: generic parameters may not be used in const operations error: generic parameters may not be used in const operations
--> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:6:44 --> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:5:44
| |
LL | struct Foo<T, U = [u8; std::mem::size_of::<T>()]>(T, U); LL | struct Foo<T, U = [u8; std::mem::size_of::<T>()]>(T, U);
| ^ cannot perform const operation using `T` | ^ cannot perform const operation using `T`
@ -16,7 +16,7 @@ LL | struct Foo<T, U = [u8; std::mem::size_of::<T>()]>(T, U);
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
error[E0128]: generic parameters with a default cannot use forward declared identifiers error[E0128]: generic parameters with a default cannot use forward declared identifiers
--> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:10:21 --> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:8:21
| |
LL | struct Bar<T = [u8; N], const N: usize>(T); LL | struct Bar<T = [u8; N], const N: usize>(T);
| ^ defaulted generic parameters cannot be forward declared | ^ defaulted generic parameters cannot be forward declared

View File

@ -1,11 +1,9 @@
// revisions: full min // revisions: full min
#![cfg_attr(full, feature(const_generics))] #![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))] #![cfg_attr(full, allow(incomplete_features))]
struct Foo<T, U = [u8; std::mem::size_of::<T>()]>(T, U); struct Foo<T, U = [u8; std::mem::size_of::<T>()]>(T, U);
//[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
//[min]~^^ ERROR generic parameters may not be used in const operations
struct Bar<T = [u8; N], const N: usize>(T); struct Bar<T = [u8; N], const N: usize>(T);
//~^ ERROR generic parameters with a default cannot use forward declared identifiers //~^ ERROR generic parameters with a default cannot use forward declared identifiers