Skip to content

Commit 08db600

Browse files
committed
Auto merge of rust-lang#135186 - camelid:const-path-multi, r=BoxyUwU
mgca: Lower all const paths as `ConstArgKind::Path` When `#![feature(min_generic_const_args)]` is enabled, we now lower all const paths in generic arg position to `hir::ConstArgKind::Path`. We then lower assoc const paths to `ty::ConstKind::Unevaluated` since we can no longer use the anon const expression lowering machinery. In the process of implementing this, I factored out `hir_ty_lowering` code that is now shared between lowering assoc types and assoc consts. This PR also introduces a `#[type_const]` attribute for trait assoc consts that are allowed as const args. However, we still need to implement code to check that assoc const definitions satisfy `#[type_const]` if present (basically is it a const path or a monomorphic anon const). r? `@BoxyUwU`
2 parents f9e0239 + 177e7ff commit 08db600

35 files changed

+602
-148
lines changed

compiler/rustc_ast/src/ast.rs

+33-15
Original file line numberDiff line numberDiff line change
@@ -124,10 +124,19 @@ impl Path {
124124
self.segments.first().is_some_and(|segment| segment.ident.name == kw::PathRoot)
125125
}
126126

127-
/// If this path is a single identifier with no arguments, does not ensure
128-
/// that the path resolves to a const param, the caller should check this.
129-
pub fn is_potential_trivial_const_arg(&self) -> bool {
130-
matches!(self.segments[..], [PathSegment { args: None, .. }])
127+
/// Check if this path is potentially a trivial const arg, i.e., one that can _potentially_
128+
/// be represented without an anon const in the HIR.
129+
///
130+
/// If `allow_mgca_arg` is true (as should be the case in most situations when
131+
/// `#![feature(min_generic_const_args)]` is enabled), then this always returns true
132+
/// because all paths are valid.
133+
///
134+
/// Otherwise, it returns true iff the path has exactly one segment, and it has no generic args
135+
/// (i.e., it is _potentially_ a const parameter).
136+
#[tracing::instrument(level = "debug", ret)]
137+
pub fn is_potential_trivial_const_arg(&self, allow_mgca_arg: bool) -> bool {
138+
allow_mgca_arg
139+
|| self.segments.len() == 1 && self.segments.iter().all(|seg| seg.args.is_none())
131140
}
132141
}
133142

@@ -1208,22 +1217,31 @@ pub struct Expr {
12081217
}
12091218

