diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs index b019e518d0c54..96fde48d96cc1 100644 --- a/compiler/rustc_hir/src/def.rs +++ b/compiler/rustc_hir/src/def.rs @@ -199,7 +199,16 @@ pub enum Res { // Type namespace PrimTy(hir::PrimTy), - SelfTy(Option /* trait */, Option /* impl */), + /// `Self`, with both an optional trait and impl `DefId`. + /// + /// 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::()] {} } + /// ``` + /// + /// 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]` // Value namespace diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index c79542342ba78..fe6653e98da89 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 7a0503d68f348..b80da64149150 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 07f36c7b7ad36..6788df9be7820 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 0f5b9b518163f..00a37d908cd07 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>], @@ -2629,13 +2629,22 @@ impl<'a> Resolver<'a> { 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), - ); + // 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 9e339b1082cb8..a743dc1cd2086 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,29 @@ 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() { + 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 + } } 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 c577b771d6094..58b76d24a5bdb 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/issues/issue-62504.min.stderr b/src/test/ui/const-generics/issues/issue-62504.min.stderr index 752df17aad614..8f794312834b2 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 b520dbe4e803b..015f170f00d1c 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 } } 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 0000000000000..0973b373c122c --- /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 0000000000000..89ce58564e465 --- /dev/null +++ b/src/test/ui/const-generics/min_const_generics/self-ty-in-const-1.stderr @@ -0,0 +1,22 @@ +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:9 + | +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.rs b/src/test/ui/const-generics/min_const_generics/self-ty-in-const-2.rs new file mode 100644 index 0000000000000..e7f80d50082b3 --- /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 0000000000000..9ac6410a290a5 --- /dev/null +++ b/src/test/ui/const-generics/min_const_generics/self-ty-in-const-2.stderr @@ -0,0 +1,14 @@ +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:17 + | +LL | impl Baz for Bar { + | ^^^^^^ + +error: aborting due to previous error +