Skip to content

Commit 7cbecce

Browse files
committed
Factor out shared code for lowering assoc item paths
1 parent 76d3584 commit 7cbecce

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, 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
///
@@ -1111,7 +1148,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
11111148
// NOTE: When this function starts resolving `Trait::AssocTy` successfully
11121149
// it should also start reporting the `BARE_TRAIT_OBJECTS` lint.
11131150
#[instrument(level = "debug", skip_all, ret)]
1114-
pub fn lower_assoc_path(
1151+
pub fn lower_assoc_path_ty(
11151152
&self,
11161153
hir_ref_id: HirId,
11171154
span: Span,
@@ -1120,6 +1157,56 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
11201157
assoc_segment: &'tcx hir::PathSegment<'tcx>,
11211158
permit_variants: bool,
11221159
) -> Result<(Ty<'tcx>, DefKind, DefId), ErrorGuaranteed> {
1160+
match self.lower_assoc_path_shared(
1161+
hir_ref_id,
1162+
span,
1163+
qself_ty,
1164+
qself,
1165+
assoc_segment,
1166+
LowerAssocMode::Type { permit_variants },
1167+
)? {
1168+
LoweredAssoc::Type(ty, def_id) => Ok((ty, DefKind::AssocTy, def_id)),
1169+
LoweredAssoc::Variant { adt, variant_did } => Ok((adt, DefKind::Variant, variant_did)),
1170+
LoweredAssoc::Const(_) => unreachable!("lowered assoc type to const somehow"),
1171+
}
1172+
}
1173+
1174+
#[instrument(level = "debug", skip_all, ret)]
1175+
fn lower_assoc_path_const(
1176+
&self,
1177+
hir_ref_id: HirId,
1178+
span: Span,
1179+
qself_ty: Ty<'tcx>,
1180+
qself: &'tcx hir::Ty<'tcx>,
1181+
assoc_segment: &'tcx hir::PathSegment<'tcx>,
1182+
) -> Result<Const<'tcx>, ErrorGuaranteed> {
1183+
match self.lower_assoc_path_shared(
1184+
hir_ref_id,
1185+
span,
1186+
qself_ty,
1187+
qself,
1188+
assoc_segment,
1189+
LowerAssocMode::Const,
1190+
)? {
1191+
LoweredAssoc::Type(..) => unreachable!("lowered assoc const to type somehow"),
1192+
LoweredAssoc::Variant { adt: _, variant_did } => {
1193+
let uv = ty::UnevaluatedConst::new(variant_did, ty::List::empty());
1194+
Ok(Const::new_unevaluated(self.tcx(), uv))
1195+
}
1196+
LoweredAssoc::Const(ct) => Ok(ct),
1197+
}
1198+
}
1199+
1200+
#[instrument(level = "debug", skip_all, ret)]
1201+
fn lower_assoc_path_shared(
1202+
&self,
1203+
hir_ref_id: HirId,
1204+
span: Span,
1205+
qself_ty: Ty<'tcx>,
1206+
qself: &'tcx hir::Ty<'tcx>,
1207+
assoc_segment: &'tcx hir::PathSegment<'tcx>,
1208+
mode: LowerAssocMode,
1209+
) -> Result<LoweredAssoc<'tcx>, ErrorGuaranteed> {
11231210
debug!(%qself_ty, ?assoc_segment.ident);
11241211
let tcx = self.tcx();
11251212

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

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

@@ -1184,7 +1290,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
11841290
)
11851291
},
11861292
AssocItemQSelf::SelfTyAlias,
1187-
ty::AssocKind::Type,
1293+
mode.kind(),
11881294
assoc_ident,
11891295
span,
11901296
None,
@@ -1196,14 +1302,15 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
11961302
) => self.probe_single_ty_param_bound_for_assoc_item(
11971303
param_did.expect_local(),
11981304
qself.span,
1199-
ty::AssocKind::Type,
1305+
mode.kind(),
12001306
assoc_ident,
12011307
span,
12021308
)?,
12031309
_ => {
1310+
let kind_str = assoc_kind_str(mode.kind());
12041311
let reported = if variant_resolution.is_some() {
12051312
// Variant in type position
1206-
let msg = format!("expected type, found variant `{assoc_ident}`");
1313+
let msg = format!("expected {kind_str}, found variant `{assoc_ident}`");
12071314
self.dcx().span_err(span, msg)
12081315
} else if qself_ty.is_enum() {
12091316
let mut err = struct_span_code_err!(
@@ -1311,18 +1418,37 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
13111418
&[qself_ty.to_string()],
13121419
&traits,
13131420
assoc_ident.name,
1314-
ty::AssocKind::Type,
1421+
mode.kind(),
13151422
)
13161423
};
13171424
return Err(reported);
13181425
}
13191426
};
13201427

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

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

13401466
could_refer_to(DefKind::Variant, variant_def_id, "");
1341-
could_refer_to(DefKind::AssocTy, assoc_ty.def_id, " also");
1467+
could_refer_to(mode.def_kind(), assoc_item.def_id, " also");
13421468

13431469
lint.span_suggestion(
13441470
span,
@@ -1348,7 +1474,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
13481474
);
13491475
});
13501476
}
1351-
Ok((ty, DefKind::AssocTy, assoc_ty.def_id))
1477+
Ok(result)
13521478
}
13531479

13541480
fn probe_inherent_assoc_ty(
@@ -2246,7 +2372,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
22462372
hir::ConstArgKind::Path(hir::QPath::TypeRelative(qself, segment)) => {
22472373
debug!(?qself, ?segment);
22482374
let ty = self.lower_ty(qself);
2249-
self.lower_const_assoc_path(hir_id, const_arg.span(), ty, qself, segment)
2375+
self.lower_assoc_path_const(hir_id, const_arg.span(), ty, qself, segment)
22502376
.unwrap_or_else(|guar| Const::new_error(tcx, guar))
22512377
}
22522378
hir::ConstArgKind::Path(qpath @ hir::QPath::LangItem(..)) => {
@@ -2361,114 +2487,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
23612487
}
23622488
}
23632489

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

0 commit comments

Comments
 (0)