12101219
impl Expr {
1211-
/// Could this expr be either `N`, or `{ N }`, where `N` is a const parameter.
1220+
/// Check if this expression is potentially a trivial const arg, i.e., one that can _potentially_
1221+
/// be represented without an anon const in the HIR.
1222+
///
1223+
/// This will unwrap at most one block level (curly braces). After that, if the expression
1224+
/// is a path, it mostly dispatches to [`Path::is_potential_trivial_const_arg`].
1225+
/// See there for more info about `allow_mgca_arg`.
12121226
///
1213-
/// If this is not the case, name resolution does not resolve `N` when using
1214-
/// `min_const_generics` as more complex expressions are not supported.
1227+
/// The only additional thing to note is that when `allow_mgca_arg` is false, this function
1228+
/// will only allow paths with no qself, before dispatching to the `Path` function of
1229+
/// the same name.
12151230
///
1216-
/// Does not ensure that the path resolves to a const param, the caller should check this.
1231+
/// Does not ensure that the path resolves to a const param/item, the caller should check this.
12171232
/// This also does not consider macros, so it's only correct after macro-expansion.
1218-
pub fn is_potential_trivial_const_arg(&self) -> bool {
1233+
pub fn is_potential_trivial_const_arg(&self, allow_mgca_arg: bool) -> bool {
12191234
let this = self.maybe_unwrap_block();
1220-
1221-
if let ExprKind::Path(None, path) = &this.kind
1222-
&& path.is_potential_trivial_const_arg()
1223-
{
1224-
true
1235+
if allow_mgca_arg {
1236+
matches!(this.kind, ExprKind::Path(..))
12251237
} else {
1226-
false
1238+
if let ExprKind::Path(None, path) = &this.kind
1239+
&& path.is_potential_trivial_const_arg(allow_mgca_arg)
1240+
{
1241+
true
1242+
} else {
1243+
false
1244+
}
12271245
}
12281246
}
12291247

compiler/rustc_ast_lowering/src/lib.rs

+8-9
Original file line numberDiff line numberDiff line change
@@ -1094,7 +1094,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
10941094
.and_then(|partial_res| partial_res.full_res())
10951095
{
10961096
if !res.matches_ns(Namespace::TypeNS)
1097-
&& path.is_potential_trivial_const_arg()
1097+
&& path.is_potential_trivial_const_arg(false)
10981098
{
10991099
debug!(
11001100
"lower_generic_arg: Lowering type argument as const argument: {:?}",
@@ -2061,8 +2061,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
20612061
) -> &'hir hir::ConstArg<'hir> {
20622062
let tcx = self.tcx;
20632063

2064-
// FIXME(min_generic_const_args): we only allow one-segment const paths for now
2065-
let ct_kind = if path.is_potential_trivial_const_arg()
2064+
let ct_kind = if path
2065+
.is_potential_trivial_const_arg(tcx.features().min_generic_const_args())
20662066
&& (tcx.features().min_generic_const_args()
20672067
|| matches!(res, Res::Def(DefKind::ConstParam, _)))
20682068
{
@@ -2072,7 +2072,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
20722072
path,
20732073
ParamMode::Optional,
20742074
AllowReturnTypeNotation::No,
2075-
// FIXME(min_generic_const_args): update for `fn foo() -> Bar<FOO<impl Trait>>` support
2075+
// FIXME(mgca): update for `fn foo() -> Bar<FOO<impl Trait>>` support
20762076
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
20772077
None,
20782078
);
@@ -2136,19 +2136,18 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
21362136
};
21372137
let maybe_res =
21382138
self.resolver.get_partial_res(expr.id).and_then(|partial_res| partial_res.full_res());
2139-
// FIXME(min_generic_const_args): we only allow one-segment const paths for now
2140-
if let ExprKind::Path(None, path) = &expr.kind
2141-
&& path.is_potential_trivial_const_arg()
2139+
if let ExprKind::Path(qself, path) = &expr.kind
2140+
&& path.is_potential_trivial_const_arg(tcx.features().min_generic_const_args())
21422141
&& (tcx.features().min_generic_const_args()
21432142
|| matches!(maybe_res, Some(Res::Def(DefKind::ConstParam, _))))
21442143
{
21452144
let qpath = self.lower_qpath(
21462145
expr.id,
2147-
&None,
2146+
qself,
21482147
path,
21492148
ParamMode::Optional,
21502149
AllowReturnTypeNotation::No,
2151-
// FIXME(min_generic_const_args): update for `fn foo() -> Bar<FOO<impl Trait>>` support
2150+
// FIXME(mgca): update for `fn foo() -> Bar<FOO<impl Trait>>` support
21522151
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
21532152
None,
21542153
);

compiler/rustc_builtin_macros/src/format.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,8 @@ fn make_format_args(
190190
&& let [stmt] = block.stmts.as_slice()
191191
&& let StmtKind::Expr(expr) = &stmt.kind
192192
&& let ExprKind::Path(None, path) = &expr.kind
193-
&& path.is_potential_trivial_const_arg()
193+
&& path.segments.len() == 1
194+
&& path.segments[0].args.is_none()
194195
{
195196
err.multipart_suggestion(
196197
"quote your inlined format argument to use as string literal",

compiler/rustc_feature/src/builtin_attrs.rs

+7
Original file line numberDiff line numberDiff line change
@@ -576,6 +576,13 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
576576
EncodeCrossCrate::Yes, experimental!(patchable_function_entry)
577577
),
578578

579+
// Probably temporary component of min_generic_const_args.
580+
// `#[type_const] const ASSOC: usize;`
581+
gated!(
582+
type_const, Normal, template!(Word), ErrorFollowing,
583+
EncodeCrossCrate::Yes, min_generic_const_args, experimental!(type_const),
584+
),
585+
579586
// ==========================================================================
580587
// Internal attributes: Stability, deprecation, and unsafe:
581588
// ==========================================================================

compiler/rustc_hir_analysis/src/collect.rs

+14-14
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ use tracing::{debug, instrument};
4545

4646
use crate::check::intrinsic::intrinsic_operation_unsafety;
4747
use crate::errors;
48+
use crate::hir_ty_lowering::errors::assoc_kind_str;
4849
use crate::hir_ty_lowering::{FeedConstTy, HirTyLowerer, RegionInferReason};
4950

5051
pub(crate) mod dump;
@@ -443,21 +444,22 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
443444
self.tcx.at(span).type_param_predicates((self.item_def_id, def_id, assoc_name))
444445
}
445446

446-
fn lower_assoc_ty(
447+
fn lower_assoc_shared(
447448
&self,
448449
span: Span,
449450
item_def_id: DefId,
450-
item_segment: &hir::PathSegment<'tcx>,
451+
item_segment: &rustc_hir::PathSegment<'tcx>,
451452
poly_trait_ref: ty::PolyTraitRef<'tcx>,
452-
) -> Ty<'tcx> {
453+
kind: ty::AssocKind,
454+
) -> Result<(DefId, ty::GenericArgsRef<'tcx>), ErrorGuaranteed> {
453455
if let Some(trait_ref) = poly_trait_ref.no_bound_vars() {
454456
let item_args = self.lowerer().lower_generic_args_of_assoc_item(
455457
span,
456458
item_def_id,
457459
item_segment,
458460
trait_ref.args,
459461
);
460-
Ty::new_projection_from_args(self.tcx(), item_def_id, item_args)
462+
Ok((item_def_id, item_args))
461463
} else {
462464
// There are no late-bound regions; we can just ignore the binder.
463465
let (mut mpart_sugg, mut inferred_sugg) = (None, None);
@@ -518,16 +520,14 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
518520
}
519521
_ => {}
520522
}
521-
Ty::new_error(
522-
self.tcx(),
523-
self.tcx().dcx().emit_err(errors::AssociatedItemTraitUninferredGenericParams {
524-
span,
525-
inferred_sugg,
526-
bound,
527-
mpart_sugg,
528-
what: "type",
529-
}),
530-
)
523+
524+
Err(self.tcx().dcx().emit_err(errors::AssociatedItemTraitUninferredGenericParams {
525+
span,
526+
inferred_sugg,
527+
bound,
528+
mpart_sugg,
529+
what: assoc_kind_str(kind),
530+
}))
531531
}
532532
}
533533

compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -468,11 +468,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
468468

469469
// Good error for `where Trait::method(..): Send`.
470470
let Some(self_ty) = opt_self_ty else {
471-
return self.error_missing_qpath_self_ty(
471+
let guar = self.error_missing_qpath_self_ty(
472472
trait_def_id,
473473
hir_ty.span,
474474
item_segment,
475+
ty::AssocKind::Type,
475476
);
477+
return Ty::new_error(tcx, guar);
476478
};
477479
let self_ty = self.lower_ty(self_ty);
478480

compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs

+22-14
Original file line numberDiff line numberDiff line change
@@ -385,14 +385,17 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
385385
})
386386
}
387387

388-
pub(super) fn report_ambiguous_assoc_ty(
388+
pub(super) fn report_ambiguous_assoc(
389389
&self,
390390
span: Span,
391391
types: &[String],
392392
traits: &[String],
393393
name: Symbol,
394+
kind: ty::AssocKind,
394395
) -> ErrorGuaranteed {
395-
let mut err = struct_span_code_err!(self.dcx(), span, E0223, "ambiguous associated type");
396+
let kind_str = assoc_kind_str(kind);
397+
let mut err =
398+
struct_span_code_err!(self.dcx(), span, E0223, "ambiguous associated {kind_str}");
396399
if self
397400
.tcx()
398401
.resolutions(())
@@ -417,7 +420,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
417420
span,
418421
format!(
419422
"if there were a type named `Type` that implements a trait named \
420-
`Trait` with associated type `{name}`, you could use the \
423+
`Trait` with associated {kind_str} `{name}`, you could use the \
421424
fully-qualified path",
422425
),
423426
format!("<Type as Trait>::{name}"),
@@ -440,7 +443,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
440443
span,
441444
format!(
442445
"if there were a type named `Example` that implemented one of the \
443-
traits with associated type `{name}`, you could use the \
446+
traits with associated {kind_str} `{name}`, you could use the \
444447
fully-qualified path",
445448
),
446449
traits.iter().map(|trait_str| format!("<Example as {trait_str}>::{name}")),
@@ -451,7 +454,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
451454
err.span_suggestion_verbose(
452455
span,
453456
format!(
454-
"if there were a trait named `Example` with associated type `{name}` \
457+
"if there were a trait named `Example` with associated {kind_str} `{name}` \
455458
implemented for `{type_str}`, you could use the fully-qualified path",
456459
),
457460
format!("<{type_str} as Example>::{name}"),
@@ -462,7 +465,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
462465
err.span_suggestions(
463466
span,
464467
format!(
465-
"if there were a trait named `Example` with associated type `{name}` \
468+
"if there were a trait named `Example` with associated {kind_str} `{name}` \
466469
implemented for one of the types, you could use the fully-qualified \
467470
path",
468471
),
@@ -491,7 +494,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
491494
err.emit()
492495
}
493496

494-
pub(crate) fn complain_about_ambiguous_inherent_assoc_ty(
497+
pub(crate) fn complain_about_ambiguous_inherent_assoc(
495498
&self,
496499
name: Ident,
497500
candidates: Vec<DefId>,
@@ -552,13 +555,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
552555
}
553556

554557
// FIXME(inherent_associated_types): Find similarly named associated types and suggest them.
555-
pub(crate) fn complain_about_inherent_assoc_ty_not_found(
558+
pub(crate) fn complain_about_inherent_assoc_not_found(
556559
&self,
557560
name: Ident,
558561
self_ty: Ty<'tcx>,
559562
candidates: Vec<(DefId, (DefId, DefId))>,
560563
fulfillment_errors: Vec<FulfillmentError<'tcx>>,
561564
span: Span,
565+
kind: ty::AssocKind,
562566
) -> ErrorGuaranteed {
563567
// FIXME(fmease): This was copied in parts from an old version of `rustc_hir_typeck::method::suggest`.
564568
// Either
@@ -568,12 +572,16 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
568572

569573
let tcx = self.tcx();
570574

575+
let kind_str = assoc_kind_str(kind);
571576
let adt_did = self_ty.ty_adt_def().map(|def| def.did());
572577
let add_def_label = |err: &mut Diag<'_>| {
573578
if let Some(did) = adt_did {
574579
err.span_label(
575580
tcx.def_span(did),
576-
format!("associated item `{name}` not found for this {}", tcx.def_descr(did)),
581+
format!(
582+
"associated {kind_str} `{name}` not found for this {}",
583+
tcx.def_descr(did)
584+
),
577585
);
578586
}
579587
};
@@ -600,11 +608,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
600608
self.dcx(),
601609
name.span,
602610
E0220,
603-
"associated type `{name}` not found for `{self_ty}` in the current scope"
611+
"associated {kind_str} `{name}` not found for `{self_ty}` in the current scope"
604612
);
605613
err.span_label(name.span, format!("associated item not found in `{self_ty}`"));
606614
err.note(format!(
607-
"the associated type was found for\n{type_candidates}{additional_types}",
615+
"the associated {kind_str} was found for\n{type_candidates}{additional_types}",
608616
));
609617
add_def_label(&mut err);
610618
return err.emit();
@@ -685,7 +693,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
685693

686694
let mut err = self.dcx().struct_span_err(
687695
name.span,
688-
format!("the associated type `{name}` exists for `{self_ty}`, but its trait bounds were not satisfied")
696+
format!("the associated {kind_str} `{name}` exists for `{self_ty}`, but its trait bounds were not satisfied")
689697
);
690698
if !bounds.is_empty() {
691699
err.note(format!(
@@ -695,7 +703,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
695703
}
696704
err.span_label(
697705
name.span,
698-
format!("associated type cannot be referenced on `{self_ty}` due to unsatisfied trait bounds")
706+
format!("associated {kind_str} cannot be referenced on `{self_ty}` due to unsatisfied trait bounds")
699707
);
700708

701709
for (span, mut bounds) in bound_spans {
@@ -1614,7 +1622,7 @@ fn generics_args_err_extend<'a>(
16141622
}
16151623
}
16161624

1617-
pub(super) fn assoc_kind_str(kind: ty::AssocKind) -> &'static str {
1625+
pub(crate) fn assoc_kind_str(kind: ty::AssocKind) -> &'static str {
16181626
match kind {
16191627
ty::AssocKind::Fn => "function",
16201628
ty::AssocKind::Const => "constant",

compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ fn generic_arg_mismatch_err(
115115
body.value.kind
116116
&& let Res::Def(DefKind::Fn { .. }, id) = path.res
117117
{
118-
// FIXME(min_generic_const_args): this branch is dead once new const path lowering
118+
// FIXME(mgca): this branch is dead once new const path lowering
119119
// (for single-segment paths) is no longer gated
120120
err.help(format!("`{}` is a function item, not a type", tcx.item_name(id)));
121121
err.help("function item types cannot be named directly");

0 commit comments

Comments
 (0)