Skip to content

Commit 50bd398

Browse files
committed
Factor out shared code for lowering assoc item paths
1 parent fcfe5bd commit 50bd398

File tree

2 files changed

+151
-133
lines changed
  • compiler
    • rustc_hir_analysis/src/hir_ty_lowering
    • rustc_hir_typeck/src/fn_ctxt

2 files changed

+151
-133
lines changed

compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs

+150-132
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ use rustc_trait_selection::traits::wf::object_region_bounds;
5151
use rustc_trait_selection::traits::{self, ObligationCtxt};
5252
use tracing::{debug, instrument};
5353

54+
use self::errors::assoc_kind_str;
5455
use crate::bounds::Bounds;
5556
use crate::check::check_abi_fn_ptr;
5657
use crate::errors::{AmbiguousLifetimeBound, BadReturnTypeNotation, InvalidBaseType, WildPatTy};
@@ -261,6 +262,42 @@ pub enum FeedConstTy {
261262
No,
262263
}
263264

265+
#[derive(Debug, Clone, Copy)]
266+
enum LowerAssocMode {
267+
Type { permit_variants: bool },
268+
Const,
269+
}
270+
271+
impl LowerAssocMode {
272+
fn kind(self) -> ty::AssocKind {
273+
match self {
274+
LowerAssocMode::Type { .. } => ty::AssocKind::Type,
275+
LowerAssocMode::Const => ty::AssocKind::Const,
276+
}
277+
}
278+
279+
fn def_kind(self) -> DefKind {
280+
match self {
281+
LowerAssocMode::Type { .. } => DefKind::AssocTy,
282+
LowerAssocMode::Const => DefKind::AssocConst,
283+
}
284+
}
285+
286+
fn permit_variants(self) -> bool {
287+
match self {
288+
LowerAssocMode::Type { permit_variants } => permit_variants,
289+
LowerAssocMode::Const => true,
290+
}
291+
}
292+
}
293+
294+
#[derive(Debug, Clone, Copy)]
295+
enum LoweredAssoc<'tcx> {
296+
Type(Ty<'tcx>, DefId),
297+
Variant { adt: Ty<'tcx>, variant_did: DefId },
298+
Const(Const<'tcx>),
299+
}
300+
264301
/// New-typed boolean indicating whether explicit late-bound lifetimes
265302
/// are present in a set of generic arguments.
266303
///
@@ -1112,7 +1149,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
11121149
// NOTE: When this function starts resolving `Trait::AssocTy` successfully
11131150
// it should also start reporting the `BARE_TRAIT_OBJECTS` lint.
11141151
#[instrument(level = "debug", skip_all, ret)]
1115-
pub fn lower_assoc_path(
1152+
pub fn lower_assoc_path_ty(
11161153
&self,
11171154
hir_ref_id: HirId,
11181155
span: Span,
@@ -1121,6 +1158,56 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
11211158
assoc_segment: &'tcx hir::PathSegment<'tcx>,
11221159
permit_variants: bool,
11231160
) -> Result<(Ty<'tcx>, DefKind, DefId), ErrorGuaranteed> {
1161+
match self.lower_assoc_path_shared(
1162+
hir_ref_id,
1163+
span,
1164+
qself_ty,
1165+
qself,
1166+
assoc_segment,
1167+
LowerAssocMode::Type { permit_variants },
1168+
)? {
1169+
LoweredAssoc::Type(ty, def_id) => Ok((ty, DefKind::AssocTy, def_id)),
1170+
LoweredAssoc::Variant { adt, variant_did } => Ok((adt, DefKind::Variant, variant_did)),
1171+
LoweredAssoc::Const(_) => unreachable!("lowered assoc type to const somehow"),
1172+
}
1173+
}
1174+
1175+
#[instrument(level = "debug", skip_all, ret)]
1176+
fn lower_assoc_path_const(
1177+
&self,
1178+
hir_ref_id: HirId,
1179+
span: Span,
1180+
qself_ty: Ty<'tcx>,
1181+
qself: &'tcx hir::Ty<'tcx>,
1182+
assoc_segment: &'tcx hir::PathSegment<'tcx>,
1183+
) -> Result<Const<'tcx>, ErrorGuaranteed> {
1184+
match self.lower_assoc_path_shared(
1185+
hir_ref_id,
1186+
span,
1187+
qself_ty,
1188+
qself,
1189+
assoc_segment,
1190+
LowerAssocMode::Const,
1191+
)? {
1192+
LoweredAssoc::Type(..) => unreachable!("lowered assoc const to type somehow"),
1193+
LoweredAssoc::Variant { adt: _, variant_did } => {
1194+
let uv = ty::UnevaluatedConst::new(variant_did, ty::List::empty());
1195+
Ok(Const::new_unevaluated(self.tcx(), uv))
1196+
}
1197+
LoweredAssoc::Const(ct) => Ok(ct),
1198+
}
1199+
}
1200+
1201+
#[instrument(level = "debug", skip_all, ret)]
1202+
fn lower_assoc_path_shared(
1203+
&self,
1204+
hir_ref_id: HirId,
1205+
span: Span,
1206+
qself_ty: Ty<'tcx>,
1207+
qself: &'tcx hir::Ty<'tcx>,
1208+
assoc_segment: &'tcx hir::PathSegment<'tcx>,
1209+
mode: LowerAssocMode,
1210+
) -> Result<LoweredAssoc<'tcx>, ErrorGuaranteed> {
11241211
debug!(%qself_ty, ?assoc_segment.ident);
11251212
let tcx = self.tcx();
11261213

@@ -1135,28 +1222,47 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
11351222
.iter()
11361223
.find(|vd| tcx.hygienic_eq(assoc_ident, vd.ident(tcx), adt_def.did()));
11371224
if let Some(variant_def) = variant_def {
1138-
if permit_variants {
1225+
if mode.permit_variants() {
11391226
tcx.check_stability(variant_def.def_id, Some(hir_ref_id), span, None);
11401227
let _ = self.prohibit_generic_args(
11411228
slice::from_ref(assoc_segment).iter(),
11421229
GenericsArgsErrExtend::EnumVariant { qself, assoc_segment, adt_def },
11431230
);
1144-
return Ok((qself_ty, DefKind::Variant, variant_def.def_id));
1231+
return Ok(LoweredAssoc::Variant {
1232+
adt: qself_ty,
1233+
variant_did: variant_def.def_id,
1234+
});
11451235
} else {
11461236
variant_resolution = Some(variant_def.def_id);
11471237
}
11481238
}
11491239
}
11501240

1151-
// FIXME(inherent_associated_types, #106719): Support self types other than ADTs.
1152-
if let Some((ty, did)) = self.probe_inherent_assoc_ty(
1153-
assoc_segment,
1154-
adt_def.did(),
1155-
qself_ty,
1156-
hir_ref_id,
1157-
span,
1158-
)? {
1159-
return Ok((ty, DefKind::AssocTy, did));
1241+
match mode {
1242+
LowerAssocMode::Type { .. } => {
1243+
// FIXME(inherent_associated_types, #106719): Support self types other than ADTs.
1244+
if let Some((ty, did)) = self.probe_inherent_assoc_ty(
1245+
assoc_segment,
1246+
adt_def.did(),
1247+
qself_ty,
1248+
hir_ref_id,
1249+
span,
1250+
)? {
1251+
return Ok(LoweredAssoc::Type(ty, did));
1252+
}
1253+
}
1254+
LowerAssocMode::Const => {
1255+
// FIXME(mgca): Support self types other than ADTs.
1256+
if let Some((ct, _)) = self.probe_inherent_assoc_const(
1257+
assoc_segment,
1258+
adt_def.did(),
1259+
qself_ty,
1260+
hir_ref_id,
1261+
span,
1262+
)? {
1263+
return Ok(LoweredAssoc::Const(ct));
1264+
}
1265+
}
11601266
}
11611267
}
11621268

@@ -1185,7 +1291,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
11851291
)
11861292
},
11871293
AssocItemQSelf::SelfTyAlias,
1188-
ty::AssocKind::Type,
1294+
mode.kind(),
11891295
assoc_ident,
11901296
span,
11911297
None,
@@ -1197,14 +1303,15 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
11971303
) => self.probe_single_ty_param_bound_for_assoc_item(
11981304
param_did.expect_local(),
11991305
qself.span,
1200-
ty::AssocKind::Type,
1306+
mode.kind(),
12011307
assoc_ident,
12021308
span,
12031309
)?,
12041310
_ => {
1311+
let kind_str = assoc_kind_str(mode.kind());
12051312
let reported = if variant_resolution.is_some() {
12061313
// Variant in type position
1207-
let msg = format!("expected type, found variant `{assoc_ident}`");
1314+
let msg = format!("expected {kind_str}, found variant `{assoc_ident}`");
12081315
self.dcx().span_err(span, msg)
12091316
} else if qself_ty.is_enum() {
12101317
let mut err = struct_span_code_err!(
@@ -1312,18 +1419,37 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
13121419
&[qself_ty.to_string()],
13131420
&traits,
13141421
assoc_ident.name,
1315-
ty::AssocKind::Type,
1422+
mode.kind(),
13161423
)
13171424
};
13181425
return Err(reported);
13191426
}
13201427
};
13211428

