Skip to content

Commit

Permalink
Auto merge of #75384 - JulianKnodt:cg_def, r=varkor,lcnr
Browse files Browse the repository at this point in the history
implement `feature(const_generics_defaults)`

Implements const generics defaults `struct Example<const N: usize=3>`, as well as a query for getting the default of a given const-parameter's def id. There are some remaining FIXME's but they were specified as not blocking for merging this PR. This also puts the defaults behind the unstable feature gate `#![feature(const_generics_defaults)]`.

~~This currently creates a field which is always false on `GenericParamDefKind` for future use when
consts are permitted to have defaults. I'm not sure if this is exactly what is best for adding default parameters, but I mimicked the style of type defaults, so hopefully this is ok.~~

r? `@lcnr`
  • Loading branch information
bors committed Mar 24, 2021
2 parents db492ec + 33370fd commit 5b33de3
Show file tree
Hide file tree
Showing 73 changed files with 517 additions and 191 deletions.
1 change: 0 additions & 1 deletion compiler/rustc_ast_lowering/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2290,7 +2290,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
this.lower_ty(&ty, ImplTraitContext::disallowed())
});
let default = default.as_ref().map(|def| self.lower_anon_const(def));

(hir::ParamName::Plain(param.ident), hir::GenericParamKind::Const { ty, default })
}
};
Expand Down
15 changes: 9 additions & 6 deletions compiler/rustc_ast_passes/src/ast_validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1150,20 +1150,23 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
}

