Skip to content
Draft
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
4 changes: 3 additions & 1 deletion compiler/rustc_ast/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,8 @@ pub enum GenericParamKind {
span: Span,
/// Optional default value for the const generic param.
default: Option<AnonConst>,
#[visitable(ignore)]
arg_pos: Option<u32>,
},
}

Expand Down Expand Up @@ -4483,7 +4485,7 @@ mod size_asserts {
static_assert_size!(GenericArg, 24);
static_assert_size!(GenericArgs, 40);
static_assert_size!(GenericBound, 80);
static_assert_size!(GenericParam, 80);
static_assert_size!(GenericParam, 88);
static_assert_size!(Generics, 40);
static_assert_size!(Impl, 80);
static_assert_size!(Item, 144);
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_ast_lowering/src/delegation/generics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -641,6 +641,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
hir::GenericParamKind::Const {
ty: self.arena.alloc(hir::Ty { kind, hir_id, span }),
default: None,
arg_pos: None,
}
}
};
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_ast_lowering/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2355,7 +2355,7 @@ impl<'hir> LoweringContext<'_, 'hir> {

(hir::ParamName::Plain(self.lower_ident(param.ident)), kind)
}
GenericParamKind::Const { ty, span: _, default } => {
GenericParamKind::Const { ty, default, arg_pos, .. } => {
let ty = self.lower_ty_alloc(
ty,
ImplTraitContext::Disallowed(ImplTraitPosition::GenericDefault),
Expand Down Expand Up @@ -2388,7 +2388,7 @@ impl<'hir> LoweringContext<'_, 'hir> {

(
hir::ParamName::Plain(self.lower_ident(param.ident)),
hir::GenericParamKind::Const { ty, default },
hir::GenericParamKind::Const { ty, default, arg_pos: *arg_pos },
)
}
}
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_ast_passes/src/ast_validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1380,11 +1380,11 @@ fn validate_generic_param_order(dcx: DiagCtxtHandle<'_>, generics: &[GenericPara
}
GenericParamKind::Type { default: None } => (),
GenericParamKind::Lifetime => (),
GenericParamKind::Const { ty: _, span: _, default: Some(default) } => {
GenericParamKind::Const { default: Some(default), .. } => {
ordered_params += " = ";
ordered_params += &pprust::expr_to_string(&default.value);
}
GenericParamKind::Const { ty: _, span: _, default: None } => (),
GenericParamKind::Const { default: None, .. } => (),
}
first = false;
}
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_ast_passes/src/feature_gate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -442,6 +442,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
gate_all!(final_associated_functions, "`final` on trait functions is experimental");
gate_all!(fn_delegation, "functions delegation is not yet fully implemented");
gate_all!(frontmatter, "frontmatters are experimental");
gate_all!(function_arg_const_generics, "function arg const generics are experimental");
gate_all!(gen_blocks, "gen blocks are experimental");
gate_all!(generic_const_items, "generic const items are experimental");
gate_all!(global_registration, "global registration is experimental");
Expand Down
15 changes: 7 additions & 8 deletions compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,14 +117,13 @@ pub(crate) fn expand_deriving_coerce_pointee(
GenericParamKind::Type { default: _ } => {
cx.typaram(p.span(), p.ident, p.bounds.clone(), None)
}
GenericParamKind::Const { ty, span: _, default: _ } => cx
.const_param(
p.span(),
p.ident,
p.bounds.clone(),
ty.clone(),
None,
),
GenericParamKind::Const { ty, .. } => cx.const_param(
p.span(),
p.ident,
p.bounds.clone(),
ty.clone(),
None,
),
})
.collect(),
where_clause: generics.where_clause.clone(),
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -649,6 +649,7 @@ impl<'a> TraitDef<'a> {

// We can't have default values inside impl block
default: None,
arg_pos: None,
};
let mut param_clone = param.clone();
param_clone.kind = const_nodefault_kind;
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_builtin_macros/src/deriving/reborrow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ fn impl_generics(cx: &ExtCtxt<'_>, generics: &Generics) -> Generics {
GenericParamKind::Type { default: _ } => {
cx.typaram(param.span(), param.ident, param.bounds.clone(), None)
}
GenericParamKind::Const { ty, span: _, default: _ } => cx.const_param(
GenericParamKind::Const { ty, .. } => cx.const_param(
param.span(),
param.ident,
param.bounds.clone(),
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_expand/src/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ impl<'a> ExtCtxt<'a> {
attrs: AttrVec::new(),
bounds,
is_placeholder: false,
kind: ast::GenericParamKind::Const { ty, span: DUMMY_SP, default },
kind: ast::GenericParamKind::Const { ty, span: DUMMY_SP, default, arg_pos: None },
colon_span: None,
}
}
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_feature/src/unstable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -542,6 +542,8 @@ declare_features! (
(internal, freeze_impls, "1.78.0", Some(121675)),
/// Frontmatter `---` blocks for use by external tools.
(unstable, frontmatter, "1.88.0", Some(136889)),
/// Should I open an issue for this? ask Boxy
(incomplete, function_arg_const_generics, "CURRENT_RUSTC_VERSION", Some(162540)),
/// Allows defining gen blocks and `gen fn`.
(unstable, gen_blocks, "1.75.0", Some(117078)),
/// Allows using generics in more complex const expressions, based on definitional equality.
Expand Down Expand Up @@ -855,6 +857,7 @@ pub const INCOMPATIBLE_FEATURES: &[(Symbol, Symbol)] = &[

/// Some features require one or more other features to be enabled.
pub const DEPENDENT_FEATURES: &[(Symbol, &[Symbol])] = &[
(sym::function_arg_const_generics, &[sym::min_generic_const_args]),
(sym::generic_const_args, &[sym::min_generic_const_args]),
(sym::macroless_generic_const_args, &[sym::min_generic_const_args]),
(sym::macroless_const_item_generic_const_args, &[sym::min_generic_const_args]),
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_hir/src/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -848,6 +848,7 @@ pub enum GenericParamKind<'hir> {
ty: &'hir Ty<'hir>,
/// Optional default value for the const generic param
default: Option<&'hir ConstArg<'hir>>,
arg_pos: Option<u32>,
},
}

Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir/src/intravisit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1165,7 +1165,7 @@ pub fn walk_generic_param<'v, V: Visitor<'v>>(
GenericParamKind::Type { ref default, .. } => {
visit_opt!(visitor, visit_ty_unambig, default)
}
GenericParamKind::Const { ref ty, ref default } => {
GenericParamKind::Const { ref ty, ref default, arg_pos: _ } => {
try_visit!(visitor.visit_ty_unambig(ty));
if let Some(default) = default {
try_visit!(visitor.visit_const_param_default(*hir_id, default));
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_hir_analysis/src/collect/generics_of.rs
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {

ty::GenericParamDefKind::Type { has_default: default.is_some(), synthetic }
}
GenericParamKind::Const { ty: _, default } => {
GenericParamKind::Const { ty: _, default, arg_pos } => {
if default.is_some() {
match param_default_policy.expect("no policy for generic param default") {
ParamDefaultPolicy::Allowed => {}
Expand All @@ -322,7 +322,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
}
}

ty::GenericParamDefKind::Const { has_default: default.is_some() }
ty::GenericParamDefKind::Const { has_default: default.is_some(), arg_pos }
}
};
Some(ty::GenericParamDef {
Expand Down Expand Up @@ -525,7 +525,7 @@ impl<'v> Visitor<'v> for AnonConstInParamTyDetector {
type Result = ControlFlow<()>;

fn visit_generic_param(&mut self, p: &'v hir::GenericParam<'v>) -> Self::Result {
if let GenericParamKind::Const { ty, default: _ } = p.kind {
if let GenericParamKind::Const { ty, default: _, arg_pos: _ } = p.kind {
let prev = self.in_param_ty;
self.in_param_ty = true;
let res = self.visit_ty_unambig(ty);
Expand Down
5 changes: 3 additions & 2 deletions compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -439,8 +439,9 @@ pub(crate) fn check_generic_arg_count(
.iter()
.filter(|param| matches!(param.kind, ty::GenericParamDefKind::Type { synthetic: true, .. }))
.count();
let arg_const_param_count = gen_params.own_arg_pos_consts().count();
let named_type_param_count = param_counts.types - has_self as usize - synth_type_param_count;
let named_const_param_count = param_counts.consts;
let named_const_param_count = param_counts.consts - arg_const_param_count;
let infer_lifetimes =
(gen_pos != GenericArgPosition::Type || seg.infer_args) && !gen_args.has_lifetime_args();

Expand Down Expand Up @@ -616,7 +617,7 @@ pub(crate) fn check_generic_arg_count(
let expected_min = if seg.infer_args {
0
} else {
param_counts.consts + named_type_param_count
named_const_param_count + named_type_param_count
- default_counts.types
- default_counts.consts
};
Expand Down
51 changes: 51 additions & 0 deletions compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2387,6 +2387,57 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
self.check_param_uses_if_mcg(ct, tcx.hir_span(path_hir_id), false)
}

pub fn lower_const_arg_expr(&self, expr: &hir::Expr<'_>, ty: Ty<'tcx>) -> Const<'tcx> {
let tcx = self.tcx();
match expr.kind {
hir::ExprKind::Lit(lit) => {
self.lower_const_arg_literal(&lit.node, false, ty, expr.span)
}
hir::ExprKind::Unary(
hir::UnOp::Neg,
hir::Expr { kind: hir::ExprKind::Lit(lit), .. },
) => self.lower_const_arg_literal(&lit.node, true, ty, expr.span),
hir::ExprKind::Path(hir::QPath::Resolved(_, hir::Path { res: Res::Local(_), .. })) => {
Const::new_error(tcx, self.dcx().span_err(expr.span, "Path error"))
}
hir::ExprKind::Path(hir::QPath::Resolved(maybe_qself, path)) => {
let opt_self_ty = maybe_qself.as_ref().map(|qself| self.lower_ty(qself));
self.lower_resolved_const_path(opt_self_ty, path, expr.hir_id)
}
hir::ExprKind::Path(hir::QPath::TypeRelative(hir_self_ty, segment)) => {
let self_ty = self.lower_ty(hir_self_ty);
self.lower_type_relative_const_path(
self_ty,
hir_self_ty,
segment,
expr.hir_id,
expr.span,
)
.unwrap_or_else(|guard| Const::new_error(tcx, guard))
}
hir::ExprKind::ConstBlock(block) => {
let root = tcx.typeck_root_def_id_local(block.def_id);
let parent_args = ty::GenericArgs::identity_for_item(tcx, root);
let args =
ty::InlineConstArgs::new(tcx, ty::InlineConstArgsParts { parent_args, ty })
.args;
Const::new_alias(
tcx,
ty::IsRigid::No,
ty::AliasConst::new(
tcx,
ty::AliasConstKind::Anon { def_id: block.def_id.to_def_id() },
args,
),
)
}
_ => Const::new_error(
tcx,
self.dcx().span_err(expr.span, "Some other variant we dont support"),
),
}
}

/// Lower a [`hir::ConstArg`] to a (type-level) [`ty::Const`].
#[instrument(skip(self), level = "debug")]
pub fn lower_const_arg(&self, const_arg: &hir::ConstArg<'_>, ty: Ty<'tcx>) -> Const<'tcx> {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir_pretty/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2476,7 +2476,7 @@ impl<'a> State<'a> {
self.print_type(default);
}
}
GenericParamKind::Const { ty, ref default } => {
GenericParamKind::Const { ty, ref default, arg_pos: _ } => {
self.word_space(":");
self.print_type(ty);
if let Some(default) = default {
Expand Down
12 changes: 11 additions & 1 deletion compiler/rustc_hir_typeck/src/callee.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use std::borrow::Cow;
use std::iter;

use rustc_abi::{CanonAbi, ExternAbi};
Expand Down Expand Up @@ -666,11 +667,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
fn_id: SplatLoweringInfo<'tcx>,
callee_generic_args: Option<GenericArgsRef<'tcx>>,
) {
let mut formal_inputs = Cow::Borrowed(fn_sig.inputs());
if let (SplatLoweringInfo::FnDef(def_id), Some(args)) = (fn_id, callee_generic_args) {
for (param, pos) in self.tcx.generics_of(def_id).own_arg_pos_consts() {
let ty = self.tcx.type_of(param.def_id).instantiate(self.tcx, args).skip_norm_wip();
let ty = self.normalize(call_expr.span, Unnormalized::new_wip(ty));
formal_inputs.to_mut().insert(pos as usize, ty);
}
}

let do_check = || {
self.check_argument_types(
call_expr.span,
call_expr,
fn_sig.inputs(),
&formal_inputs,
fn_sig.output(),
expected,
arg_exprs,
Expand Down
16 changes: 14 additions & 2 deletions compiler/rustc_hir_typeck/src/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
//!
//! See [`rustc_hir_analysis::check`] for more context on type checking in general.

use std::borrow::Cow;

use rustc_abi::{FIRST_VARIANT, FieldIdx};
use rustc_ast as ast;
use rustc_ast::util::parser::ExprPrecedence;
Expand Down Expand Up @@ -618,6 +620,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
call_expr_and_args.map_or(expr.span, |(e, _)| e.span),
expr.span,
expr.hir_id,
call_expr_and_args.map(|(_, args)| args),
)
.0
}
Expand Down Expand Up @@ -1488,14 +1491,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {

// Handle splatted method arguments
// self is already handled as `rcvr`, so it's never splatted here
let method_inputs = &method.sig.inputs()[1..];
let mut method_inputs = Cow::Borrowed(&method.sig.inputs()[1..]);
for (param, pos) in self.tcx.generics_of(method.def_id).own_arg_pos_consts() {
let ty = self
.tcx
.type_of(param.def_id)
.instantiate(self.tcx, method.args)
.skip_norm_wip();
method_inputs.to_mut().insert(pos as usize - 1, ty);
}

let method_tuple_args_flag =
TupleArgumentsFlag::with_fn_sig_kind(method.sig.fn_sig_kind, true);

self.check_argument_types(
segment.ident.span,
expr,
method_inputs,
&method_inputs,
method.sig.output(),
expected,
args,
Expand Down
31 changes: 31 additions & 0 deletions compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -614,6 +614,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
ct
}

pub(crate) fn lower_const_arg_expr(
&self,
expr: &hir::Expr<'_>,
ty: Ty<'tcx>,
) -> ty::Const<'tcx> {
let ct = self.lowerer().lower_const_arg_expr(expr, ty);
self.register_wf_obligation(ct.into(), expr.span, ObligationCauseCode::WellFormed(None));
ct
}

// If the type given by the user has free regions, save it for later, since
// NLL would like to enforce those. Also pass in types that involve
// projections, since those can resolve to `'static` bounds (modulo #54940,
Expand Down Expand Up @@ -1007,6 +1017,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
span: Span,
path_span: Span,
hir_id: HirId,
call_args: Option<&'tcx [hir::Expr<'tcx>]>,
) -> (Ty<'tcx>, Res) {
let tcx = self.tcx;

Expand Down Expand Up @@ -1292,6 +1303,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
generic_segments: &'a [GenericPathSegment],
infer_args_for_err: &'a FxHashSet<usize>,
segments: &'tcx [hir::PathSegment<'tcx>],
call_args: Option<&'tcx [hir::Expr<'tcx>]>,
}
impl<'a, 'tcx> GenericArgsLowerer<'a, 'tcx> for CtorGenericArgsCtxt<'a, 'tcx> {
fn args_for_def_id(
Expand Down Expand Up @@ -1360,6 +1372,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
infer_args: bool,
) -> ty::GenericArg<'tcx> {
let tcx = self.fcx.tcx();
if let Some(pos) = param.kind.arg_pos() {
let Some(args) = self.call_args else {
let guard =
self.fcx.dcx().span_err(self.span, "argument should be provided");
return ty::Const::new_error(tcx, guard).into();
};

let Some(arg) = args.get(pos as usize) else {
let guard = self
.fcx
.dcx()
.span_delayed_bug(self.span, "missing argument for const param");
return ty::Const::new_error(tcx, guard).into();
};
let ty =
tcx.type_of(param.def_id).instantiate(tcx, preceding_args).skip_norm_wip();
return self.fcx.lower_const_arg_expr(arg, ty).into();
}
if !infer_args && let Some(default) = param.default_value(tcx) {
// If we have a default, then it doesn't matter that we're not inferring
// the type/const arguments: We provide the default where any is missing.
Expand Down Expand Up @@ -1387,6 +1417,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
generic_segments: &generic_segments,
infer_args_for_err: &infer_args_for_err,
segments,
call_args,
},
)
});
Expand Down
Loading
Loading