From 05dcb7874a5a8c84fe943dcbae12010ba5a40c25 Mon Sep 17 00:00:00 2001 From: Ellen Date: Wed, 23 Jun 2021 18:18:32 +0100 Subject: [PATCH 1/6] Dont provide all parent generics to cgdefaults --- compiler/rustc_middle/src/ty/consts.rs | 33 +++++++++++++++++-- .../defaults/cec-build-subst-ice.rs | 10 ++++++ .../defaults/cec-build-subst-ice.stderr | 12 +++++++ 3 files changed, 53 insertions(+), 2 deletions(-) create mode 100644 src/test/ui/const-generics/defaults/cec-build-subst-ice.rs create mode 100644 src/test/ui/const-generics/defaults/cec-build-subst-ice.stderr diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index c78151271c171..16ec935ba1ad0 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -85,7 +85,10 @@ impl<'tcx> Const<'tcx> { _ => expr, }; - use hir::{def::DefKind::ConstParam, def::Res, ExprKind, Path, QPath}; + use hir::{ + def::DefKind::ConstParam, def::Res, ExprKind, GenericParam, GenericParamKind, Node, + Path, QPath, + }; let val = match expr.kind { ExprKind::Path(QPath::Resolved(_, &Path { res: Res::Def(ConstParam, def_id), .. })) => { // Find the name and index of the const parameter by indexing the generics of @@ -100,7 +103,33 @@ impl<'tcx> Const<'tcx> { } _ => ty::ConstKind::Unevaluated(ty::Unevaluated { def: def.to_global(), - substs: InternalSubsts::identity_for_item(tcx, def.did.to_def_id()), + substs: { + let ct_hir_id = tcx.hir().local_def_id_to_hir_id(def.did); + let parent_id = tcx.hir().get_parent_node(ct_hir_id); + match tcx.hir().get(parent_id) { + // If this anon ct is a cg default we should only provide non-fwd declared params + // https://github.com/rust-lang/rust/issues/83938 + Node::GenericParam(GenericParam { + hir_id: param_id, + kind: GenericParamKind::Const { .. }, + .. + }) => { + let item_id = tcx.hir().get_parent_node(*param_id); + let item_def_id = tcx.hir().local_def_id(item_id); + let generics = tcx.generics_of(item_def_id.to_def_id()); + let param_def = tcx.hir().local_def_id(*param_id).to_def_id(); + let param_def_idx = generics.param_def_id_to_index[¶m_def]; + let substs = generics + .params + .iter() + .map(|param| tcx.mk_param_from_def(param)) + .take(param_def_idx as usize) + .collect::>(); + tcx.intern_substs(&substs) + } + _ => InternalSubsts::identity_for_item(tcx, def.did.to_def_id()), + } + }, promoted: None, }), }; diff --git a/src/test/ui/const-generics/defaults/cec-build-subst-ice.rs b/src/test/ui/const-generics/defaults/cec-build-subst-ice.rs new file mode 100644 index 0000000000000..d43e136d5748a --- /dev/null +++ b/src/test/ui/const-generics/defaults/cec-build-subst-ice.rs @@ -0,0 +1,10 @@ +#![feature(const_evaluatable_checked, const_generics, const_generics_defaults)] +#![allow(incomplete_features)] + +pub struct Bar; +pub fn foo() -> Bar { + loop {} +} +//~^ error: unconstrained generic constant + +fn main() {} diff --git a/src/test/ui/const-generics/defaults/cec-build-subst-ice.stderr b/src/test/ui/const-generics/defaults/cec-build-subst-ice.stderr new file mode 100644 index 0000000000000..0508007412c7d --- /dev/null +++ b/src/test/ui/const-generics/defaults/cec-build-subst-ice.stderr @@ -0,0 +1,12 @@ +error: unconstrained generic constant + --> $DIR/cec-build-subst-ice.rs:5:34 + | +LL | pub struct Bar; + | --------- required by this bound in `Bar` +LL | pub fn foo() -> Bar { loop {} } + | ^^^^^^^ + | + = help: try adding a `where` bound using this expression: `where [(); { N + 1 }]:` + +error: aborting due to previous error + From b44be27999d26ee5f6712704e5d0535c2ea08e70 Mon Sep 17 00:00:00 2001 From: Ellen Date: Sat, 10 Jul 2021 14:53:37 +0100 Subject: [PATCH 2/6] Moves changes to explicit_preds_of/inferred_outlives_of/generics_of --- compiler/rustc_middle/src/ty/consts.rs | 33 +------------- compiler/rustc_typeck/src/collect.rs | 44 ++++++++++++++++++- compiler/rustc_typeck/src/outlives/mod.rs | 16 +++++++ .../defaults/cec-build-subst-ice.stderr | 11 ++++- 4 files changed, 71 insertions(+), 33 deletions(-) diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index 16ec935ba1ad0..c78151271c171 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -85,10 +85,7 @@ impl<'tcx> Const<'tcx> { _ => expr, }; - use hir::{ - def::DefKind::ConstParam, def::Res, ExprKind, GenericParam, GenericParamKind, Node, - Path, QPath, - }; + use hir::{def::DefKind::ConstParam, def::Res, ExprKind, Path, QPath}; let val = match expr.kind { ExprKind::Path(QPath::Resolved(_, &Path { res: Res::Def(ConstParam, def_id), .. })) => { // Find the name and index of the const parameter by indexing the generics of @@ -103,33 +100,7 @@ impl<'tcx> Const<'tcx> { } _ => ty::ConstKind::Unevaluated(ty::Unevaluated { def: def.to_global(), - substs: { - let ct_hir_id = tcx.hir().local_def_id_to_hir_id(def.did); - let parent_id = tcx.hir().get_parent_node(ct_hir_id); - match tcx.hir().get(parent_id) { - // If this anon ct is a cg default we should only provide non-fwd declared params - // https://github.com/rust-lang/rust/issues/83938 - Node::GenericParam(GenericParam { - hir_id: param_id, - kind: GenericParamKind::Const { .. }, - .. - }) => { - let item_id = tcx.hir().get_parent_node(*param_id); - let item_def_id = tcx.hir().local_def_id(item_id); - let generics = tcx.generics_of(item_def_id.to_def_id()); - let param_def = tcx.hir().local_def_id(*param_id).to_def_id(); - let param_def_idx = generics.param_def_id_to_index[¶m_def]; - let substs = generics - .params - .iter() - .map(|param| tcx.mk_param_from_def(param)) - .take(param_def_idx as usize) - .collect::>(); - tcx.intern_substs(&substs) - } - _ => InternalSubsts::identity_for_item(tcx, def.did.to_def_id()), - } - }, + substs: InternalSubsts::identity_for_item(tcx, def.did.to_def_id()), promoted: None, }), }; diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index 583ba9392f062..924a0b8410a12 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -1441,6 +1441,32 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics { // of a const parameter type, e.g. `struct Foo` is not allowed. None } else if tcx.lazy_normalization() { + // Only provide backwards declared generics to cg defaults (#83938) + if let Node::GenericParam(GenericParam { + hir_id: param_id, + kind: GenericParamKind::Const { .. }, + .. + }) = tcx.hir().get(tcx.hir().get_parent_node(hir_id)) + { + let item_id = tcx.hir().get_parent_node(*param_id); + let item_def_id = tcx.hir().local_def_id(item_id); + let generics = tcx.generics_of(item_def_id.to_def_id()); + let param_def = tcx.hir().local_def_id(*param_id).to_def_id(); + let param_def_idx = generics.param_def_id_to_index[¶m_def]; + let params = generics.params[..param_def_idx as usize].to_owned(); + let param_def_id_to_index = + params.iter().map(|param| (param.def_id, param.index)).collect(); + + return ty::Generics { + parent: generics.parent, + parent_count: generics.parent_count, + params, + param_def_id_to_index, + has_self: generics.has_self, + has_late_bound_regions: generics.has_late_bound_regions, + }; + } + // HACK(eddyb) this provides the correct generics when // `feature(const_generics)` is enabled, so that const expressions // used with const generics, e.g. `Foo<{N+1}>`, can work at all. @@ -2359,7 +2385,8 @@ fn trait_explicit_predicates_and_bounds( } fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicates<'_> { - if let DefKind::Trait = tcx.def_kind(def_id) { + let def_kind = tcx.def_kind(def_id); + if let DefKind::Trait = def_kind { // Remove bounds on associated types from the predicates, they will be // returned by `explicit_item_bounds`. let predicates_and_bounds = tcx.trait_explicit_predicates_and_bounds(def_id.expect_local()); @@ -2404,6 +2431,21 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat } } } else { + if matches!(def_kind, DefKind::AnonConst) && tcx.lazy_normalization() { + // Provide predicates of parent item of cg defaults manually + // as generics_of doesn't return a parent for the generics + let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); + if let Node::GenericParam(hir::GenericParam { + hir_id: param_id, + kind: hir::GenericParamKind::Const { .. }, + .. + }) = tcx.hir().get(tcx.hir().get_parent_node(hir_id)) + { + let item_id = tcx.hir().get_parent_node(*param_id); + let item_def_id = tcx.hir().local_def_id(item_id).to_def_id(); + return tcx.explicit_predicates_of(item_def_id); + } + } gather_explicit_predicates_of(tcx, def_id) } } diff --git a/compiler/rustc_typeck/src/outlives/mod.rs b/compiler/rustc_typeck/src/outlives/mod.rs index d7eb31c2abef5..c2f8525f7aba6 100644 --- a/compiler/rustc_typeck/src/outlives/mod.rs +++ b/compiler/rustc_typeck/src/outlives/mod.rs @@ -20,6 +20,22 @@ pub fn provide(providers: &mut Providers) { fn inferred_outlives_of(tcx: TyCtxt<'_>, item_def_id: DefId) -> &[(ty::Predicate<'_>, Span)] { let id = tcx.hir().local_def_id_to_hir_id(item_def_id.expect_local()); + if matches!(tcx.def_kind(item_def_id), hir::def::DefKind::AnonConst) && tcx.lazy_normalization() + { + // Provide inferred outlive preds of parent item of cg defaults manually + // as generics_of doesn't return a parent for the generics + if let Node::GenericParam(hir::GenericParam { + hir_id: param_id, + kind: hir::GenericParamKind::Const { .. }, + .. + }) = tcx.hir().get(tcx.hir().get_parent_node(id)) + { + let item_id = tcx.hir().get_parent_node(*param_id); + let item_def_id = tcx.hir().local_def_id(item_id).to_def_id(); + return tcx.inferred_outlives_of(item_def_id); + } + } + match tcx.hir().get(id) { Node::Item(item) => match item.kind { hir::ItemKind::Struct(..) | hir::ItemKind::Enum(..) | hir::ItemKind::Union(..) => { diff --git a/src/test/ui/const-generics/defaults/cec-build-subst-ice.stderr b/src/test/ui/const-generics/defaults/cec-build-subst-ice.stderr index 0508007412c7d..30a01d48c4c8d 100644 --- a/src/test/ui/const-generics/defaults/cec-build-subst-ice.stderr +++ b/src/test/ui/const-generics/defaults/cec-build-subst-ice.stderr @@ -8,5 +8,14 @@ LL | pub fn foo() -> Bar { loop {} } | = help: try adding a `where` bound using this expression: `where [(); { N + 1 }]:` -error: aborting due to previous error +error: unconstrained generic constant + --> $DIR/cec-build-subst-ice.rs:15:8 + | +LL | type Alias = [T; NP]; + | ---------- required by this bound in `Alias::{constant#0}` +LL | fn alias(_: [T; N], _: T) +LL | -> Alias + | ^^^^^^^^^^^ + | + = help: try adding a `where` bound using this expression: `where [(); {N+1usize}]:` From e276b860e25a900037dd964b5c4b42afe1187abc Mon Sep 17 00:00:00 2001 From: Ellen Date: Sat, 10 Jul 2021 17:38:39 +0100 Subject: [PATCH 3/6] redo tests --- .../defaults/cec-build-subst-ice.rs | 10 -------- .../defaults/cec-build-subst-ice.stderr | 21 ---------------- .../defaults/cec-concrete-default.rs | 14 +++++++++++ .../defaults/cec-concrete-default.stderr | 12 ++++++++++ .../cec-generic-default-mismatched-types.rs | 16 +++++++++++++ ...ec-generic-default-mismatched-types.stderr | 12 ++++++++++ .../defaults/cec-generic-default.rs | 24 +++++++++++++++++++ .../defaults/cec-generic-default.stderr | 18 ++++++++++++++ 8 files changed, 96 insertions(+), 31 deletions(-) delete mode 100644 src/test/ui/const-generics/defaults/cec-build-subst-ice.rs delete mode 100644 src/test/ui/const-generics/defaults/cec-build-subst-ice.stderr create mode 100644 src/test/ui/const-generics/defaults/cec-concrete-default.rs create mode 100644 src/test/ui/const-generics/defaults/cec-concrete-default.stderr create mode 100644 src/test/ui/const-generics/defaults/cec-generic-default-mismatched-types.rs create mode 100644 src/test/ui/const-generics/defaults/cec-generic-default-mismatched-types.stderr create mode 100644 src/test/ui/const-generics/defaults/cec-generic-default.rs create mode 100644 src/test/ui/const-generics/defaults/cec-generic-default.stderr diff --git a/src/test/ui/const-generics/defaults/cec-build-subst-ice.rs b/src/test/ui/const-generics/defaults/cec-build-subst-ice.rs deleted file mode 100644 index d43e136d5748a..0000000000000 --- a/src/test/ui/const-generics/defaults/cec-build-subst-ice.rs +++ /dev/null @@ -1,10 +0,0 @@ -#![feature(const_evaluatable_checked, const_generics, const_generics_defaults)] -#![allow(incomplete_features)] - -pub struct Bar; -pub fn foo() -> Bar { - loop {} -} -//~^ error: unconstrained generic constant - -fn main() {} diff --git a/src/test/ui/const-generics/defaults/cec-build-subst-ice.stderr b/src/test/ui/const-generics/defaults/cec-build-subst-ice.stderr deleted file mode 100644 index 30a01d48c4c8d..0000000000000 --- a/src/test/ui/const-generics/defaults/cec-build-subst-ice.stderr +++ /dev/null @@ -1,21 +0,0 @@ -error: unconstrained generic constant - --> $DIR/cec-build-subst-ice.rs:5:34 - | -LL | pub struct Bar; - | --------- required by this bound in `Bar` -LL | pub fn foo() -> Bar { loop {} } - | ^^^^^^^ - | - = help: try adding a `where` bound using this expression: `where [(); { N + 1 }]:` - -error: unconstrained generic constant - --> $DIR/cec-build-subst-ice.rs:15:8 - | -LL | type Alias = [T; NP]; - | ---------- required by this bound in `Alias::{constant#0}` -LL | fn alias(_: [T; N], _: T) -LL | -> Alias - | ^^^^^^^^^^^ - | - = help: try adding a `where` bound using this expression: `where [(); {N+1usize}]:` - diff --git a/src/test/ui/const-generics/defaults/cec-concrete-default.rs b/src/test/ui/const-generics/defaults/cec-concrete-default.rs new file mode 100644 index 0000000000000..c2a41cf2ad7dd --- /dev/null +++ b/src/test/ui/const-generics/defaults/cec-concrete-default.rs @@ -0,0 +1,14 @@ +#![feature(const_generics, const_evaluatable_checked, const_generics_defaults)] +#![allow(incomplete_features)] + +struct Foo; +fn no_constraining() -> Foo<10> { + Foo::<10, 11> +} + +pub fn different_than_default() -> Foo<10> { + Foo::<10, 12> + //~^ error: mismatched types +} + +fn main() {} diff --git a/src/test/ui/const-generics/defaults/cec-concrete-default.stderr b/src/test/ui/const-generics/defaults/cec-concrete-default.stderr new file mode 100644 index 0000000000000..090e507b7f34e --- /dev/null +++ b/src/test/ui/const-generics/defaults/cec-concrete-default.stderr @@ -0,0 +1,12 @@ +error[E0308]: mismatched types + --> $DIR/cec-concrete-default.rs:10:5 + | +LL | Foo::<10, 12> + | ^^^^^^^^^^^^^ expected `11_usize`, found `12_usize` + | + = note: expected type `11_usize` + found type `12_usize` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/const-generics/defaults/cec-generic-default-mismatched-types.rs b/src/test/ui/const-generics/defaults/cec-generic-default-mismatched-types.rs new file mode 100644 index 0000000000000..15822dfac1c5a --- /dev/null +++ b/src/test/ui/const-generics/defaults/cec-generic-default-mismatched-types.rs @@ -0,0 +1,16 @@ +#![feature(const_generics, const_evaluatable_checked, const_generics_defaults)] +#![allow(incomplete_features)] + +struct Foo; +fn should_unify() -> Foo where [(); { N + 1 }]: { + Foo:: +} +pub fn shouldnt_unify() -> Foo +where + [(); { N + 1 }]:, + [(); { N + 2 }]:, { + Foo:: + //~^ error: mismatched types +} + +fn main() {} diff --git a/src/test/ui/const-generics/defaults/cec-generic-default-mismatched-types.stderr b/src/test/ui/const-generics/defaults/cec-generic-default-mismatched-types.stderr new file mode 100644 index 0000000000000..f97fc26a07321 --- /dev/null +++ b/src/test/ui/const-generics/defaults/cec-generic-default-mismatched-types.stderr @@ -0,0 +1,12 @@ +error[E0308]: mismatched types + --> $DIR/cec-generic-default-mismatched-types.rs:12:5 + | +LL | Foo:: + | ^^^^^^^^^^^^^^^^^^^ expected `{ N + 1 }`, found `{ N + 2 }` + | + = note: expected type `{ N + 1 }` + found type `{ N + 2 }` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/const-generics/defaults/cec-generic-default.rs b/src/test/ui/const-generics/defaults/cec-generic-default.rs new file mode 100644 index 0000000000000..76ff7c7801b06 --- /dev/null +++ b/src/test/ui/const-generics/defaults/cec-generic-default.rs @@ -0,0 +1,24 @@ +#![feature(const_evaluatable_checked, const_generics, const_generics_defaults)] +#![allow(incomplete_features)] + +pub struct Foo; +pub fn needs_evaluatable_bound() -> Foo { + //~^ error: unconstrained generic constant + loop {} +} +pub fn has_evaluatable_bound() -> Foo where [(); N1 + 1]: { + loop {} +} + +type FooAlias = [(); NP]; +fn needs_evaluatable_bound_alias() -> FooAlias +{ + //~^^ error: unconstrained generic constant + todo!() +} +fn has_evaluatable_bound_alias() -> FooAlias +where [(); N + 1]: { + todo!() +} + +fn main() {} diff --git a/src/test/ui/const-generics/defaults/cec-generic-default.stderr b/src/test/ui/const-generics/defaults/cec-generic-default.stderr new file mode 100644 index 0000000000000..0234ea8b9a4a9 --- /dev/null +++ b/src/test/ui/const-generics/defaults/cec-generic-default.stderr @@ -0,0 +1,18 @@ +error: unconstrained generic constant + --> $DIR/cec-generic-default.rs:5:54 + | +LL | pub fn needs_evaluatable_bound() -> Foo { + | ^^^^^^^ + | + = help: try adding a `where` bound using this expression: `where [(); { N + 1 }]:` + +error: unconstrained generic constant + --> $DIR/cec-generic-default.rs:14:58 + | +LL | fn needs_evaluatable_bound_alias() -> FooAlias + | ^^^^^^^^^^^ + | + = help: try adding a `where` bound using this expression: `where [(); { N + 1 }]:` + +error: aborting due to 2 previous errors + From 8c40360ed413c0024787cf14fc83af0d98037c7a Mon Sep 17 00:00:00 2001 From: Ellen Date: Tue, 13 Jul 2021 17:23:26 +0100 Subject: [PATCH 4/6] Put checking if anonct is a default into a method on hir map --- compiler/rustc_hir/src/hir.rs | 3 +++ compiler/rustc_middle/src/hir/map/mod.rs | 13 +++++++++++ compiler/rustc_typeck/src/collect.rs | 28 +++++++---------------- compiler/rustc_typeck/src/outlives/mod.rs | 13 ++++------- 4 files changed, 28 insertions(+), 29 deletions(-) diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index a7ce92ea57917..04c29c50e75a1 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1422,6 +1422,9 @@ pub type Lit = Spanned; /// These are usually found nested inside types (e.g., array lengths) /// or expressions (e.g., repeat counts), and also used to define /// explicit discriminant values for enum variants. +/// +/// You can check if this anon const is a default in a const param +/// `const N: usize = { ... }` with [Map::opt_const_param_default_param_hir_id] #[derive(Copy, Clone, PartialEq, Eq, Encodable, Debug, HashStable_Generic)] pub struct AnonConst { pub hir_id: HirId, diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 07b39c97c492a..9d81407c330c4 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -901,6 +901,19 @@ impl<'hir> Map<'hir> { pub fn node_to_string(&self, id: HirId) -> String { hir_id_to_string(self, id) } + + /// Returns the HirId of `N` in `struct Foo` when + /// called with the HirId for the `{ ... }` anon const + pub fn opt_const_param_default_param_hir_id(&self, anon_const: HirId) -> Option { + match self.get(self.get_parent_node(anon_const)) { + Node::GenericParam(GenericParam { + hir_id: param_id, + kind: GenericParamKind::Const { .. }, + .. + }) => Some(*param_id), + _ => None, + } + } } impl<'hir> intravisit::Map<'hir> for Map<'hir> { diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index 924a0b8410a12..31cafb9d96652 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -1441,17 +1441,10 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics { // of a const parameter type, e.g. `struct Foo` is not allowed. None } else if tcx.lazy_normalization() { - // Only provide backwards declared generics to cg defaults (#83938) - if let Node::GenericParam(GenericParam { - hir_id: param_id, - kind: GenericParamKind::Const { .. }, - .. - }) = tcx.hir().get(tcx.hir().get_parent_node(hir_id)) - { - let item_id = tcx.hir().get_parent_node(*param_id); - let item_def_id = tcx.hir().local_def_id(item_id); - let generics = tcx.generics_of(item_def_id.to_def_id()); - let param_def = tcx.hir().local_def_id(*param_id).to_def_id(); + // Only provide backwards declared generics to cg defaults (#86580) + if let Some(param_id) = tcx.hir().opt_const_param_default_param_hir_id(hir_id) { + let generics = tcx.generics_of(parent_def_id.to_def_id()); + let param_def = tcx.hir().local_def_id(param_id).to_def_id(); let param_def_idx = generics.param_def_id_to_index[¶m_def]; let params = generics.params[..param_def_idx as usize].to_owned(); let param_def_id_to_index = @@ -2432,16 +2425,11 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat } } else { if matches!(def_kind, DefKind::AnonConst) && tcx.lazy_normalization() { - // Provide predicates of parent item of cg defaults manually - // as generics_of doesn't return a parent for the generics + // Provide predicates of parent item of cg defaults manually as `generics_of` + // doesn't set the parent item as the parent for the generics (#86580) let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); - if let Node::GenericParam(hir::GenericParam { - hir_id: param_id, - kind: hir::GenericParamKind::Const { .. }, - .. - }) = tcx.hir().get(tcx.hir().get_parent_node(hir_id)) - { - let item_id = tcx.hir().get_parent_node(*param_id); + if let Some(_) = tcx.hir().opt_const_param_default_param_hir_id(hir_id) { + let item_id = tcx.hir().get_parent_item(hir_id); let item_def_id = tcx.hir().local_def_id(item_id).to_def_id(); return tcx.explicit_predicates_of(item_def_id); } diff --git a/compiler/rustc_typeck/src/outlives/mod.rs b/compiler/rustc_typeck/src/outlives/mod.rs index c2f8525f7aba6..16d698fc8cb0f 100644 --- a/compiler/rustc_typeck/src/outlives/mod.rs +++ b/compiler/rustc_typeck/src/outlives/mod.rs @@ -22,15 +22,10 @@ fn inferred_outlives_of(tcx: TyCtxt<'_>, item_def_id: DefId) -> &[(ty::Predicate if matches!(tcx.def_kind(item_def_id), hir::def::DefKind::AnonConst) && tcx.lazy_normalization() { - // Provide inferred outlive preds of parent item of cg defaults manually - // as generics_of doesn't return a parent for the generics - if let Node::GenericParam(hir::GenericParam { - hir_id: param_id, - kind: hir::GenericParamKind::Const { .. }, - .. - }) = tcx.hir().get(tcx.hir().get_parent_node(id)) - { - let item_id = tcx.hir().get_parent_node(*param_id); + // Provide predicates of parent item of cg defaults manually as `generics_of` + // doesn't set the parent item as the parent for the generics (#86580) + if let Some(_) = tcx.hir().opt_const_param_default_param_hir_id(id) { + let item_id = tcx.hir().get_parent_item(id); let item_def_id = tcx.hir().local_def_id(item_id).to_def_id(); return tcx.inferred_outlives_of(item_def_id); } From abfd44d8a3b13d56dc0c7904c35a8155a62f19fb Mon Sep 17 00:00:00 2001 From: Ellen Date: Sat, 17 Jul 2021 11:59:42 +0100 Subject: [PATCH 5/6] Comments --- compiler/rustc_typeck/src/collect.rs | 43 +++++++++++++++++++++-- compiler/rustc_typeck/src/outlives/mod.rs | 14 ++++++-- 2 files changed, 52 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index 31cafb9d96652..a2ac3e2555f50 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -1441,16 +1441,43 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics { // of a const parameter type, e.g. `struct Foo` is not allowed. None } else if tcx.lazy_normalization() { - // Only provide backwards declared generics to cg defaults (#86580) if let Some(param_id) = tcx.hir().opt_const_param_default_param_hir_id(hir_id) { + // If the def_id we are calling generics_of on is an anon ct default i.e: + // + // struct Foo; + // ^^^ ^ ^^^^^^ def id of this anon const + // ^ ^ param_id + // ^ parent_def_id + // + // then we only want to return generics for params to the left of `N`. If we don't do that we + // end up with that const looking like: `ty::ConstKind::Unevaluated(def_id, substs: [N#0])`. + // + // This causes ICEs (#86580) when building the substs for Foo in `fn foo() -> Foo { .. }` as + // we substitute the defaults with the partially built substs when we build the substs. Subst'ing + // the `N#0` on the unevaluated const indexes into the empty substs we're in the process of building. + // + // We fix this by having this function return the parent's generics ourselves and truncating the + // generics to only include non-forward declared params (with the exception of the `Self` ty) + // + // For the above code example that means we want `substs: []` + // For the following struct def we want `substs: [N#0]` when generics_of is called on + // the def id of the `{ N + 1 }` anon const + // struct Foo; + // + // This has some implications for how we get the predicates available to the anon const + // see `explicit_predicates_of` for more information on this let generics = tcx.generics_of(parent_def_id.to_def_id()); let param_def = tcx.hir().local_def_id(param_id).to_def_id(); let param_def_idx = generics.param_def_id_to_index[¶m_def]; + // In the above example this would be .params[..N#0] let params = generics.params[..param_def_idx as usize].to_owned(); let param_def_id_to_index = params.iter().map(|param| (param.def_id, param.index)).collect(); return ty::Generics { + // we set the parent of these generics to be our parent's parent so that we + // dont end up with substs: [N, M, N] for the const default on a struct like this: + // struct Foo; parent: generics.parent, parent_count: generics.parent_count, params, @@ -2425,12 +2452,22 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat } } else { if matches!(def_kind, DefKind::AnonConst) && tcx.lazy_normalization() { - // Provide predicates of parent item of cg defaults manually as `generics_of` - // doesn't set the parent item as the parent for the generics (#86580) let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); if let Some(_) = tcx.hir().opt_const_param_default_param_hir_id(hir_id) { + // In `generics_of` we set the generics' parent to be our parent's parent which means that + // we lose out on the predicates of our actual parent if we dont return those predicates here. + // (See comment in `generics_of` for more information on why the parent shenanigans is necessary) + // + // struct Foo::ASSOC }>(T) where T: Trait; + // ^^^ ^^^^^^^^^^^^^^^^^^^^^^^ the def id we are calling + // ^^^ explicit_predicates_of on + // parent item we dont have set as the + // parent of generics returned by `generics_of` + // + // In the above code we want the anon const to have predicates in its param env for `T: Trait` let item_id = tcx.hir().get_parent_item(hir_id); let item_def_id = tcx.hir().local_def_id(item_id).to_def_id(); + // In the above code example we would be calling `explicit_predicates_of(Foo)` here return tcx.explicit_predicates_of(item_def_id); } } diff --git a/compiler/rustc_typeck/src/outlives/mod.rs b/compiler/rustc_typeck/src/outlives/mod.rs index 16d698fc8cb0f..70a2ba7fcd9d9 100644 --- a/compiler/rustc_typeck/src/outlives/mod.rs +++ b/compiler/rustc_typeck/src/outlives/mod.rs @@ -22,11 +22,21 @@ fn inferred_outlives_of(tcx: TyCtxt<'_>, item_def_id: DefId) -> &[(ty::Predicate if matches!(tcx.def_kind(item_def_id), hir::def::DefKind::AnonConst) && tcx.lazy_normalization() { - // Provide predicates of parent item of cg defaults manually as `generics_of` - // doesn't set the parent item as the parent for the generics (#86580) if let Some(_) = tcx.hir().opt_const_param_default_param_hir_id(id) { + // In `generics_of` we set the generics' parent to be our parent's parent which means that + // we lose out on the predicates of our actual parent if we dont return those predicates here. + // (See comment in `generics_of` for more information on why the parent shenanigans is necessary) + // + // struct Foo<'a, 'b, const N: usize = { ... }>(&'a &'b ()); + // ^^^ ^^^^^^^ the def id we are calling + // ^^^ inferred_outlives_of on + // parent item we dont have set as the + // parent of generics returned by `generics_of` + // + // In the above code we want the anon const to have predicates in its param env for `'b: 'a` let item_id = tcx.hir().get_parent_item(id); let item_def_id = tcx.hir().local_def_id(item_id).to_def_id(); + // In the above code example we would be calling `inferred_outlives_of(Foo)` here return tcx.inferred_outlives_of(item_def_id); } } From d1e5e72f7d25cc60ccfc54d3cd3e1ef3efa3dab9 Mon Sep 17 00:00:00 2001 From: Ellen Date: Sat, 24 Jul 2021 17:32:02 +0100 Subject: [PATCH 6/6] change doc comment --- compiler/rustc_hir/src/hir.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 04c29c50e75a1..f3f2b83c821d5 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1424,7 +1424,7 @@ pub type Lit = Spanned; /// explicit discriminant values for enum variants. /// /// You can check if this anon const is a default in a const param -/// `const N: usize = { ... }` with [Map::opt_const_param_default_param_hir_id] +/// `const N: usize = { ... }` with `tcx.hir().opt_const_param_default_param_hir_id(..)` #[derive(Copy, Clone, PartialEq, Eq, Encodable, Debug, HashStable_Generic)] pub struct AnonConst { pub hir_id: HirId,