fn visit_generics(&mut self, generics: &'a Generics) {
let mut prev_ty_default = None;
let cg_defaults = self.session.features_untracked().const_generics_defaults;

let mut prev_param_default = None;
for param in &generics.params {
match param.kind {
GenericParamKind::Lifetime => (),
GenericParamKind::Type { default: Some(_), .. } => {
prev_ty_default = Some(param.ident.span);
GenericParamKind::Type { default: Some(_), .. }
| GenericParamKind::Const { default: Some(_), .. } => {
prev_param_default = Some(param.ident.span);
}
GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
if let Some(span) = prev_ty_default {
if let Some(span) = prev_param_default {
let mut err = self.err_handler().struct_span_err(
span,
"type parameters with a default must be trailing",
"generic parameters with a default must be trailing",
);
if matches!(param.kind, GenericParamKind::Const { .. }) {
if matches!(param.kind, GenericParamKind::Const { .. }) && !cg_defaults {
err.note(
"using type defaults and const parameters \
in the same parameter list is currently not permitted",
Expand Down
6 changes: 4 additions & 2 deletions compiler/rustc_ast_pretty/src/pprust/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2659,8 +2659,10 @@ impl<'a> State<'a> {
s.word_space(":");
s.print_type(ty);
s.print_type_bounds(":", &param.bounds);
if let Some(ref _default) = default {
// FIXME(const_generics_defaults): print the `default` value here
if let Some(ref default) = default {
s.s.space();
s.word_space("=");
s.print_expr(&default.value);
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_error_codes/src/error_codes/E0128.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ struct Foo<T = U, U = ()> {
field1: T,
field2: U,
}
// error: type parameters with a default cannot use forward declared
// error: generic parameters with a default cannot use forward declared
// identifiers
```

Expand Down
9 changes: 8 additions & 1 deletion compiler/rustc_hir/src/intravisit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,9 @@ pub trait Visitor<'v>: Sized {
fn visit_generic_param(&mut self, p: &'v GenericParam<'v>) {
walk_generic_param(self, p)
}
fn visit_const_param_default(&mut self, _param: HirId, ct: &'v AnonConst) {
walk_const_param_default(self, ct)
}
fn visit_generics(&mut self, g: &'v Generics<'v>) {
walk_generics(self, g)
}
Expand Down Expand Up @@ -869,13 +872,17 @@ pub fn walk_generic_param<'v, V: Visitor<'v>>(visitor: &mut V, param: &'v Generi
GenericParamKind::Const { ref ty, ref default } => {
visitor.visit_ty(ty);
if let Some(ref default) = default {
visitor.visit_anon_const(default);
visitor.visit_const_param_default(param.hir_id, default);
}
}
}
walk_list!(visitor, visit_param_bound, param.bounds);
}

pub fn walk_const_param_default<'v, V: Visitor<'v>>(visitor: &mut V, ct: &'v AnonConst) {
visitor.visit_anon_const(ct)
}

pub fn walk_generics<'v, V: Visitor<'v>>(visitor: &mut V, generics: &'v Generics<'v>) {
walk_list!(visitor, visit_generic_param, generics.params);
walk_list!(visitor, visit_where_predicate, generics.where_clause.predicates);
Expand Down
6 changes: 4 additions & 2 deletions compiler/rustc_hir_pretty/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2266,8 +2266,10 @@ impl<'a> State<'a> {
GenericParamKind::Const { ref ty, ref default } => {
self.word_space(":");
self.print_type(ty);
if let Some(ref _default) = default {
// FIXME(const_generics_defaults): print the `default` value here
if let Some(ref default) = default {
self.s.space();
self.word_space("=");
self.print_anon_const(&default)
}
}
}
Expand Down
44 changes: 19 additions & 25 deletions compiler/rustc_infer/src/infer/error_reporting/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ use rustc_hir::{Item, ItemKind, Node};
use rustc_middle::ty::error::TypeError;
use rustc_middle::ty::{
self,
subst::{Subst, SubstsRef},
subst::{GenericArgKind, Subst, SubstsRef},
Region, Ty, TyCtxt, TypeFoldable,
};
use rustc_span::{sym, BytePos, DesugaringKind, Pos, Span};
Expand Down Expand Up @@ -957,33 +957,27 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
) -> SubstsRef<'tcx> {
let generics = self.tcx.generics_of(def_id);
let mut num_supplied_defaults = 0;
let mut type_params = generics
.params
.iter()
.rev()
.filter_map(|param| match param.kind {
ty::GenericParamDefKind::Lifetime => None,
ty::GenericParamDefKind::Type { has_default, .. } => {
Some((param.def_id, has_default))
}
ty::GenericParamDefKind::Const => None, // FIXME(const_generics_defaults)
})
.peekable();
let has_default = {
let has_default = type_params.peek().map(|(_, has_default)| has_default);
*has_default.unwrap_or(&false)
};
if has_default {
let types = substs.types().rev();
for ((def_id, has_default), actual) in type_params.zip(types) {
if !has_default {
break;

let default_params = generics.params.iter().rev().filter_map(|param| match param.kind {
ty::GenericParamDefKind::Type { has_default: true, .. } => Some(param.def_id),
ty::GenericParamDefKind::Const { has_default: true } => Some(param.def_id),
_ => None,
});
for (def_id, actual) in default_params.zip(substs.iter().rev()) {
match actual.unpack() {
GenericArgKind::Const(c) => {
if self.tcx.const_param_default(def_id).subst(self.tcx, substs) != c {
break;
}
}
if self.tcx.type_of(def_id).subst(self.tcx, substs) != actual {
break;
GenericArgKind::Type(ty) => {
if self.tcx.type_of(def_id).subst(self.tcx, substs) != ty {
break;
}
}
num_supplied_defaults += 1;
_ => break,
}
num_supplied_defaults += 1;
}
let len = generics.params.len();
let mut generics = generics.clone();
Expand Down
8 changes: 8 additions & 0 deletions compiler/rustc_metadata/src/rmeta/decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -953,6 +953,14 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
self.root.tables.expn_that_defined.get(self, id).unwrap().decode((self, sess))
}

fn get_const_param_default(
&self,
tcx: TyCtxt<'tcx>,
id: DefIndex,
) -> rustc_middle::ty::Const<'tcx> {
self.root.tables.const_defaults.get(self, id).unwrap().decode((self, tcx))
}

/// Iterates over all the stability attributes in the given crate.
fn get_lib_features(&self, tcx: TyCtxt<'tcx>) -> &'tcx [(Symbol, Option<Symbol>)] {
// FIXME: For a proc macro crate, not sure whether we should return the "host"
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ provide! { <'tcx> tcx, def_id, other, cdata,
promoted_mir => { tcx.arena.alloc(cdata.get_promoted_mir(tcx, def_id.index)) }
mir_abstract_const => { cdata.get_mir_abstract_const(tcx, def_id.index) }
unused_generic_params => { cdata.get_unused_generic_params(def_id.index) }
const_param_default => { tcx.mk_const(cdata.get_const_param_default(tcx, def_id.index)) }
mir_const_qualif => { cdata.mir_const_qualif(def_id.index) }
fn_sig => { cdata.fn_sig(def_id.index, tcx) }
inherent_impls => { cdata.get_inherent_implementations_for_type(tcx, def_id.index) }
Expand Down
13 changes: 6 additions & 7 deletions compiler/rustc_metadata/src/rmeta/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1876,13 +1876,12 @@ impl EncodeContext<'a, 'tcx> {
default.is_some(),
);
}
GenericParamKind::Const { .. } => {
self.encode_info_for_generic_param(
def_id.to_def_id(),
EntryKind::ConstParam,
true,
);
// FIXME(const_generics_defaults)
GenericParamKind::Const { ref default, .. } => {
let def_id = def_id.to_def_id();
self.encode_info_for_generic_param(def_id, EntryKind::ConstParam, true);
if default.is_some() {
record!(self.tables.const_defaults[def_id] <- self.tcx.const_param_default(def_id))
}
}
}
}
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_metadata/src/rmeta/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -307,13 +307,14 @@ define_tables! {
mir_for_ctfe: Table<DefIndex, Lazy!(mir::Body<'tcx>)>,
promoted_mir: Table<DefIndex, Lazy!(IndexVec<mir::Promoted, mir::Body<'tcx>>)>,
mir_abstract_consts: Table<DefIndex, Lazy!(&'tcx [mir::abstract_const::Node<'tcx>])>,
const_defaults: Table<DefIndex, Lazy<rustc_middle::ty::Const<'tcx>>>,
unused_generic_params: Table<DefIndex, Lazy<FiniteBitSet<u32>>>,
// `def_keys` and `def_path_hashes` represent a lazy version of a
// `DefPathTable`. This allows us to avoid deserializing an entire
// `DefPathTable` up front, since we may only ever use a few
// definitions from any given crate.
def_keys: Table<DefIndex, Lazy<DefKey>>,
def_path_hashes: Table<DefIndex, Lazy<DefPathHash>>
def_path_hashes: Table<DefIndex, Lazy<DefPathHash>>,
}

#[derive(Copy, Clone, MetadataEncodable, MetadataDecodable)]
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_middle/src/hir/map/collector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,10 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
}
}

fn visit_const_param_default(&mut self, param: HirId, ct: &'hir AnonConst) {
self.with_parent(param, |this| intravisit::walk_const_param_default(this, ct))
}

fn visit_trait_item(&mut self, ti: &'hir TraitItem<'hir>) {
self.with_dep_node_owner(ti.def_id, ti, |this, hash| {
this.insert_with_hash(ti.span, ti.hir_id(), Node::TraitItem(ti), hash);
Expand Down
6 changes: 6 additions & 0 deletions compiler/rustc_middle/src/query/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,12 @@ rustc_queries! {
desc { |tcx| "computing the optional const parameter of `{}`", tcx.def_path_str(key.to_def_id()) }
}

/// Given the def_id of a const-generic parameter, computes the associated default const
/// parameter. e.g. `fn example<const N: usize=3>` called on `N` would return `3`.
query const_param_default(param: DefId) -> &'tcx ty::Const<'tcx> {
desc { |tcx| "compute const default for a given parameter `{}`", tcx.def_path_str(param) }
}

/// Records the type of every item.
query type_of(key: DefId) -> Ty<'tcx> {
desc { |tcx| "computing type of `{}`", tcx.def_path_str(key) }
Expand Down
17 changes: 16 additions & 1 deletion compiler/rustc_middle/src/ty/consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use crate::ty::{self, Ty, TyCtxt};
use crate::ty::{ParamEnv, ParamEnvAnd};
use rustc_errors::ErrorReported;
use rustc_hir as hir;
use rustc_hir::def_id::LocalDefId;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_macros::HashStable;

mod int;
Expand Down Expand Up @@ -202,3 +202,18 @@ impl<'tcx> Const<'tcx> {
.unwrap_or_else(|| bug!("expected usize, got {:#?}", self))
}
}

pub fn const_param_default<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx Const<'tcx> {
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
let default_def_id = match tcx.hir().get(hir_id) {
hir::Node::GenericParam(hir::GenericParam {
kind: hir::GenericParamKind::Const { ty: _, default: Some(ac) },
..
}) => tcx.hir().local_def_id(ac.hir_id),
_ => span_bug!(
tcx.def_span(def_id),
"`const_param_default` expected a generic parameter with a constant"
),
};
Const::from_anon_const(tcx, default_def_id)
}
4 changes: 2 additions & 2 deletions compiler/rustc_middle/src/ty/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2221,7 +2221,7 @@ impl<'tcx> TyCtxt<'tcx> {
let adt_def = self.adt_def(wrapper_def_id);
let substs =
InternalSubsts::for_item(self, wrapper_def_id, |param, substs| match param.kind {
GenericParamDefKind::Lifetime | GenericParamDefKind::Const => bug!(),
GenericParamDefKind::Lifetime | GenericParamDefKind::Const { .. } => bug!(),
GenericParamDefKind::Type { has_default, .. } => {
if param.index == 0 {
ty_param.into()
Expand Down Expand Up @@ -2416,7 +2416,7 @@ impl<'tcx> TyCtxt<'tcx> {
self.mk_region(ty::ReEarlyBound(param.to_early_bound_region_data())).into()
}
GenericParamDefKind::Type { .. } => self.mk_ty_param(param.index, param.name).into(),
GenericParamDefKind::Const => {
GenericParamDefKind::Const { .. } => {
self.mk_const_param(param.index, param.name, self.type_of(param.def_id)).into()
}
}
Expand Down
20 changes: 12 additions & 8 deletions compiler/rustc_middle/src/ty/generics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,22 +18,24 @@ pub enum GenericParamDefKind {
object_lifetime_default: ObjectLifetimeDefault,
synthetic: Option<hir::SyntheticTyParamKind>,
},
Const,
Const {
has_default: bool,
},
}

impl GenericParamDefKind {
pub fn descr(&self) -> &'static str {
match self {
GenericParamDefKind::Lifetime => "lifetime",
GenericParamDefKind::Type { .. } => "type",
GenericParamDefKind::Const => "constant",
GenericParamDefKind::Const { .. } => "constant",
}
}
pub fn to_ord(&self, tcx: TyCtxt<'_>) -> ast::ParamKindOrd {
match self {
GenericParamDefKind::Lifetime => ast::ParamKindOrd::Lifetime,
GenericParamDefKind::Type { .. } => ast::ParamKindOrd::Type,
GenericParamDefKind::Const => {
GenericParamDefKind::Const { .. } => {
ast::ParamKindOrd::Const { unordered: tcx.features().const_generics }
}
}
Expand Down Expand Up @@ -105,7 +107,7 @@ impl<'tcx> Generics {
match param.kind {
GenericParamDefKind::Lifetime => own_counts.lifetimes += 1,
GenericParamDefKind::Type { .. } => own_counts.types += 1,
GenericParamDefKind::Const => own_counts.consts += 1,
GenericParamDefKind::Const { .. } => own_counts.consts += 1,
}
}

Expand All @@ -121,8 +123,8 @@ impl<'tcx> Generics {
GenericParamDefKind::Type { has_default, .. } => {
own_defaults.types += has_default as usize;
}
GenericParamDefKind::Const => {
// FIXME(const_generics:defaults)
GenericParamDefKind::Const { has_default } => {
own_defaults.consts += has_default as usize;
}
}
}
Expand All @@ -146,7 +148,9 @@ impl<'tcx> Generics {
pub fn own_requires_monomorphization(&self) -> bool {
for param in &self.params {
match param.kind {
GenericParamDefKind::Type { .. } | GenericParamDefKind::Const => return true,
GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => {
return true;
}
GenericParamDefKind::Lifetime => {}
}
}
Expand Down Expand Up @@ -189,7 +193,7 @@ impl<'tcx> Generics {
pub fn const_param(&'tcx self, param: &ParamConst, tcx: TyCtxt<'tcx>) -> &GenericParamDef {
let param = self.param_at(param.index as usize, tcx);
match param.kind {
GenericParamDefKind::Const => param,
GenericParamDefKind::Const { .. } => param,
_ => bug!("expected const parameter, but found another generic parameter"),
}
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/ty/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -593,7 +593,7 @@ fn polymorphize<'tcx>(
},

// Simple case: If parameter is a const or type parameter..
ty::GenericParamDefKind::Const | ty::GenericParamDefKind::Type { .. } if
ty::GenericParamDefKind::Const { .. } | ty::GenericParamDefKind::Type { .. } if
// ..and is within range and unused..
unused.contains(param.index).unwrap_or(false) =>
// ..then use the identity for this parameter.
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_middle/src/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1949,6 +1949,7 @@ pub fn provide(providers: &mut ty::query::Providers) {
trait_impls_of: trait_def::trait_impls_of_provider,
all_local_trait_impls: trait_def::all_local_trait_impls,
type_uninhabited_from: inhabitedness::type_uninhabited_from,
const_param_default: consts::const_param_default,
..*providers
};
}
Expand Down
Loading

0 comments on commit 5b33de3

Please sign in to comment.