allow concrete self types in consts
This commit is contained in:
parent
7402a39447
commit
e5b82a56c5
11 changed files with 141 additions and 18 deletions
|
@ -199,7 +199,14 @@ pub enum Res<Id = hir::HirId> {
|
||||||
|
|
||||||
// Type namespace
|
// Type namespace
|
||||||
PrimTy(hir::PrimTy),
|
PrimTy(hir::PrimTy),
|
||||||
SelfTy(Option<DefId> /* trait */, Option<DefId> /* 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::<Self>()]`.
|
||||||
|
///
|
||||||
|
/// Once `lazy_normalization_consts` is stable, this bodge can be removed again.
|
||||||
|
SelfTy(Option<DefId> /* trait */, Option<(DefId, bool)> /* impl */),
|
||||||
ToolMod, // e.g., `rustfmt` in `#[rustfmt::skip]`
|
ToolMod, // e.g., `rustfmt` in `#[rustfmt::skip]`
|
||||||
|
|
||||||
// Value namespace
|
// Value namespace
|
||||||
|
|
|
@ -104,7 +104,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
|
||||||
if let Some(t) = t {
|
if let Some(t) = t {
|
||||||
self.check_def_id(t);
|
self.check_def_id(t);
|
||||||
}
|
}
|
||||||
if let Some(i) = i {
|
if let Some((i, _)) = i {
|
||||||
self.check_def_id(i);
|
self.check_def_id(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -112,7 +112,7 @@ impl<'a> Resolver<'a> {
|
||||||
match outer_res {
|
match outer_res {
|
||||||
Res::SelfTy(maybe_trait_defid, maybe_impl_defid) => {
|
Res::SelfTy(maybe_trait_defid, maybe_impl_defid) => {
|
||||||
if let Some(impl_span) =
|
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(
|
err.span_label(
|
||||||
reduce_impl_span_to_impl_keyword(sm, impl_span),
|
reduce_impl_span_to_impl_keyword(sm, impl_span),
|
||||||
|
|
|
@ -110,6 +110,9 @@ crate enum RibKind<'a> {
|
||||||
ItemRibKind(HasGenericParams),
|
ItemRibKind(HasGenericParams),
|
||||||
|
|
||||||
/// We're in a constant item. Can't refer to dynamic stuff.
|
/// 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),
|
ConstantItemRibKind(bool),
|
||||||
|
|
||||||
/// We passed through a module.
|
/// 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| {
|
self.with_current_self_item(item, |this| {
|
||||||
this.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |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();
|
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);
|
visit::walk_item(this, item);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1215,7 +1218,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||||
// Resolve the trait reference, if necessary.
|
// Resolve the trait reference, if necessary.
|
||||||
this.with_optional_trait_ref(opt_trait_reference.as_ref(), |this, trait_id| {
|
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();
|
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() {
|
if let Some(trait_ref) = opt_trait_reference.as_ref() {
|
||||||
// Resolve type arguments in the trait path.
|
// Resolve type arguments in the trait path.
|
||||||
visit::walk_trait_ref(this, trait_ref);
|
visit::walk_trait_ref(this, trait_ref);
|
||||||
|
|
|
@ -2539,7 +2539,7 @@ impl<'a> Resolver<'a> {
|
||||||
&mut self,
|
&mut self,
|
||||||
rib_index: usize,
|
rib_index: usize,
|
||||||
rib_ident: Ident,
|
rib_ident: Ident,
|
||||||
res: Res,
|
mut res: Res,
|
||||||
record_used: bool,
|
record_used: bool,
|
||||||
span: Span,
|
span: Span,
|
||||||
all_ribs: &[Rib<'a>],
|
all_ribs: &[Rib<'a>],
|
||||||
|
@ -2627,16 +2627,27 @@ impl<'a> Resolver<'a> {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
ConstantItemRibKind(trivial) => {
|
ConstantItemRibKind(trivial) => {
|
||||||
|
if self.session.features_untracked().min_const_generics {
|
||||||
// HACK(min_const_generics): We currently only allow `N` or `{ N }`.
|
// HACK(min_const_generics): We currently only allow `N` or `{ N }`.
|
||||||
if !trivial && self.session.features_untracked().min_const_generics {
|
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 {
|
if record_used {
|
||||||
self.report_error(
|
self.report_error(
|
||||||
span,
|
span,
|
||||||
ResolutionError::ParamInNonTrivialAnonConst(rib_ident.name),
|
ResolutionError::ParamInNonTrivialAnonConst(
|
||||||
|
rib_ident.name,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return Res::Err;
|
return Res::Err;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if in_ty_param_default {
|
if in_ty_param_default {
|
||||||
if record_used {
|
if record_used {
|
||||||
|
|
|
@ -1460,7 +1460,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||||
// Find the type of the associated item, and the trait where the associated
|
// Find the type of the associated item, and the trait where the associated
|
||||||
// item is declared.
|
// item is declared.
|
||||||
let bound = match (&qself_ty.kind(), qself_res) {
|
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
|
// `Self` in an impl of a trait -- we have a concrete self type and a
|
||||||
// trait reference.
|
// trait reference.
|
||||||
let trait_ref = match tcx.impl_trait_ref(impl_def_id) {
|
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);
|
self.prohibit_generics(path.segments);
|
||||||
tcx.types.self_param
|
tcx.types.self_param
|
||||||
}
|
}
|
||||||
Res::SelfTy(_, Some(def_id)) => {
|
Res::SelfTy(_, Some((def_id, forbid_generic))) => {
|
||||||
// `Self` in impl (we know the concrete type).
|
// `Self` in impl (we know the concrete type).
|
||||||
assert_eq!(opt_self_ty, None);
|
assert_eq!(opt_self_ty, None);
|
||||||
self.prohibit_generics(path.segments);
|
self.prohibit_generics(path.segments);
|
||||||
// Try to evaluate any array length constants.
|
// 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) => {
|
Res::Def(DefKind::AssocTy, def_id) => {
|
||||||
debug_assert!(path.segments.len() >= 2);
|
debug_assert!(path.segments.len() >= 2);
|
||||||
|
|
|
@ -601,7 +601,7 @@ pub fn register_res(cx: &DocContext<'_>, res: Res) -> DefId {
|
||||||
},
|
},
|
||||||
Res::Def(DefKind::TraitAlias, i) => (i, TypeKind::TraitAlias),
|
Res::Def(DefKind::TraitAlias, i) => (i, TypeKind::TraitAlias),
|
||||||
Res::SelfTy(Some(def_id), _) => (def_id, TypeKind::Trait),
|
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(),
|
_ => return res.def_id(),
|
||||||
};
|
};
|
||||||
if did.is_local() {
|
if did.is_local() {
|
||||||
|
|
|
@ -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() {}
|
|
@ -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::<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:1
|
||||||
|
|
|
||||||
|
LL | / impl<T> Bar<T> {
|
||||||
|
LL | | fn t3() -> [u8; std::mem::size_of::<Self>()] {}
|
||||||
|
LL | | }
|
||||||
|
| |_^
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
|
@ -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() {}
|
|
@ -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::<Self>()];
|
||||||
|
| ^^^^
|
||||||
|
|
|
||||||
|
note: not a concrete type
|
||||||
|
--> $DIR/self-ty-in-const-2.rs:15:1
|
||||||
|
|
|
||||||
|
LL | / impl<T> Baz for Bar<T> {
|
||||||
|
LL | | fn hey() {
|
||||||
|
LL | | let _: [u8; std::mem::size_of::<Self>()];
|
||||||
|
LL | | }
|
||||||
|
LL | | }
|
||||||
|
| |_^
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue