Skip to content
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
34 changes: 33 additions & 1 deletion compiler/rustc_ast_lowering/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2396,6 +2396,35 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
};

match &expr.kind {
ExprKind::Call(func, args) if let ExprKind::Path(qself, path) = &func.kind => {
let qpath = self.lower_qpath(
func.id,
qself,
path,
ParamMode::Explicit,
AllowReturnTypeNotation::No,
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
None,
);

let lowered_args = self.arena.alloc_from_iter(args.iter().map(|arg| {
let const_arg = if let ExprKind::ConstBlock(anon_const) = &arg.kind {
let def_id = self.local_def_id(anon_const.id);
let def_kind = self.tcx.def_kind(def_id);
assert_eq!(DefKind::AnonConst, def_kind);
self.lower_anon_const_to_const_arg_direct(anon_const)
} else {
self.lower_expr_to_const_arg_direct(arg)
};

&*self.arena.alloc(const_arg)
}));

ConstArg {
hir_id: self.next_id(),
kind: hir::ConstArgKind::TupleCall(qpath, lowered_args),
}
}
ExprKind::Path(qself, path) => {
let qpath = self.lower_qpath(
expr.id,
Expand Down Expand Up @@ -2460,7 +2489,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
&& let StmtKind::Expr(expr) = &stmt.kind
&& matches!(
expr.kind,
ExprKind::Block(..) | ExprKind::Path(..) | ExprKind::Struct(..)
ExprKind::Block(..)
| ExprKind::Path(..)
| ExprKind::Struct(..)
| ExprKind::Call(..)
)
{
return self.lower_expr_to_const_arg_direct(expr);
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_hir/src/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -499,6 +499,7 @@ impl<'hir, Unambig> ConstArg<'hir, Unambig> {
match self.kind {
ConstArgKind::Struct(path, _) => path.span(),
ConstArgKind::Path(path) => path.span(),
ConstArgKind::TupleCall(path, _) => path.span(),
ConstArgKind::Anon(anon) => anon.span,
ConstArgKind::Error(span, _) => span,
ConstArgKind::Infer(span, _) => span,
Expand All @@ -519,6 +520,8 @@ pub enum ConstArgKind<'hir, Unambig = ()> {
Anon(&'hir AnonConst),
/// Represents construction of struct/struct variants
Struct(QPath<'hir>, &'hir [&'hir ConstArgExprField<'hir>]),
/// Tuple constructor variant
TupleCall(QPath<'hir>, &'hir [&'hir ConstArg<'hir>]),
/// Error const
Error(Span, ErrorGuaranteed),
/// This variant is not always used to represent inference consts, sometimes
Expand Down
7 changes: 7 additions & 0 deletions compiler/rustc_hir/src/intravisit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1090,6 +1090,13 @@ pub fn walk_const_arg<'v, V: Visitor<'v>>(

V::Result::output()
}
ConstArgKind::TupleCall(qpath, args) => {
try_visit!(visitor.visit_qpath(qpath, *hir_id, qpath.span()));
for arg in *args {
try_visit!(visitor.visit_const_arg_unambig(*arg));
}
V::Result::output()
}
ConstArgKind::Path(qpath) => visitor.visit_qpath(qpath, *hir_id, qpath.span()),
ConstArgKind::Anon(anon) => visitor.visit_anon_const(*anon),
ConstArgKind::Error(_, _) => V::Result::output(), // errors and spans are not important
Expand Down
135 changes: 133 additions & 2 deletions compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,7 @@ pub enum PermitVariants {
enum TypeRelativePath<'tcx> {
AssocItem(DefId, GenericArgsRef<'tcx>),
Variant { adt: Ty<'tcx>, variant_did: DefId },
Ctor { ctor_def_id: DefId, args: GenericArgsRef<'tcx> },
}

/// New-typed boolean indicating whether explicit late-bound lifetimes
Expand Down Expand Up @@ -1261,6 +1262,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
TypeRelativePath::Variant { adt, variant_did } => {
Ok((adt, DefKind::Variant, variant_did))
}
TypeRelativePath::Ctor { .. } => {
let e = tcx.dcx().span_err(span, "expected type, found tuple constructor");
Err(e)
}
}
}

Expand Down Expand Up @@ -1294,6 +1299,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
}
(def_id, args)
}
TypeRelativePath::Ctor { ctor_def_id, args } => {
return Ok(ty::Const::zero_sized(tcx, Ty::new_fn_def(tcx, ctor_def_id, args)));
}
// FIXME(mgca): implement support for this once ready to support all adt ctor expressions,
// not just const ctors
TypeRelativePath::Variant { .. } => {
Expand Down Expand Up @@ -1326,6 +1334,23 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
.iter()
.find(|vd| tcx.hygienic_eq(segment.ident, vd.ident(tcx), adt_def.did()));
if let Some(variant_def) = variant_def {
// FIXME(mgca): do we want constructor resolutions to take priority over
// other possible resolutions?
if matches!(mode, LowerTypeRelativePathMode::Const)
&& let Some((CtorKind::Fn, ctor_def_id)) = variant_def.ctor
{
tcx.check_stability(variant_def.def_id, Some(qpath_hir_id), span, None);
let _ = self.prohibit_generic_args(
slice::from_ref(segment).iter(),
GenericsArgsErrExtend::EnumVariant {
qself: hir_self_ty,
assoc_segment: segment,
adt_def,
},
);
let ty::Adt(_, enum_args) = self_ty.kind() else { unreachable!() };
return Ok(TypeRelativePath::Ctor { ctor_def_id, args: enum_args });
}
if let PermitVariants::Yes = mode.permit_variants() {
tcx.check_stability(variant_def.def_id, Some(qpath_hir_id), span, None);
let _ = self.prohibit_generic_args(
Expand Down Expand Up @@ -2266,12 +2291,106 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
hir::ConstArgKind::Struct(qpath, inits) => {
self.lower_const_arg_struct(hir_id, qpath, inits, const_arg.span())
}
hir::ConstArgKind::TupleCall(qpath, args) => {
self.lower_const_arg_tuple_call(hir_id, qpath, args, const_arg.span())
}
hir::ConstArgKind::Anon(anon) => self.lower_const_arg_anon(anon),
hir::ConstArgKind::Infer(span, ()) => self.ct_infer(None, span),
hir::ConstArgKind::Error(_, e) => ty::Const::new_error(tcx, e),
}
}

fn lower_const_arg_tuple_call(
&self,
hir_id: HirId,
qpath: hir::QPath<'tcx>,
args: &'tcx [&'tcx hir::ConstArg<'tcx>],
span: Span,
) -> Const<'tcx> {
let tcx = self.tcx();

let non_adt_or_variant_res = || {
let e = tcx.dcx().span_err(span, "tuple constructor with invalid base path");
ty::Const::new_error(tcx, e)
};

let ctor_const = match qpath {
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, hir_id)
}
hir::QPath::TypeRelative(hir_self_ty, segment) => {
let self_ty = self.lower_ty(hir_self_ty);
match self.lower_type_relative_const_path(
self_ty,
hir_self_ty,
segment,
hir_id,
span,
) {
Ok(c) => c,
Err(_) => return non_adt_or_variant_res(),
}
}
};

let Some(value) = ctor_const.try_to_value() else {
return non_adt_or_variant_res();
};

let (adt_def, adt_args, variant_did) = match value.ty.kind() {
ty::FnDef(def_id, fn_args)
if let DefKind::Ctor(CtorOf::Variant, _) = tcx.def_kind(*def_id) =>
{
let parent_did = tcx.parent(*def_id);
let enum_did = tcx.parent(parent_did);
(tcx.adt_def(enum_did), fn_args, parent_did)
}
ty::FnDef(def_id, fn_args)
if let DefKind::Ctor(CtorOf::Struct, _) = tcx.def_kind(*def_id) =>
{
let parent_did = tcx.parent(*def_id);
(tcx.adt_def(parent_did), fn_args, parent_did)
}
_ => return non_adt_or_variant_res(),
};

let variant_def = adt_def.variant_with_id(variant_did);
let variant_idx = adt_def.variant_index_with_id(variant_did).as_u32();

if args.len() != variant_def.fields.len() {
let e = tcx.dcx().span_err(
span,
format!(
"tuple constructor has {} arguments but {} were provided",
variant_def.fields.len(),
args.len()
),
);
return ty::Const::new_error(tcx, e);
}

let fields = variant_def
.fields
.iter()
.zip(args)
.map(|(field_def, arg)| {
self.lower_const_arg(arg, FeedConstTy::Param(field_def.did, adt_args))
})
.collect::<Vec<_>>();

let opt_discr_const = if adt_def.is_enum() {
let valtree = ty::ValTree::from_scalar_int(tcx, variant_idx.into());
Some(ty::Const::new_value(tcx, valtree, tcx.types.u32))
} else {
None
};

let valtree = ty::ValTree::from_branches(tcx, opt_discr_const.into_iter().chain(fields));
let adt_ty = Ty::new_adt(tcx, adt_def, adt_args);
ty::Const::new_value(tcx, valtree, adt_ty)
}

fn lower_const_arg_struct(
&self,
hir_id: HirId,
Expand Down Expand Up @@ -2403,6 +2522,20 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let args = self.lower_generic_args_of_path_segment(span, did, segment);
ty::Const::new_unevaluated(tcx, ty::UnevaluatedConst::new(did, args))
}
Res::Def(DefKind::Ctor(_, CtorKind::Fn), did) => {
assert_eq!(opt_self_ty, None);
let [leading_segments @ .., segment] = path.segments else { bug!() };
let _ = self
.prohibit_generic_args(leading_segments.iter(), GenericsArgsErrExtend::None);
let parent_did = tcx.parent(did);
let generics_did = if let DefKind::Ctor(CtorOf::Variant, _) = tcx.def_kind(did) {
tcx.parent(parent_did)
} else {
parent_did
};
let args = self.lower_generic_args_of_path_segment(span, generics_did, segment);
ty::Const::zero_sized(tcx, Ty::new_fn_def(tcx, did, args))
}
Res::Def(DefKind::AssocConst, did) => {
let trait_segment = if let [modules @ .., trait_, _item] = path.segments {
let _ = self.prohibit_generic_args(modules.iter(), GenericsArgsErrExtend::None);
Expand Down Expand Up @@ -2438,9 +2571,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
DefKind::Mod
| DefKind::Enum
| DefKind::Variant
| DefKind::Ctor(CtorOf::Variant, CtorKind::Fn)
| DefKind::Struct
| DefKind::Ctor(CtorOf::Struct, CtorKind::Fn)
| DefKind::OpaqueTy
| DefKind::TyAlias
| DefKind::TraitAlias
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_hir_pretty/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1139,6 +1139,7 @@ impl<'a> State<'a> {
match &const_arg.kind {
// FIXME(mgca): proper printing for struct exprs
ConstArgKind::Struct(..) => self.word("/* STRUCT EXPR */"),
ConstArgKind::TupleCall(..) => self.word("/* TUPLE CALL */"),
ConstArgKind::Path(qpath) => self.print_qpath(qpath, true),
ConstArgKind::Anon(anon) => self.print_anon_const(anon),
ConstArgKind::Error(_, _) => self.word("/*ERROR*/"),
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_metadata/src/rmeta/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1441,6 +1441,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
// Skip encoding defs for these as they should not have had a `DefId` created
hir::ConstArgKind::Error(..)
| hir::ConstArgKind::Struct(..)
| hir::ConstArgKind::TupleCall(..)
| hir::ConstArgKind::Path(..)
| hir::ConstArgKind::Infer(..) => true,
hir::ConstArgKind::Anon(..) => false,
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_resolve/src/def_collector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -419,7 +419,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> {

// Avoid overwriting `const_arg_context` as we may want to treat const blocks
// as being anon consts if we are inside a const argument.
ExprKind::Struct(_) => return visit::walk_expr(self, expr),
ExprKind::Struct(_) | ExprKind::Call(..) => return visit::walk_expr(self, expr),
// FIXME(mgca): we may want to handle block labels in some manner
ExprKind::Block(block, _) if let [stmt] = block.stmts.as_slice() => match stmt.kind {
// FIXME(mgca): this probably means that mac calls that expand
Expand Down
7 changes: 6 additions & 1 deletion src/librustdoc/clean/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,9 @@ pub(crate) fn clean_const<'tcx>(constant: &hir::ConstArg<'tcx>) -> ConstantKind
// FIXME(mgca): proper printing :3
ConstantKind::Path { path: "/* STRUCT EXPR */".to_string().into() }
}
hir::ConstArgKind::TupleCall(..) => {
ConstantKind::Path { path: "/* TUPLE CALL */".to_string().into() }
}
hir::ConstArgKind::Anon(anon) => ConstantKind::Anonymous { body: anon.body },
hir::ConstArgKind::Infer(..) | hir::ConstArgKind::Error(..) => ConstantKind::Infer,
}
Expand Down Expand Up @@ -1804,7 +1807,9 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T
let ct = cx.tcx.normalize_erasing_regions(typing_env, ct);
print_const(cx, ct)
}
hir::ConstArgKind::Struct(..) | hir::ConstArgKind::Path(..) => {
hir::ConstArgKind::Struct(..)
| hir::ConstArgKind::Path(..)
| hir::ConstArgKind::TupleCall(..) => {
let ct = lower_const_arg_for_rustdoc(cx.tcx, const_arg, FeedConstTy::No);
print_const(cx, ct)
}
Expand Down
1 change: 1 addition & 0 deletions src/tools/clippy/clippy_lints/src/utils/author.rs
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
self.body(field!(anon_const.body));
},
ConstArgKind::Struct(..) => chain!(self, "let ConstArgKind::Struct(..) = {const_arg}.kind"),
ConstArgKind::TupleCall(..) => chain!(self, "let ConstArgKind::TupleCall(..) = {const_arg}.kind"),
ConstArgKind::Infer(..) => chain!(self, "let ConstArgKind::Infer(..) = {const_arg}.kind"),
ConstArgKind::Error(..) => chain!(self, "let ConstArgKind::Error(..) = {const_arg}.kind"),
}
Expand Down
2 changes: 1 addition & 1 deletion src/tools/clippy/clippy_utils/src/consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1140,7 +1140,7 @@ pub fn const_item_rhs_to_expr<'tcx>(tcx: TyCtxt<'tcx>, ct_rhs: ConstItemRhs<'tcx
ConstItemRhs::Body(body_id) => Some(tcx.hir_body(body_id).value),
ConstItemRhs::TypeConst(const_arg) => match const_arg.kind {
ConstArgKind::Anon(anon) => Some(tcx.hir_body(anon.body).value),
ConstArgKind::Struct(..) | ConstArgKind::Path(_) | ConstArgKind::Error(..) | ConstArgKind::Infer(..) => {
ConstArgKind::Struct(..) | ConstArgKind::TupleCall(..) | ConstArgKind::Path(_) | ConstArgKind::Error(..) | ConstArgKind::Infer(..) => {
None
},
},
Expand Down
16 changes: 15 additions & 1 deletion src/tools/clippy/clippy_utils/src/hir_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -671,11 +671,19 @@ impl HirEqInterExpr<'_, '_, '_> {
.iter()
.zip(*inits_b)
.all(|(init_a, init_b)| self.eq_const_arg(init_a.expr, init_b.expr))
},
}
(ConstArgKind::TupleCall(path_a, args_a), ConstArgKind::TupleCall(path_b, args_b)) => {
self.eq_qpath(path_a, path_b)
&& args_a
.iter()
.zip(*args_b)
.all(|(arg_a, arg_b)| self.eq_const_arg(arg_a, arg_b))
}
// Use explicit match for now since ConstArg is undergoing flux.
(
ConstArgKind::Path(..)
| ConstArgKind::Anon(..)
| ConstArgKind::TupleCall(..)
| ConstArgKind::Infer(..)
| ConstArgKind::Struct(..)
| ConstArgKind::Error(..),
Expand Down Expand Up @@ -1546,6 +1554,12 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
self.hash_const_arg(init.expr);
}
},
ConstArgKind::TupleCall(path, args) => {
self.hash_qpath(path);
for arg in *args {
self.hash_const_arg(arg);
}
},
ConstArgKind::Infer(..) | ConstArgKind::Error(..) => {},
}
}
Expand Down
11 changes: 0 additions & 11 deletions tests/crashes/136379.rs

This file was deleted.

10 changes: 0 additions & 10 deletions tests/crashes/138132.rs

This file was deleted.

Loading
Loading