13221429
let trait_did = bound.def_id();
1323-
let assoc_ty = self
1324-
.probe_assoc_item(assoc_ident, ty::AssocKind::Type, hir_ref_id, span, trait_did)
1325-
.expect("failed to find associated type");
1326-
let ty = self.lower_assoc_ty(span, assoc_ty.def_id, assoc_segment, bound);
1430+
let assoc_item = self
1431+
.probe_assoc_item(assoc_ident, mode.kind(), hir_ref_id, span, trait_did)
1432+
.expect("failed to find associated item");
1433+
let result = match mode {
1434+
LowerAssocMode::Type { .. } => {
1435+
let assoc_ty = self.lower_assoc_ty(span, assoc_item.def_id, assoc_segment, bound);
1436+
LoweredAssoc::Type(assoc_ty, assoc_item.def_id)
1437+
}
1438+
LowerAssocMode::Const => {
1439+
if assoc_item.has_type_const_attr(tcx) {
1440+
let assoc_ct =
1441+
self.lower_assoc_const(span, assoc_item.def_id, assoc_segment, bound);
1442+
LoweredAssoc::Const(assoc_ct)
1443+
} else {
1444+
let mut err = tcx.dcx().struct_span_err(
1445+
span,
1446+
"use of trait associated const without `#[type_const]`",
1447+
);
1448+
err.note("the declaration in the trait must be marked with `#[type_const]`");
1449+
return Err(err.emit());
1450+
}
1451+
}
1452+
};
13271453

