Skip to content

Commit 425c2bc

Browse files
committed
Start lowering multi-segment const paths as ConstArgKind::Path
1 parent 2010bba commit 425c2bc

File tree

5 files changed

+165
-26
lines changed

5 files changed

+165
-26
lines changed

compiler/rustc_ast/src/ast.rs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -124,10 +124,10 @@ 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+
/// Does this path have no arguments, and if allow_multi_segment is false, is it a single segment?
128+
pub fn is_potential_trivial_const_arg(&self, allow_multi_segment: bool) -> bool {
129+
(allow_multi_segment || self.segments.len() == 1)
130+
&& self.segments.iter().all(|seg| seg.args.is_none())
131131
}
132132
}
133133

@@ -1208,18 +1208,19 @@ pub struct Expr {
12081208
}
12091209

12101210
impl Expr {
1211+
// FIXME: update docs
12111212
/// Could this expr be either `N`, or `{ N }`, where `N` is a const parameter.
12121213
///
12131214
/// If this is not the case, name resolution does not resolve `N` when using
12141215
/// `min_const_generics` as more complex expressions are not supported.
12151216
///
12161217
/// Does not ensure that the path resolves to a const param, the caller should check this.
12171218
/// This also does not consider macros, so it's only correct after macro-expansion.
1218-
pub fn is_potential_trivial_const_arg(&self) -> bool {
1219+
pub fn is_potential_trivial_const_arg(&self, allow_multi_segment: bool) -> bool {
12191220
let this = self.maybe_unwrap_block();
12201221

12211222
if let ExprKind::Path(None, path) = &this.kind
1222-
&& path.is_potential_trivial_const_arg()
1223+
&& path.is_potential_trivial_const_arg(allow_multi_segment)
12231224
{
12241225
true
12251226
} else {

compiler/rustc_ast_lowering/src/lib.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1094,7 +1094,8 @@ 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+
// FIXME: should this only allow single-segment paths?
1098+
&& path.is_potential_trivial_const_arg(self.tcx.features().min_generic_const_args())
10981099
{
10991100
debug!(
11001101
"lower_generic_arg: Lowering type argument as const argument: {:?}",
@@ -2061,8 +2062,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
20612062
) -> &'hir hir::ConstArg<'hir> {
20622063
let tcx = self.tcx;
20632064

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()
2065+
let ct_kind = if path
2066+
.is_potential_trivial_const_arg(tcx.features().min_generic_const_args())
20662067
&& (tcx.features().min_generic_const_args()
20672068
|| matches!(res, Res::Def(DefKind::ConstParam, _)))
20682069
{
@@ -2136,9 +2137,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
21362137
};
21372138
let maybe_res =
21382139
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
21402140
if let ExprKind::Path(None, path) = &expr.kind
2141-
&& path.is_potential_trivial_const_arg()
2141+
&& path.is_potential_trivial_const_arg(tcx.features().min_generic_const_args())
21422142
&& (tcx.features().min_generic_const_args()
21432143
|| matches!(maybe_res, Some(Res::Def(DefKind::ConstParam, _))))
21442144
{

compiler/rustc_builtin_macros/src/format.rs

Lines changed: 2 additions & 1 deletion
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_hir_analysis/src/hir_ty_lowering/mod.rs

Lines changed: 140 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2167,11 +2167,18 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
21672167
let opt_self_ty = maybe_qself.as_ref().map(|qself| self.lower_ty(qself));
21682168
self.lower_const_path_resolved(opt_self_ty, path, hir_id)
21692169
}
2170-
hir::ConstArgKind::Path(qpath) => ty::Const::new_error_with_message(
2171-
tcx,
2172-
qpath.span(),
2173-
format!("Const::lower_const_arg: invalid qpath {qpath:?}"),
2174-
),
2170+
hir::ConstArgKind::Path(hir::QPath::TypeRelative(qself, segment)) => {
2171+
debug!(?qself, ?segment);
2172+
let ty = self.lower_ty(qself);
2173+
self.lower_const_assoc_path(hir_id, const_arg.span(), ty, qself, segment)
2174+
}
2175+
hir::ConstArgKind::Path(qpath @ hir::QPath::LangItem(..)) => {
2176+
ty::Const::new_error_with_message(
2177+
tcx,
2178+
qpath.span(),
2179+
format!("Const::lower_const_arg: invalid qpath {qpath:?}"),
2180+
)
2181+
}
21752182
hir::ConstArgKind::Anon(anon) => self.lower_anon_const(anon),
21762183
hir::ConstArgKind::Infer(span, ()) => self.ct_infer(None, span),
21772184
}
@@ -2264,8 +2271,134 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
22642271
}
22652272
}
22662273

2267-
/// Literals and const generic parameters are eagerly converted to a constant, everything else
2268-
/// becomes `Unevaluated`.
2274+
#[instrument(level = "debug", skip(self))]
2275+
pub fn lower_const_assoc_path(
2276+
&self,
2277+
hir_ref_id: HirId,
2278+
span: Span,
2279+
qself_ty: Ty<'tcx>,
2280+
qself: &'tcx hir::Ty<'tcx>,
2281+
assoc_segment: &'tcx hir::PathSegment<'tcx>,
2282+
) -> Const<'tcx> {
2283+
debug!(%qself_ty, ?assoc_segment.ident);
2284+
let tcx = self.tcx();
2285+
2286+
let assoc_ident = assoc_segment.ident;
2287+
2288+
// Check if we have an enum variant or an inherent associated const.
2289+
// FIXME(min_generic_const_args): handle assoc fns once we support those
2290+
if let Some(adt_def) = self.probe_adt(span, qself_ty) {
2291+
if adt_def.is_enum() {
2292+
let variant_def = adt_def
2293+
.variants()
2294+
.iter()
2295+
.find(|vd| tcx.hygienic_eq(assoc_ident, vd.ident(tcx), adt_def.did()));
2296+
if let Some(variant_def) = variant_def {
2297+
tcx.check_stability(variant_def.def_id, Some(hir_ref_id), span, None);
2298+
let _ = self.prohibit_generic_args(
2299+
slice::from_ref(assoc_segment).iter(),
2300+
GenericsArgsErrExtend::EnumVariant { qself, assoc_segment, adt_def },
2301+
);
2302+
let uv = ty::UnevaluatedConst::new(variant_def.def_id, ty::List::empty());
2303+
return Const::new_unevaluated(tcx, uv);
2304+
}
2305+
}
2306+
2307+
// FIXME(min_generic_const_args): Support self types other than ADTs.
2308+
let candidates = tcx
2309+
.inherent_impls(adt_def.did())
2310+
.iter()
2311+
.filter_map(|&impl_| {
2312+
self.probe_assoc_item(
2313+
assoc_ident,
2314+
ty::AssocKind::Const,
2315+
hir_ref_id,
2316+
span,
2317+
impl_,
2318+
)
2319+
})
2320+
.collect::<Vec<_>>();
2321+
match &candidates[..] {
2322+
[] => {}
2323+
[assoc] => return self.lower_assoc_const(span, assoc.def_id, assoc_segment),
2324+
[..] => {
2325+
return Const::new_error_with_message(tcx, span, "ambiguous assoc const path");
2326+
}
2327+
}
2328+
}
2329+
2330+
let qself_res = if let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = &qself.kind {
2331+
path.res
2332+
} else {
2333+
Res::Err
2334+
};
2335+
2336+
// Find the type of the associated item, and the trait where the associated
2337+
// item is declared.
2338+
let bound_result = match (qself_ty.kind(), qself_res) {
2339+
(_, Res::SelfTyAlias { alias_to: impl_def_id, is_trait_impl: true, .. }) => {
2340+
// `Self` in an impl of a trait -- we have a concrete self type and a
2341+
// trait reference.
2342+
let Some(trait_ref) = tcx.impl_trait_ref(impl_def_id) else {
2343+
// A cycle error occurred, most likely.
2344+
self.dcx().span_bug(span, "expected cycle error");
2345+
};
2346+
2347+
self.probe_single_bound_for_assoc_item(
2348+
|| {
2349+
traits::supertraits(
2350+
tcx,
2351+
ty::Binder::dummy(trait_ref.instantiate_identity()),
2352+
)
2353+
},
2354+
AssocItemQSelf::SelfTyAlias,
2355+
ty::AssocKind::Const,
2356+
assoc_ident,
2357+
span,
2358+
None,
2359+
)
2360+
}
2361+
(
2362+
&ty::Param(_),
2363+
Res::SelfTyParam { trait_: param_did } | Res::Def(DefKind::TyParam, param_did),
2364+
) => self.probe_single_ty_param_bound_for_assoc_item(
2365+
param_did.expect_local(),
2366+
qself.span,
2367+
ty::AssocKind::Const,
2368+
assoc_ident,
2369+
span,
2370+
),
2371+
_ => panic!("handle errors here"), // TODO: do this
2372+
};
2373+
let bound = match bound_result {
2374+
Ok(b) => b,
2375+
Err(reported) => return Const::new_error(tcx, reported),
2376+
};
2377+
2378+
let trait_did = bound.def_id();
2379+
let assoc_const = self
2380+
.probe_assoc_item(assoc_ident, ty::AssocKind::Const, hir_ref_id, span, trait_did)
2381+
.expect("failed to find associated const");
2382+
self.lower_assoc_const(span, assoc_const.def_id, assoc_segment)
2383+
}
2384+
2385+
fn lower_assoc_const(
2386+
&self,
2387+
span: Span,
2388+
item_def_id: DefId,
2389+
item_segment: &hir::PathSegment<'tcx>,
2390+
) -> Const<'tcx> {
2391+
let tcx = self.tcx();
2392+
// FIXME: this is not necessarily correct.
2393+
// adapted from other code that also had a fixme about it being temporary.
2394+
let parent_args = ty::GenericArgs::identity_for_item(tcx, tcx.parent(item_def_id));
2395+
let args =
2396+
self.lower_generic_args_of_assoc_item(span, item_def_id, item_segment, parent_args);
2397+
let uv = ty::UnevaluatedConst::new(item_def_id, args);
2398+
Const::new_unevaluated(tcx, uv)
2399+
}
2400+
2401+
/// Literals are eagerly converted to a constant, everything else becomes `Unevaluated`.
22692402
#[instrument(skip(self), level = "debug")]
22702403
fn lower_anon_const(&self, anon: &AnonConst) -> Const<'tcx> {
22712404
let tcx = self.tcx();

compiler/rustc_resolve/src/late.rs

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1202,7 +1202,7 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r
12021202
if let TyKind::Path(None, ref path) = ty.kind
12031203
// We cannot disambiguate multi-segment paths right now as that requires type
12041204
// checking.
1205-
&& path.is_potential_trivial_const_arg()
1205+
&& path.is_potential_trivial_const_arg(false)
12061206
{
12071207
let mut check_ns = |ns| {
12081208
self.maybe_resolve_ident_in_lexical_scope(path.segments[0].ident, ns)
@@ -4630,11 +4630,12 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
46304630
constant, anon_const_kind
46314631
);
46324632

4633-
self.resolve_anon_const_manual(
4634-
constant.value.is_potential_trivial_const_arg(),
4635-
anon_const_kind,
4636-
|this| this.resolve_expr(&constant.value, None),
4637-
)
4633+
let is_trivial_const_arg = constant
4634+
.value
4635+
.is_potential_trivial_const_arg(self.r.tcx.features().min_generic_const_args());
4636+
self.resolve_anon_const_manual(is_trivial_const_arg, anon_const_kind, |this| {
4637+
this.resolve_expr(&constant.value, None)
4638+
})
46384639
}
46394640

46404641
/// There are a few places that we need to resolve an anon const but we did not parse an
@@ -4794,8 +4795,11 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
47944795
// Constant arguments need to be treated as AnonConst since
47954796
// that is how they will be later lowered to HIR.
47964797
if const_args.contains(&idx) {
4798+
let is_trivial_const_arg = argument.is_potential_trivial_const_arg(
4799+
self.r.tcx.features().min_generic_const_args(),
4800+
);
47974801
self.resolve_anon_const_manual(
4798-
argument.is_potential_trivial_const_arg(),
4802+
is_trivial_const_arg,
47994803
AnonConstKind::ConstArg(IsRepeatExpr::No),
48004804
|this| this.resolve_expr(argument, None),
48014805
);

0 commit comments

Comments
 (0)