Skip to content

implement feature(const_generics_defaults) #75384

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

Merged
merged 8 commits into from
Mar 24, 2021
Merged
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
1 change: 0 additions & 1 deletion compiler/rustc_ast_lowering/src/lib.rs
Original file line number Diff line number Diff line change
@@ -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 })
}
};
15 changes: 9 additions & 6 deletions compiler/rustc_ast_passes/src/ast_validation.rs
Original file line number Diff line number Diff line change
@@ -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",
6 changes: 4 additions & 2 deletions compiler/rustc_ast_pretty/src/pprust/state.rs
Original file line number Diff line number Diff line change
@@ -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);
}
}
}
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
@@ -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
```

9 changes: 8 additions & 1 deletion compiler/rustc_hir/src/intravisit.rs
Original file line number Diff line number Diff line change
@@ -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)
}
@@ -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);
6 changes: 4 additions & 2 deletions compiler/rustc_hir_pretty/src/lib.rs
Original file line number Diff line number Diff line change
@@ -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)
}
}
}
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
@@ -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};
@@ -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();
8 changes: 8 additions & 0 deletions compiler/rustc_metadata/src/rmeta/decoder.rs
Original file line number Diff line number Diff line change
@@ -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"
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
@@ -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) }
13 changes: 6 additions & 7 deletions compiler/rustc_metadata/src/rmeta/encoder.rs
Original file line number Diff line number Diff line change
@@ -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))
}
}
}
}
3 changes: 2 additions & 1 deletion compiler/rustc_metadata/src/rmeta/mod.rs
Original file line number Diff line number Diff line change
@@ -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)]
4 changes: 4 additions & 0 deletions compiler/rustc_middle/src/hir/map/collector.rs
Original file line number Diff line number Diff line change
@@ -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);
6 changes: 6 additions & 0 deletions compiler/rustc_middle/src/query/mod.rs
Original file line number Diff line number Diff line change
@@ -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) }
17 changes: 16 additions & 1 deletion compiler/rustc_middle/src/ty/consts.rs
Original file line number Diff line number Diff line change
@@ -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;
@@ -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
@@ -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()
@@ -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()
}
}
20 changes: 12 additions & 8 deletions compiler/rustc_middle/src/ty/generics.rs
Original file line number Diff line number Diff line change
@@ -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 }
}
}
@@ -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,
}
}

@@ -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;
}
}
}
@@ -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 => {}
}
}
@@ -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"),
}
}
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/ty/instance.rs
Original file line number Diff line number Diff line change
@@ -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.
1 change: 1 addition & 0 deletions compiler/rustc_middle/src/ty/mod.rs
Original file line number Diff line number Diff line change
@@ -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
};
}
Loading