Skip to content

Commit e5b82a5

Browse files
committed
allow concrete self types in consts
1 parent 7402a39 commit e5b82a5

File tree

11 files changed

+141
-18
lines changed

11 files changed

+141
-18
lines changed

compiler/rustc_hir/src/def.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,14 @@ pub enum Res<Id = hir::HirId> {
199199

200200
// Type namespace
201201
PrimTy(hir::PrimTy),
202-
SelfTy(Option<DefId> /* trait */, Option<DefId> /* impl */),
202+
/// `Self`, with both an optional trait and impl `DefId`.
203+
///
204+
/// HACK: impl self types also have an optional requirement to not mention
205+
/// any generic parameters to allow the following with `min_const_generics`.
206+
/// `impl Foo { fn test() -> [u8; std::mem::size_of::<Self>()]`.
207+
///
208+
/// Once `lazy_normalization_consts` is stable, this bodge can be removed again.
209+
SelfTy(Option<DefId> /* trait */, Option<(DefId, bool)> /* impl */),
203210
ToolMod, // e.g., `rustfmt` in `#[rustfmt::skip]`
204211

205212
// Value namespace

compiler/rustc_passes/src/dead.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
104104
if let Some(t) = t {
105105
self.check_def_id(t);
106106
}
107-
if let Some(i) = i {
107+
if let Some((i, _)) = i {
108108
self.check_def_id(i);
109109
}
110110
}

compiler/rustc_resolve/src/diagnostics.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ impl<'a> Resolver<'a> {
112112
match outer_res {
113113
Res::SelfTy(maybe_trait_defid, maybe_impl_defid) => {
114114
if let Some(impl_span) =
115-
maybe_impl_defid.and_then(|def_id| self.opt_span(def_id))
115+
maybe_impl_defid.and_then(|(def_id, _)| self.opt_span(def_id))
116116
{
117117
err.span_label(
118118
reduce_impl_span_to_impl_keyword(sm, impl_span),

compiler/rustc_resolve/src/late.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,9 @@ crate enum RibKind<'a> {
110110
ItemRibKind(HasGenericParams),
111111

112112
/// We're in a constant item. Can't refer to dynamic stuff.
113+
///
114+
/// The `bool` indicates if this constant may reference generic parameters
115+
/// and is used to only allow generic parameters to be used in trivial constant expressions.
113116
ConstantItemRibKind(bool),
114117

115118
/// We passed through a module.
@@ -848,7 +851,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
848851
self.with_current_self_item(item, |this| {
849852
this.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| {
850853
let item_def_id = this.r.local_def_id(item.id).to_def_id();
851-
this.with_self_rib(Res::SelfTy(None, Some(item_def_id)), |this| {
854+
this.with_self_rib(Res::SelfTy(None, Some((item_def_id, false))), |this| {
852855
visit::walk_item(this, item);
853856
});
854857
});
@@ -1215,7 +1218,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
12151218
// Resolve the trait reference, if necessary.
12161219
this.with_optional_trait_ref(opt_trait_reference.as_ref(), |this, trait_id| {
12171220
let item_def_id = this.r.local_def_id(item_id).to_def_id();
1218-
this.with_self_rib(Res::SelfTy(trait_id, Some(item_def_id)), |this| {
1221+
this.with_self_rib(Res::SelfTy(trait_id, Some((item_def_id, false))), |this| {
12191222
if let Some(trait_ref) = opt_trait_reference.as_ref() {
12201223
// Resolve type arguments in the trait path.
12211224
visit::walk_trait_ref(this, trait_ref);

compiler/rustc_resolve/src/lib.rs

+20-9
Original file line numberDiff line numberDiff line change
@@ -2539,7 +2539,7 @@ impl<'a> Resolver<'a> {
25392539
&mut self,
25402540
rib_index: usize,
25412541
rib_ident: Ident,
2542-
res: Res,
2542+
mut res: Res,
25432543
record_used: bool,
25442544
span: Span,
25452545
all_ribs: &[Rib<'a>],
@@ -2627,15 +2627,26 @@ impl<'a> Resolver<'a> {
26272627
continue;
26282628
}
26292629
ConstantItemRibKind(trivial) => {
2630-
// HACK(min_const_generics): We currently only allow `N` or `{ N }`.
2631-
if !trivial && self.session.features_untracked().min_const_generics {
2632-
if record_used {
2633-
self.report_error(
2634-
span,
2635-
ResolutionError::ParamInNonTrivialAnonConst(rib_ident.name),
2636-
);
2630+
if self.session.features_untracked().min_const_generics {
2631+
// HACK(min_const_generics): We currently only allow `N` or `{ N }`.
2632+
if !trivial {
2633+
// HACK(min_const_generics): If we encounter `Self` in an anonymous constant
2634+
// we can't easily tell if it's generic at this stage, so we instead remember
2635+
// this and then enforce the self type to be concrete later on.
2636+
if let Res::SelfTy(trait_def, Some((impl_def, _))) = res {
2637+
res = Res::SelfTy(trait_def, Some((impl_def, true)));
2638+
} else {
2639+
if record_used {
2640+
self.report_error(
2641+
span,
2642+
ResolutionError::ParamInNonTrivialAnonConst(
2643+
rib_ident.name,
2644+
),
2645+
);
2646+
}
2647+
return Res::Err;
2648+
}
26372649
}
2638-
return Res::Err;
26392650
}
26402651

26412652
if in_ty_param_default {

compiler/rustc_typeck/src/astconv/mod.rs

+15-3
Original file line numberDiff line numberDiff line change
@@ -1460,7 +1460,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
14601460
// Find the type of the associated item, and the trait where the associated
14611461
// item is declared.
14621462
let bound = match (&qself_ty.kind(), qself_res) {
1463-
(_, Res::SelfTy(Some(_), Some(impl_def_id))) => {
1463+
(_, Res::SelfTy(Some(_), Some((impl_def_id, _)))) => {
14641464
// `Self` in an impl of a trait -- we have a concrete self type and a
14651465
// trait reference.
14661466
let trait_ref = match tcx.impl_trait_ref(impl_def_id) {
@@ -1917,12 +1917,24 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
19171917
self.prohibit_generics(path.segments);
19181918
tcx.types.self_param
19191919
}
1920-
Res::SelfTy(_, Some(def_id)) => {
1920+
Res::SelfTy(_, Some((def_id, forbid_generic))) => {
19211921
// `Self` in impl (we know the concrete type).
19221922
assert_eq!(opt_self_ty, None);
19231923
self.prohibit_generics(path.segments);
19241924
// Try to evaluate any array length constants.
1925-
self.normalize_ty(span, tcx.at(span).type_of(def_id))
1925+
let normalized_ty = self.normalize_ty(span, tcx.at(span).type_of(def_id));
1926+
if forbid_generic && normalized_ty.needs_subst() {
1927+
tcx.sess
1928+
.struct_span_err(
1929+
path.span,
1930+
"generic `Self` types are currently not permitted in anonymous constants"
1931+
)
1932+
.span_note(tcx.def_span(def_id), "not a concrete type")
1933+
.emit();
1934+
tcx.ty_error()
1935+
} else {
1936+
normalized_ty
1937+
}
19261938
}
19271939
Res::Def(DefKind::AssocTy, def_id) => {
19281940
debug_assert!(path.segments.len() >= 2);

src/librustdoc/clean/utils.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -601,7 +601,7 @@ pub fn register_res(cx: &DocContext<'_>, res: Res) -> DefId {
601601
},
602602
Res::Def(DefKind::TraitAlias, i) => (i, TypeKind::TraitAlias),
603603
Res::SelfTy(Some(def_id), _) => (def_id, TypeKind::Trait),
604-
Res::SelfTy(_, Some(impl_def_id)) => return impl_def_id,
604+
Res::SelfTy(_, Some((impl_def_id, _))) => return impl_def_id,
605605
_ => return res.def_id(),
606606
};
607607
if did.is_local() {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#![feature(min_const_generics)]
2+
3+
trait Foo {
4+
fn t1() -> [u8; std::mem::size_of::<Self>()]; //~ERROR generic parameters
5+
}
6+
7+
struct Bar<T>(T);
8+
9+
impl Bar<u8> {
10+
fn t2() -> [u8; std::mem::size_of::<Self>()] { todo!() } // ok
11+
}
12+
13+
impl<T> Bar<T> {
14+
fn t3() -> [u8; std::mem::size_of::<Self>()] {} //~ERROR generic `Self`
15+
}
16+
17+
trait Baz {
18+
fn hey();
19+
}
20+
21+
impl Baz for u16 {
22+
fn hey() {
23+
let _: [u8; std::mem::size_of::<Self>()]; // ok
24+
}
25+
}
26+
27+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
error: generic parameters must not be used inside of non trivial constant values
2+
--> $DIR/self-ty-in-const-1.rs:4:41
3+
|
4+
LL | fn t1() -> [u8; std::mem::size_of::<Self>()];
5+
| ^^^^ non-trivial anonymous constants must not depend on the parameter `Self`
6+
|
7+
= help: it is currently only allowed to use either `Self` or `{ Self }` as generic constants
8+
9+
error: generic `Self` types are currently not permitted in anonymous constants
10+
--> $DIR/self-ty-in-const-1.rs:14:41
11+
|
12+
LL | fn t3() -> [u8; std::mem::size_of::<Self>()] {}
13+
| ^^^^
14+
|
15+
note: not a concrete type
16+
--> $DIR/self-ty-in-const-1.rs:13:1
17+
|
18+
LL | / impl<T> Bar<T> {
19+
LL | | fn t3() -> [u8; std::mem::size_of::<Self>()] {}
20+
LL | | }
21+
| |_^
22+
23+
error: aborting due to 2 previous errors
24+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#![feature(min_const_generics)]
2+
3+
struct Bar<T>(T);
4+
5+
trait Baz {
6+
fn hey();
7+
}
8+
9+
impl Baz for u16 {
10+
fn hey() {
11+
let _: [u8; std::mem::size_of::<Self>()]; // ok
12+
}
13+
}
14+
15+
impl<T> Baz for Bar<T> {
16+
fn hey() {
17+
let _: [u8; std::mem::size_of::<Self>()]; //~ERROR generic `Self`
18+
}
19+
}
20+
21+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
error: generic `Self` types are currently not permitted in anonymous constants
2+
--> $DIR/self-ty-in-const-2.rs:17:41
3+
|
4+
LL | let _: [u8; std::mem::size_of::<Self>()];
5+
| ^^^^
6+
|
7+
note: not a concrete type
8+
--> $DIR/self-ty-in-const-2.rs:15:1
9+
|
10+
LL | / impl<T> Baz for Bar<T> {
11+
LL | | fn hey() {
12+
LL | | let _: [u8; std::mem::size_of::<Self>()];
13+
LL | | }
14+
LL | | }
15+
| |_^
16+
17+
error: aborting due to previous error
18+

0 commit comments

Comments
 (0)