13281454
if let Some(variant_def_id) = variant_resolution {
13291455
tcx.node_span_lint(AMBIGUOUS_ASSOCIATED_ITEMS, hir_ref_id, span, |lint| {
@@ -1339,7 +1465,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
13391465
};
13401466

13411467
could_refer_to(DefKind::Variant, variant_def_id, "");
1342-
could_refer_to(DefKind::AssocTy, assoc_ty.def_id, " also");
1468+
could_refer_to(mode.def_kind(), assoc_item.def_id, " also");
13431469

13441470
lint.span_suggestion(
13451471
span,
@@ -1349,7 +1475,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
13491475
);
13501476
});
13511477
}
1352-
Ok((ty, DefKind::AssocTy, assoc_ty.def_id))
1478+
Ok(result)
13531479
}
13541480

13551481
fn probe_inherent_assoc_ty(
@@ -2247,7 +2373,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
22472373
hir::ConstArgKind::Path(hir::QPath::TypeRelative(qself, segment)) => {
22482374
debug!(?qself, ?segment);
22492375
let ty = self.lower_ty(qself);
2250-
self.lower_const_assoc_path(hir_id, const_arg.span(), ty, qself, segment)
2376+
self.lower_assoc_path_const(hir_id, const_arg.span(), ty, qself, segment)
22512377
.unwrap_or_else(|guar| Const::new_error(tcx, guar))
22522378
}
22532379
hir::ConstArgKind::Path(qpath @ hir::QPath::LangItem(..)) => {
@@ -2362,114 +2488,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
23622488
}
23632489
}
23642490

