From e5b82a56c5a9dd5c40f2abe8ee5398fc8acdd4b4 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Tue, 1 Sep 2020 14:30:16 +0200 Subject: [PATCH 1/3] allow concrete self types in consts --- compiler/rustc_hir/src/def.rs | 9 +++++- compiler/rustc_passes/src/dead.rs | 2 +- compiler/rustc_resolve/src/diagnostics.rs | 2 +- compiler/rustc_resolve/src/late.rs | 7 +++-- compiler/rustc_resolve/src/lib.rs | 29 +++++++++++++------ compiler/rustc_typeck/src/astconv/mod.rs | 18 ++++++++++-- src/librustdoc/clean/utils.rs | 2 +- .../min_const_generics/self-ty-in-const-1.rs | 27 +++++++++++++++++ .../self-ty-in-const-1.stderr | 24 +++++++++++++++ .../min_const_generics/self-ty-in-const-2.rs | 21 ++++++++++++++ .../self-ty-in-const-2.stderr | 18 ++++++++++++ 11 files changed, 141 insertions(+), 18 deletions(-) create mode 100644 src/test/ui/const-generics/min_const_generics/self-ty-in-const-1.rs create mode 100644 src/test/ui/const-generics/min_const_generics/self-ty-in-const-1.stderr create mode 100644 src/test/ui/const-generics/min_const_generics/self-ty-in-const-2.rs create mode 100644 src/test/ui/const-generics/min_const_generics/self-ty-in-const-2.stderr diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs index b019e518d0c..730059e7ece 100644 --- a/compiler/rustc_hir/src/def.rs +++ b/compiler/rustc_hir/src/def.rs @@ -199,7 +199,14 @@ pub enum Res { // Type namespace PrimTy(hir::PrimTy), - SelfTy(Option /* trait */, Option /* impl */), + /// `Self`, with both an optional trait and impl `DefId`. + /// + /// HACK: impl self types also have an optional requirement to not mention + /// any generic parameters to allow the following with `min_const_generics`. + /// `impl Foo { fn test() -> [u8; std::mem::size_of::()]`. + /// + /// Once `lazy_normalization_consts` is stable, this bodge can be removed again. + SelfTy(Option /* trait */, Option<(DefId, bool)> /* impl */), ToolMod, // e.g., `rustfmt` in `#[rustfmt::skip]` // Value namespace diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index c79542342ba..fe6653e98da 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -104,7 +104,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { if let Some(t) = t { self.check_def_id(t); } - if let Some(i) = i { + if let Some((i, _)) = i { self.check_def_id(i); } } diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 7a0503d68f3..b80da641491 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -112,7 +112,7 @@ impl<'a> Resolver<'a> { match outer_res { Res::SelfTy(maybe_trait_defid, maybe_impl_defid) => { if let Some(impl_span) = - maybe_impl_defid.and_then(|def_id| self.opt_span(def_id)) + maybe_impl_defid.and_then(|(def_id, _)| self.opt_span(def_id)) { err.span_label( reduce_impl_span_to_impl_keyword(sm, impl_span), diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 07f36c7b7ad..6788df9be78 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -110,6 +110,9 @@ crate enum RibKind<'a> { ItemRibKind(HasGenericParams), /// We're in a constant item. Can't refer to dynamic stuff. + /// + /// The `bool` indicates if this constant may reference generic parameters + /// and is used to only allow generic parameters to be used in trivial constant expressions. ConstantItemRibKind(bool), /// We passed through a module. @@ -848,7 +851,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { self.with_current_self_item(item, |this| { this.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| { let item_def_id = this.r.local_def_id(item.id).to_def_id(); - this.with_self_rib(Res::SelfTy(None, Some(item_def_id)), |this| { + this.with_self_rib(Res::SelfTy(None, Some((item_def_id, false))), |this| { visit::walk_item(this, item); }); }); @@ -1215,7 +1218,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { // Resolve the trait reference, if necessary. this.with_optional_trait_ref(opt_trait_reference.as_ref(), |this, trait_id| { let item_def_id = this.r.local_def_id(item_id).to_def_id(); - this.with_self_rib(Res::SelfTy(trait_id, Some(item_def_id)), |this| { + this.with_self_rib(Res::SelfTy(trait_id, Some((item_def_id, false))), |this| { if let Some(trait_ref) = opt_trait_reference.as_ref() { // Resolve type arguments in the trait path. visit::walk_trait_ref(this, trait_ref); diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 0f5b9b51816..1922f0d566e 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -2539,7 +2539,7 @@ impl<'a> Resolver<'a> { &mut self, rib_index: usize, rib_ident: Ident, - res: Res, + mut res: Res, record_used: bool, span: Span, all_ribs: &[Rib<'a>], @@ -2627,15 +2627,26 @@ impl<'a> Resolver<'a> { continue; } ConstantItemRibKind(trivial) => { - // HACK(min_const_generics): We currently only allow `N` or `{ N }`. - if !trivial && self.session.features_untracked().min_const_generics { - if record_used { - self.report_error( - span, - ResolutionError::ParamInNonTrivialAnonConst(rib_ident.name), - ); + if self.session.features_untracked().min_const_generics { + // HACK(min_const_generics): We currently only allow `N` or `{ N }`. + if !trivial { + // HACK(min_const_generics): If we encounter `Self` in an anonymous constant + // we can't easily tell if it's generic at this stage, so we instead remember + // this and then enforce the self type to be concrete later on. + if let Res::SelfTy(trait_def, Some((impl_def, _))) = res { + res = Res::SelfTy(trait_def, Some((impl_def, true))); + } else { + if record_used { + self.report_error( + span, + ResolutionError::ParamInNonTrivialAnonConst( + rib_ident.name, + ), + ); + } + return Res::Err; + } } - return Res::Err; } if in_ty_param_default { diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index 9e339b1082c..66d9d49d93f 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -1460,7 +1460,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // Find the type of the associated item, and the trait where the associated // item is declared. let bound = match (&qself_ty.kind(), qself_res) { - (_, Res::SelfTy(Some(_), Some(impl_def_id))) => { + (_, Res::SelfTy(Some(_), Some((impl_def_id, _)))) => { // `Self` in an impl of a trait -- we have a concrete self type and a // trait reference. let trait_ref = match tcx.impl_trait_ref(impl_def_id) { @@ -1917,12 +1917,24 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { self.prohibit_generics(path.segments); tcx.types.self_param } - Res::SelfTy(_, Some(def_id)) => { + Res::SelfTy(_, Some((def_id, forbid_generic))) => { // `Self` in impl (we know the concrete type). assert_eq!(opt_self_ty, None); self.prohibit_generics(path.segments); // Try to evaluate any array length constants. - self.normalize_ty(span, tcx.at(span).type_of(def_id)) + let normalized_ty = self.normalize_ty(span, tcx.at(span).type_of(def_id)); + if forbid_generic && normalized_ty.needs_subst() { + tcx.sess + .struct_span_err( + path.span, + "generic `Self` types are currently not permitted in anonymous constants" + ) + .span_note(tcx.def_span(def_id), "not a concrete type") + .emit(); + tcx.ty_error() + } else { + normalized_ty + } } Res::Def(DefKind::AssocTy, def_id) => { debug_assert!(path.segments.len() >= 2); diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index c577b771d60..58b76d24a5b 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -601,7 +601,7 @@ pub fn register_res(cx: &DocContext<'_>, res: Res) -> DefId { }, Res::Def(DefKind::TraitAlias, i) => (i, TypeKind::TraitAlias), Res::SelfTy(Some(def_id), _) => (def_id, TypeKind::Trait), - Res::SelfTy(_, Some(impl_def_id)) => return impl_def_id, + Res::SelfTy(_, Some((impl_def_id, _))) => return impl_def_id, _ => return res.def_id(), }; if did.is_local() { diff --git a/src/test/ui/const-generics/min_const_generics/self-ty-in-const-1.rs b/src/test/ui/const-generics/min_const_generics/self-ty-in-const-1.rs new file mode 100644 index 00000000000..0973b373c12 --- /dev/null +++ b/src/test/ui/const-generics/min_const_generics/self-ty-in-const-1.rs @@ -0,0 +1,27 @@ +#![feature(min_const_generics)] + +trait Foo { + fn t1() -> [u8; std::mem::size_of::()]; //~ERROR generic parameters +} + +struct Bar(T); + +impl Bar { + fn t2() -> [u8; std::mem::size_of::()] { todo!() } // ok +} + +impl Bar { + fn t3() -> [u8; std::mem::size_of::()] {} //~ERROR generic `Self` +} + +trait Baz { + fn hey(); +} + +impl Baz for u16 { + fn hey() { + let _: [u8; std::mem::size_of::()]; // ok + } +} + +fn main() {} diff --git a/src/test/ui/const-generics/min_const_generics/self-ty-in-const-1.stderr b/src/test/ui/const-generics/min_const_generics/self-ty-in-const-1.stderr new file mode 100644 index 00000000000..94f67735fca --- /dev/null +++ b/src/test/ui/const-generics/min_const_generics/self-ty-in-const-1.stderr @@ -0,0 +1,24 @@ +error: generic parameters must not be used inside of non trivial constant values + --> $DIR/self-ty-in-const-1.rs:4:41 + | +LL | fn t1() -> [u8; std::mem::size_of::()]; + | ^^^^ non-trivial anonymous constants must not depend on the parameter `Self` + | + = help: it is currently only allowed to use either `Self` or `{ Self }` as generic constants + +error: generic `Self` types are currently not permitted in anonymous constants + --> $DIR/self-ty-in-const-1.rs:14:41 + | +LL | fn t3() -> [u8; std::mem::size_of::()] {} + | ^^^^ + | +note: not a concrete type + --> $DIR/self-ty-in-const-1.rs:13:1 + | +LL | / impl Bar { +LL | | fn t3() -> [u8; std::mem::size_of::()] {} +LL | | } + | |_^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/const-generics/min_const_generics/self-ty-in-const-2.rs b/src/test/ui/const-generics/min_const_generics/self-ty-in-const-2.rs new file mode 100644 index 00000000000..e7f80d50082 --- /dev/null +++ b/src/test/ui/const-generics/min_const_generics/self-ty-in-const-2.rs @@ -0,0 +1,21 @@ +#![feature(min_const_generics)] + +struct Bar(T); + +trait Baz { + fn hey(); +} + +impl Baz for u16 { + fn hey() { + let _: [u8; std::mem::size_of::()]; // ok + } +} + +impl Baz for Bar { + fn hey() { + let _: [u8; std::mem::size_of::()]; //~ERROR generic `Self` + } +} + +fn main() {} diff --git a/src/test/ui/const-generics/min_const_generics/self-ty-in-const-2.stderr b/src/test/ui/const-generics/min_const_generics/self-ty-in-const-2.stderr new file mode 100644 index 00000000000..70f44e7de63 --- /dev/null +++ b/src/test/ui/const-generics/min_const_generics/self-ty-in-const-2.stderr @@ -0,0 +1,18 @@ +error: generic `Self` types are currently not permitted in anonymous constants + --> $DIR/self-ty-in-const-2.rs:17:41 + | +LL | let _: [u8; std::mem::size_of::()]; + | ^^^^ + | +note: not a concrete type + --> $DIR/self-ty-in-const-2.rs:15:1 + | +LL | / impl Baz for Bar { +LL | | fn hey() { +LL | | let _: [u8; std::mem::size_of::()]; +LL | | } +LL | | } + | |_^ + +error: aborting due to previous error + From c552717e9da86f70d49390bba1e4b305054d9ed4 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Tue, 8 Sep 2020 11:37:27 +0200 Subject: [PATCH 2/3] review, improve note span --- compiler/rustc_hir/src/def.rs | 10 +++--- compiler/rustc_resolve/src/lib.rs | 34 +++++++++---------- compiler/rustc_typeck/src/astconv/mod.rs | 19 +++++++---- .../self-ty-in-const-1.stderr | 8 ++--- .../self-ty-in-const-2.stderr | 10 ++---- 5 files changed, 40 insertions(+), 41 deletions(-) diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs index 730059e7ece..96fde48d96c 100644 --- a/compiler/rustc_hir/src/def.rs +++ b/compiler/rustc_hir/src/def.rs @@ -201,11 +201,13 @@ pub enum Res { PrimTy(hir::PrimTy), /// `Self`, with both an optional trait and impl `DefId`. /// - /// HACK: impl self types also have an optional requirement to not mention - /// any generic parameters to allow the following with `min_const_generics`. - /// `impl Foo { fn test() -> [u8; std::mem::size_of::()]`. + /// HACK(min_const_generics): impl self types also have an optional requirement to not mention + /// any generic parameters to allow the following with `min_const_generics`: + /// ```rust + /// impl Foo { fn test() -> [u8; std::mem::size_of::()] {} } + /// ``` /// - /// Once `lazy_normalization_consts` is stable, this bodge can be removed again. + /// FIXME(lazy_normalization_consts): Remove this bodge once this feature is stable. SelfTy(Option /* trait */, Option<(DefId, bool)> /* impl */), ToolMod, // e.g., `rustfmt` in `#[rustfmt::skip]` diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 1922f0d566e..00a37d908cd 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -2627,25 +2627,23 @@ impl<'a> Resolver<'a> { continue; } ConstantItemRibKind(trivial) => { - if self.session.features_untracked().min_const_generics { - // HACK(min_const_generics): We currently only allow `N` or `{ N }`. - if !trivial { - // HACK(min_const_generics): If we encounter `Self` in an anonymous constant - // we can't easily tell if it's generic at this stage, so we instead remember - // this and then enforce the self type to be concrete later on. - if let Res::SelfTy(trait_def, Some((impl_def, _))) = res { - res = Res::SelfTy(trait_def, Some((impl_def, true))); - } else { - if record_used { - self.report_error( - span, - ResolutionError::ParamInNonTrivialAnonConst( - rib_ident.name, - ), - ); - } - return Res::Err; + // HACK(min_const_generics): We currently only allow `N` or `{ N }`. + if !trivial && self.session.features_untracked().min_const_generics { + // HACK(min_const_generics): If we encounter `Self` in an anonymous constant + // we can't easily tell if it's generic at this stage, so we instead remember + // this and then enforce the self type to be concrete later on. + if let Res::SelfTy(trait_def, Some((impl_def, _))) = res { + res = Res::SelfTy(trait_def, Some((impl_def, true))); + } else { + if record_used { + self.report_error( + span, + ResolutionError::ParamInNonTrivialAnonConst( + rib_ident.name, + ), + ); } + return Res::Err; } } diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index 66d9d49d93f..a743dc1cd20 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -1924,13 +1924,18 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // Try to evaluate any array length constants. let normalized_ty = self.normalize_ty(span, tcx.at(span).type_of(def_id)); if forbid_generic && normalized_ty.needs_subst() { - tcx.sess - .struct_span_err( - path.span, - "generic `Self` types are currently not permitted in anonymous constants" - ) - .span_note(tcx.def_span(def_id), "not a concrete type") - .emit(); + let mut err = tcx.sess.struct_span_err( + path.span, + "generic `Self` types are currently not permitted in anonymous constants", + ); + if let Some(hir::Node::Item(&hir::Item { + kind: hir::ItemKind::Impl { self_ty, .. }, + .. + })) = tcx.hir().get_if_local(def_id) + { + err.span_note(self_ty.span, "not a concrete type"); + } + err.emit(); tcx.ty_error() } else { normalized_ty diff --git a/src/test/ui/const-generics/min_const_generics/self-ty-in-const-1.stderr b/src/test/ui/const-generics/min_const_generics/self-ty-in-const-1.stderr index 94f67735fca..89ce58564e4 100644 --- a/src/test/ui/const-generics/min_const_generics/self-ty-in-const-1.stderr +++ b/src/test/ui/const-generics/min_const_generics/self-ty-in-const-1.stderr @@ -13,12 +13,10 @@ LL | fn t3() -> [u8; std::mem::size_of::()] {} | ^^^^ | note: not a concrete type - --> $DIR/self-ty-in-const-1.rs:13:1 + --> $DIR/self-ty-in-const-1.rs:13:9 | -LL | / impl Bar { -LL | | fn t3() -> [u8; std::mem::size_of::()] {} -LL | | } - | |_^ +LL | impl Bar { + | ^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/const-generics/min_const_generics/self-ty-in-const-2.stderr b/src/test/ui/const-generics/min_const_generics/self-ty-in-const-2.stderr index 70f44e7de63..9ac6410a290 100644 --- a/src/test/ui/const-generics/min_const_generics/self-ty-in-const-2.stderr +++ b/src/test/ui/const-generics/min_const_generics/self-ty-in-const-2.stderr @@ -5,14 +5,10 @@ LL | let _: [u8; std::mem::size_of::()]; | ^^^^ | note: not a concrete type - --> $DIR/self-ty-in-const-2.rs:15:1 + --> $DIR/self-ty-in-const-2.rs:15:17 | -LL | / impl Baz for Bar { -LL | | fn hey() { -LL | | let _: [u8; std::mem::size_of::()]; -LL | | } -LL | | } - | |_^ +LL | impl Baz for Bar { + | ^^^^^^ error: aborting due to previous error From 90dd798cf53320b3478119d06d2d8c47880c9247 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Sun, 13 Sep 2020 23:02:43 +0200 Subject: [PATCH 3/3] bless tests --- .../ui/const-generics/issues/issue-62504.min.stderr | 10 +++++++--- src/test/ui/const-generics/issues/issue-62504.rs | 2 +- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/test/ui/const-generics/issues/issue-62504.min.stderr b/src/test/ui/const-generics/issues/issue-62504.min.stderr index 752df17aad6..8f794312834 100644 --- a/src/test/ui/const-generics/issues/issue-62504.min.stderr +++ b/src/test/ui/const-generics/issues/issue-62504.min.stderr @@ -1,10 +1,14 @@ -error: generic parameters must not be used inside of non trivial constant values +error: generic `Self` types are currently not permitted in anonymous constants --> $DIR/issue-62504.rs:19:25 | LL | ArrayHolder([0; Self::SIZE]) - | ^^^^^^^^^^ non-trivial anonymous constants must not depend on the parameter `Self` + | ^^^^^^^^^^ | - = help: it is currently only allowed to use either `Self` or `{ Self }` as generic constants +note: not a concrete type + --> $DIR/issue-62504.rs:17:22 + | +LL | impl ArrayHolder { + | ^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/const-generics/issues/issue-62504.rs b/src/test/ui/const-generics/issues/issue-62504.rs index b520dbe4e80..015f170f00d 100644 --- a/src/test/ui/const-generics/issues/issue-62504.rs +++ b/src/test/ui/const-generics/issues/issue-62504.rs @@ -18,7 +18,7 @@ impl ArrayHolder { pub const fn new() -> Self { ArrayHolder([0; Self::SIZE]) //[full]~^ ERROR constant expression depends on a generic parameter - //[min]~^^ ERROR generic parameters must not be used inside of non trivial constant values + //[min]~^^ ERROR generic `Self` types are currently } }