Skip to content

Commit 5d8267f

Browse files
committed
Start lowering multi-segment const paths as ConstArgKind::Path
1 parent 243d2ca commit 5d8267f

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
@@ -123,10 +123,10 @@ impl Path {
123123
!self.segments.is_empty() && self.segments[0].ident.name == kw::PathRoot
124124
}
125125

126-
/// If this path is a single identifier with no arguments, does not ensure
127-
/// that the path resolves to a const param, the caller should check this.
128-
pub fn is_potential_trivial_const_arg(&self) -> bool {
129-
self.segments.len() == 1 && self.segments[0].args.is_none()
126+
/// Does this path have no arguments, and if allow_multi_segment is false, is it a single segment?
127+
pub fn is_potential_trivial_const_arg(&self, allow_multi_segment: bool) -> bool {
128+
(allow_multi_segment || self.segments.len() == 1)
129+
&& self.segments.iter().all(|seg| seg.args.is_none())
130130
}
131131
}
132132

@@ -1175,18 +1175,19 @@ pub struct Expr {
11751175
}
11761176

11771177
impl Expr {
1178+
// FIXME: update docs
11781179
/// Could this expr be either `N`, or `{ N }`, where `N` is a const parameter.
11791180
///
11801181
/// If this is not the case, name resolution does not resolve `N` when using
11811182
/// `min_const_generics` as more complex expressions are not supported.
11821183
///
11831184
/// Does not ensure that the path resolves to a const param, the caller should check this.
11841185
/// This also does not consider macros, so it's only correct after macro-expansion.
1185-
pub fn is_potential_trivial_const_arg(&self) -> bool {
1186+
pub fn is_potential_trivial_const_arg(&self, allow_multi_segment: bool) -> bool {
11861187
let this = self.maybe_unwrap_block();
11871188

11881189
if let ExprKind::Path(None, path) = &this.kind
1189-
&& path.is_potential_trivial_const_arg()
1190+
&& path.is_potential_trivial_const_arg(allow_multi_segment)
11901191
{
11911192
true
11921193
} else {

compiler/rustc_ast_lowering/src/lib.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1100,7 +1100,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
11001100
.and_then(|partial_res| partial_res.full_res())
11011101
{
11021102
if !res.matches_ns(Namespace::TypeNS)
1103-
&& path.is_potential_trivial_const_arg()
1103+
// FIXME: should this only allow single-segment paths?
1104+
&& path.is_potential_trivial_const_arg(self.tcx.features().min_generic_const_args())
11041105
{
11051106
debug!(
11061107
"lower_generic_arg: Lowering type argument as const argument: {:?}",
@@ -2060,8 +2061,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
20602061
) -> &'hir hir::ConstArg<'hir> {
20612062
let tcx = self.tcx;
20622063

2063-
// FIXME(min_generic_const_args): we only allow one-segment const paths for now
2064-
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())
20652066
&& (tcx.features().min_generic_const_args()
20662067
|| matches!(res, Res::Def(DefKind::ConstParam, _)))
20672068
{
@@ -2135,9 +2136,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
21352136
};
21362137
let maybe_res =
21372138
self.resolver.get_partial_res(expr.id).and_then(|partial_res| partial_res.full_res());
2138-
// FIXME(min_generic_const_args): we only allow one-segment const paths for now
21392139
if let ExprKind::Path(None, path) = &expr.kind
2140-
&& path.is_potential_trivial_const_arg()
2140+
&& path.is_potential_trivial_const_arg(tcx.features().min_generic_const_args())
21412141
&& (tcx.features().min_generic_const_args()
21422142
|| matches!(maybe_res, Some(Res::Def(DefKind::ConstParam, _))))
21432143
{

compiler/rustc_builtin_macros/src/format.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,8 @@ fn make_format_args(
189189
&& let [stmt] = block.stmts.as_slice()
190190
&& let StmtKind::Expr(expr) = &stmt.kind
191191
&& let ExprKind::Path(None, path) = &expr.kind
192-
&& path.is_potential_trivial_const_arg()
192+
&& path.segments.len() == 1
193+
&& path.segments[0].args.is_none()
193194
{
194195
err.multipart_suggestion(
195196
"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
@@ -2109,11 +2109,18 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
21092109
let opt_self_ty = maybe_qself.as_ref().map(|qself| self.lower_ty(qself));
21102110
self.lower_const_path_resolved(opt_self_ty, path, hir_id)
21112111
}
2112-
hir::ConstArgKind::Path(qpath) => ty::Const::new_error_with_message(
2113-
tcx,
2114-
qpath.span(),
2115-
format!("Const::lower_const_arg: invalid qpath {qpath:?}"),
2116-
),
2112+
hir::ConstArgKind::Path(hir::QPath::TypeRelative(qself, segment)) => {
2113+
debug!(?qself, ?segment);
2114+
let ty = self.lower_ty(qself);
2115+
self.lower_const_assoc_path(hir_id, const_arg.span(), ty, qself, segment)
2116+
}
2117+
hir::ConstArgKind::Path(qpath @ hir::QPath::LangItem(..)) => {
2118+
ty::Const::new_error_with_message(
2119+
tcx,
2120+
qpath.span(),
2121+
format!("Const::lower_const_arg: invalid qpath {qpath:?}"),
2122+
)
2123+
}
21172124
hir::ConstArgKind::Anon(anon) => self.lower_anon_const(anon),
21182125
hir::ConstArgKind::Infer(span) => self.ct_infer(None, span),
21192126
}
@@ -2202,8 +2209,134 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
22022209
}
22032210
}
22042211

2205-
/// Literals and const generic parameters are eagerly converted to a constant, everything else
2206-
/// becomes `Unevaluated`.
2212+
#[instrument(level = "debug", skip(self))]
2213+
pub fn lower_const_assoc_path(
2214+
&self,
2215+
hir_ref_id: HirId,
2216+
span: Span,
2217+
qself_ty: Ty<'tcx>,
2218+
qself: &'tcx hir::Ty<'tcx>,
2219+
assoc_segment: &'tcx hir::PathSegment<'tcx>,
2220+
) -> Const<'tcx> {
2221+
debug!(%qself_ty, ?assoc_segment.ident);
2222+
let tcx = self.tcx();
2223+
2224+
let assoc_ident = assoc_segment.ident;
2225+
2226+
// Check if we have an enum variant or an inherent associated const.
2227+
// FIXME(min_generic_const_args): handle assoc fns once we support those
2228+
if let Some(adt_def) = self.probe_adt(span, qself_ty) {
2229+
if adt_def.is_enum() {
2230+
let variant_def = adt_def
2231+
.variants()
2232+
.iter()
2233+
.find(|vd| tcx.hygienic_eq(assoc_ident, vd.ident(tcx), adt_def.did()));
2234+
if let Some(variant_def) = variant_def {
2235+
tcx.check_stability(variant_def.def_id, Some(hir_ref_id), span, None);
2236+
let _ = self.prohibit_generic_args(
2237+
slice::from_ref(assoc_segment).iter(),
2238+
GenericsArgsErrExtend::EnumVariant { qself, assoc_segment, adt_def },
2239+
);
2240+
let uv = ty::UnevaluatedConst::new(variant_def.def_id, ty::List::empty());
2241+
return Const::new_unevaluated(tcx, uv);
2242+
}
2243+
}
2244+
2245+
// FIXME(min_generic_const_args): Support self types other than ADTs.
2246+
let candidates = tcx
2247+
.inherent_impls(adt_def.did())
2248+
.iter()
2249+
.filter_map(|&impl_| {
2250+
self.probe_assoc_item(
2251+
assoc_ident,
2252+
ty::AssocKind::Const,
2253+
hir_ref_id,
2254+
span,
2255+
impl_,
2256+
)
2257+
})
2258+
.collect::<Vec<_>>();
2259+
match &candidates[..] {
2260+
[] => {}
2261+
[assoc] => return self.lower_assoc_const(span, assoc.def_id, assoc_segment),
2262+
[..] => {
2263+
return Const::new_error_with_message(tcx, span, "ambiguous assoc const path");
2264+
}
2265+
}
2266+
}
2267+
2268+
let qself_res = if let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = &qself.kind {
2269+
path.res
2270+
} else {
2271+
Res::Err
2272+
};
2273+
2274+
// Find the type of the associated item, and the trait where the associated
2275+
// item is declared.
2276+
let bound_result = match (qself_ty.kind(), qself_res) {
2277+
(_, Res::SelfTyAlias { alias_to: impl_def_id, is_trait_impl: true, .. }) => {
2278+
// `Self` in an impl of a trait -- we have a concrete self type and a
2279+
// trait reference.
2280+
let Some(trait_ref) = tcx.impl_trait_ref(impl_def_id) else {
2281+
// A cycle error occurred, most likely.
2282+
self.dcx().span_bug(span, "expected cycle error");
2283+
};
2284+
2285+
self.probe_single_bound_for_assoc_item(
2286+
|| {
2287+
traits::supertraits(
2288+
tcx,
2289+
ty::Binder::dummy(trait_ref.instantiate_identity()),
2290+
)
2291+
},
2292+
AssocItemQSelf::SelfTyAlias,
2293+
ty::AssocKind::Const,
2294+
assoc_ident,
2295+
span,
2296+
None,
2297+
)
2298+
}
2299+
(
2300+
&ty::Param(_),
2301+
Res::SelfTyParam { trait_: param_did } | Res::Def(DefKind::TyParam, param_did),
2302+
) => self.probe_single_ty_param_bound_for_assoc_item(
2303+
param_did.expect_local(),
2304+
qself.span,
2305+
ty::AssocKind::Const,
2306+
assoc_ident,
2307+
span,
2308+
),
2309+
_ => panic!("handle errors here"), // TODO: do this
2310+
};
2311+
let bound = match bound_result {
2312+
Ok(b) => b,
2313+
Err(reported) => return Const::new_error(tcx, reported),
2314+
};
2315+
2316+
let trait_did = bound.def_id();
2317+
let assoc_const = self
2318+
.probe_assoc_item(assoc_ident, ty::AssocKind::Const, hir_ref_id, span, trait_did)
2319+
.expect("failed to find associated const");
2320+
self.lower_assoc_const(span, assoc_const.def_id, assoc_segment)
2321+
}
2322+
2323+
fn lower_assoc_const(
2324+
&self,
2325+
span: Span,
2326+
item_def_id: DefId,
2327+
item_segment: &hir::PathSegment<'tcx>,
2328+
) -> Const<'tcx> {
2329+
let tcx = self.tcx();
2330+
// FIXME: this is not necessarily correct.
2331+
// adapted from other code that also had a fixme about it being temporary.
2332+
let parent_args = ty::GenericArgs::identity_for_item(tcx, tcx.parent(item_def_id));
2333+
let args =
2334+
self.lower_generic_args_of_assoc_item(span, item_def_id, item_segment, parent_args);
2335+
let uv = ty::UnevaluatedConst::new(item_def_id, args);
2336+
Const::new_unevaluated(tcx, uv)
2337+
}
2338+
2339+
/// Literals are eagerly converted to a constant, everything else becomes `Unevaluated`.
22072340
#[instrument(skip(self), level = "debug")]
22082341
fn lower_anon_const(&self, anon: &AnonConst) -> Const<'tcx> {
22092342
let tcx = self.tcx();

compiler/rustc_resolve/src/late.rs

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1185,7 +1185,7 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r
11851185
if let TyKind::Path(None, ref path) = ty.kind {
11861186
// We cannot disambiguate multi-segment paths right now as that requires type
11871187
// checking.
1188-
if path.is_potential_trivial_const_arg() {
1188+
if path.is_potential_trivial_const_arg(false) {
11891189
let mut check_ns = |ns| {
11901190
self.maybe_resolve_ident_in_lexical_scope(path.segments[0].ident, ns)
11911191
.is_some()
@@ -4599,11 +4599,12 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
45994599
constant, anon_const_kind
46004600
);
46014601

4602-
self.resolve_anon_const_manual(
4603-
constant.value.is_potential_trivial_const_arg(),
4604-
anon_const_kind,
4605-
|this| this.resolve_expr(&constant.value, None),
4606-
)
4602+
let is_trivial_const_arg = constant
4603+
.value
4604+
.is_potential_trivial_const_arg(self.r.tcx.features().min_generic_const_args());
4605+
self.resolve_anon_const_manual(is_trivial_const_arg, anon_const_kind, |this| {
4606+
this.resolve_expr(&constant.value, None)
4607+
})
46074608
}
46084609

46094610
/// There are a few places that we need to resolve an anon const but we did not parse an
@@ -4763,8 +4764,11 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
47634764
// Constant arguments need to be treated as AnonConst since
47644765
// that is how they will be later lowered to HIR.
47654766
if const_args.contains(&idx) {
4767+
let is_trivial_const_arg = argument.is_potential_trivial_const_arg(
4768+
self.r.tcx.features().min_generic_const_args(),
4769+
);
47664770
self.resolve_anon_const_manual(
4767-
argument.is_potential_trivial_const_arg(),
4771+
is_trivial_const_arg,
47684772
AnonConstKind::ConstArg(IsRepeatExpr::No),
47694773
|this| this.resolve_expr(argument, None),
47704774
);

0 commit comments

Comments
 (0)