2365-
#[instrument(level = "debug", skip(self), ret)]
2366-
pub fn lower_const_assoc_path(
2367-
&self,
2368-
hir_ref_id: HirId,
2369-
span: Span,
2370-
qself_ty: Ty<'tcx>,
2371-
qself: &'tcx hir::Ty<'tcx>,
2372-
assoc_segment: &'tcx hir::PathSegment<'tcx>,
2373-
) -> Result<Const<'tcx>, ErrorGuaranteed> {
2374-
debug!(%qself_ty, ?assoc_segment.ident);
2375-
let tcx = self.tcx();
2376-
2377-
let assoc_ident = assoc_segment.ident;
2378-
2379-
// Check if we have an enum variant or an inherent associated const.
2380-
// FIXME(mgca): handle assoc fns once we support those
2381-
if let Some(adt_def) = self.probe_adt(span, qself_ty) {
2382-
if adt_def.is_enum() {
2383-
let variant_def = adt_def
2384-
.variants()
2385-
.iter()
2386-
.find(|vd| tcx.hygienic_eq(assoc_ident, vd.ident(tcx), adt_def.did()));
2387-
if let Some(variant_def) = variant_def {
2388-
tcx.check_stability(variant_def.def_id, Some(hir_ref_id), span, None);
2389-
let _ = self.prohibit_generic_args(
2390-
slice::from_ref(assoc_segment).iter(),
2391-
GenericsArgsErrExtend::EnumVariant { qself, assoc_segment, adt_def },
2392-
);
2393-
let uv = ty::UnevaluatedConst::new(variant_def.def_id, ty::List::empty());
2394-
return Ok(Const::new_unevaluated(tcx, uv));
2395-
}
2396-
}
2397-
2398-
// FIXME(mgca): Support self types other than ADTs.
2399-
if let Some((ct, _)) = self.probe_inherent_assoc_const(
2400-
assoc_segment,
2401-
adt_def.did(),
2402-
qself_ty,
2403-
hir_ref_id,
2404-
span,
2405-
)? {
2406-
return Ok(ct);
2407-
}
2408-
}
2409-
2410-
let qself_res = if let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = &qself.kind {
2411-
path.res
2412-
} else {
2413-
Res::Err
2414-
};
2415-
2416-
// Find the type of the associated item, and the trait where the associated
2417-
// item is declared.
2418-
let bound_result = match (qself_ty.kind(), qself_res) {
2419-
(_, Res::SelfTyAlias { alias_to: impl_def_id, is_trait_impl: true, .. }) => {
2420-
// `Self` in an impl of a trait -- we have a concrete self type and a
2421-
// trait reference.
2422-
let Some(trait_ref) = tcx.impl_trait_ref(impl_def_id) else {
2423-
// A cycle error occurred, most likely.
2424-
self.dcx().span_bug(span, "expected cycle error");
2425-
};
2426-
2427-
self.probe_single_bound_for_assoc_item(
2428-
|| {
2429-
traits::supertraits(
2430-
tcx,
2431-
ty::Binder::dummy(trait_ref.instantiate_identity()),
2432-
)
2433-
},
2434-
AssocItemQSelf::SelfTyAlias,
2435-
ty::AssocKind::Const,
2436-
assoc_ident,
2437-
span,
2438-
None,
2439-
)
2440-
}
2441-
(
2442-
&ty::Param(_),
2443-
Res::SelfTyParam { trait_: param_did } | Res::Def(DefKind::TyParam, param_did),
2444-
) => self.probe_single_ty_param_bound_for_assoc_item(
2445-
param_did.expect_local(),
2446-
qself.span,
2447-
ty::AssocKind::Const,
2448-
assoc_ident,
2449-
span,
2450-
),
2451-
_ => panic!("handle errors here"), // FIXME: do this
2452-
};
2453-
let bound = match bound_result {
2454-
Ok(b) => b,
2455-
Err(reported) => return Err(reported),
2456-
};
2457-
2458-
let trait_did = bound.def_id();
2459-
let assoc_const = self
2460-
.probe_assoc_item(assoc_ident, ty::AssocKind::Const, hir_ref_id, span, trait_did)
2461-
.expect("failed to find associated const");
2462-
if assoc_const.has_type_const_attr(tcx) {
2463-
Ok(self.lower_assoc_const(span, assoc_const.def_id, assoc_segment, bound))
2464-
} else {
2465-
let mut err = tcx
2466-
.dcx()
2467-
.struct_span_err(span, "use of trait associated const without `#[type_const]`");
2468-
err.note("the declaration in the trait must be marked with `#[type_const]`");
2469-
Err(err.emit())
2470-
}
2471-
}
2472-
24732491
/// Literals are eagerly converted to a constant, everything else becomes `Unevaluated`.
24742492
#[instrument(skip(self), level = "debug")]
24752493
fn lower_anon_const(&self, anon: &AnonConst) -> Const<'tcx> {
@@ -2670,7 +2688,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
26702688
hir::TyKind::Path(hir::QPath::TypeRelative(qself, segment)) => {
26712689
debug!(?qself, ?segment);
26722690
let ty = self.lower_ty(qself);
2673-
self.lower_assoc_path(hir_ty.hir_id, hir_ty.span, ty, qself, segment, false)
2691+
self.lower_assoc_path_ty(hir_ty.hir_id, hir_ty.span, ty, qself, segment, false)
26742692
.map(|(ty, _, _)| ty)
26752693
.unwrap_or_else(|guar| Ty::new_error(tcx, guar))
26762694
}

0 commit comments

Comments
 (0)