Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

allow concrete self types in consts #76195

Merged
merged 3 commits into from
Sep 14, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion compiler/rustc_hir/src/def.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_passes/src/dead.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_resolve/src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down
7 changes: 5 additions & 2 deletions compiler/rustc_resolve/src/late.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Comment on lines +114 to 116
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideally this would be a new enum, but it is great you added docs to it.


/// We passed through a module.
Expand Down Expand Up @@ -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);
});
});
Expand Down Expand Up @@ -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);
Expand Down
23 changes: 16 additions & 7 deletions compiler/rustc_resolve/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>],
Expand Down Expand Up @@ -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 {
Expand Down
23 changes: 20 additions & 3 deletions compiler/rustc_typeck/src/astconv/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion src/librustdoc/clean/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down
10 changes: 7 additions & 3 deletions src/test/ui/const-generics/issues/issue-62504.min.stderr
Original file line number Diff line number Diff line change
@@ -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

2 changes: 1 addition & 1 deletion src/test/ui/const-generics/issues/issue-62504.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -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() {}
Original file line number Diff line number Diff line change
@@ -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

Original file line number Diff line number Diff line change
@@ -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() {}
Original file line number Diff line number Diff line change
@@ -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