Auto merge of #76195 - lcnr:const-Self, r=varkor

allow concrete self types in consts

This is quite a bad hack to fix #75486. There might be a better way to check if the self type depends on generic parameters, but I wasn't able to come up with one.

r? `@varkor` cc `@petrochenkov`
This commit is contained in:
bors 2020-09-14 04:07:08 +00:00
commit 56d8a933b3
13 changed files with 146 additions and 20 deletions

View File

@ -199,7 +199,16 @@ pub enum Res<Id = hir::HirId> {
// Type namespace
PrimTy(hir::PrimTy),
SelfTy(Option<DefId> /* trait */, Option<DefId> /* 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::<Self>()] {} }
/// ```
///
/// FIXME(lazy_normalization_consts): Remove this bodge once this feature is stable.
SelfTy(Option<DefId> /* trait */, Option<(DefId, bool)> /* impl */),
ToolMod, // e.g., `rustfmt` in `#[rustfmt::skip]`
// Value namespace

View File

@ -104,7 +104,7 @@ fn handle_res(&mut self, res: Res) {
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);
}
}

View File

@ -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),

View File

@ -110,6 +110,9 @@ enum PatBoundCtx {
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 @@ fn resolve_adt(&mut self, item: &'ast Item, generics: &'ast Generics) {
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 @@ fn resolve_implementation(
// 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);

View File

@ -2539,7 +2539,7 @@ fn validate_res_from_ribs(
&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 @@ fn validate_res_from_ribs(
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 {

View File

@ -1460,7 +1460,7 @@ pub fn associated_path_to_ty(
// 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 @@ pub fn res_to_ty(
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);

View File

@ -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() {

View File

@ -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<const X: usize> ArrayHolder<X> {
| ^^^^^^^^^^^^^^
error: aborting due to previous error

View File

@ -18,7 +18,7 @@ impl<const X: usize> ArrayHolder<X> {
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
}
}

View File

@ -0,0 +1,27 @@
#![feature(min_const_generics)]
trait Foo {
fn t1() -> [u8; std::mem::size_of::<Self>()]; //~ERROR generic parameters
}
struct Bar<T>(T);
impl Bar<u8> {
fn t2() -> [u8; std::mem::size_of::<Self>()] { todo!() } // ok
}
impl<T> Bar<T> {
fn t3() -> [u8; std::mem::size_of::<Self>()] {} //~ERROR generic `Self`
}
trait Baz {
fn hey();
}
impl Baz for u16 {
fn hey() {
let _: [u8; std::mem::size_of::<Self>()]; // ok
}
}
fn main() {}

View File

@ -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::<Self>()];
| ^^^^ 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::<Self>()] {}
| ^^^^
|
note: not a concrete type
--> $DIR/self-ty-in-const-1.rs:13:9
|
LL | impl<T> Bar<T> {
| ^^^^^^
error: aborting due to 2 previous errors

View File

@ -0,0 +1,21 @@
#![feature(min_const_generics)]
struct Bar<T>(T);
trait Baz {
fn hey();
}
impl Baz for u16 {
fn hey() {
let _: [u8; std::mem::size_of::<Self>()]; // ok
}
}
impl<T> Baz for Bar<T> {
fn hey() {
let _: [u8; std::mem::size_of::<Self>()]; //~ERROR generic `Self`
}
}
fn main() {}

View File

@ -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::<Self>()];
| ^^^^
|
note: not a concrete type
--> $DIR/self-ty-in-const-2.rs:15:17
|
LL | impl<T> Baz for Bar<T> {
| ^^^^^^
error: aborting due to previous error