Skip to content

Commit d9dab43

Browse files
committed
move lower_field_of to rustc_hir_analysis and improve diagnostics
1 parent d95cb89 commit d9dab43

12 files changed

Lines changed: 233 additions & 265 deletions

File tree

compiler/rustc_hir_analysis/messages.ftl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,8 @@ hir_analysis_missing_trait_item_unstable = not all trait items implemented, miss
376376
.some_note = use of unstable library feature `{$feature}`: {$reason}
377377
.none_note = use of unstable library feature `{$feature}`
378378
379+
hir_analysis_no_field_on_type = no field `{$field}` on type `{$ty}`
380+
379381
hir_analysis_no_variant_named = no variant named `{$ident}` found for enum `{$ty}`
380382
381383
hir_analysis_not_supported_delegation = {$descr}

compiler/rustc_hir_analysis/src/errors.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1295,6 +1295,15 @@ pub struct NoVariantNamed<'tcx> {
12951295
pub ty: Ty<'tcx>,
12961296
}
12971297

1298+
#[derive(Diagnostic)]
1299+
#[diag(hir_analysis_no_field_on_type, code = E0609)]
1300+
pub struct NoFieldOnType<'tcx> {
1301+
#[primary_span]
1302+
pub span: Span,
1303+
pub ty: Ty<'tcx>,
1304+
pub field: Ident,
1305+
}
1306+
12981307
// FIXME(fmease): Deduplicate:
12991308

13001309
#[derive(Diagnostic)]

compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs

Lines changed: 167 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ pub mod generics;
2121

2222
use std::slice;
2323

24+
use rustc_abi::FIRST_VARIANT;
2425
use rustc_ast::LitKind;
2526
use rustc_data_structures::assert_matches;
2627
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
@@ -39,7 +40,7 @@ use rustc_middle::middle::stability::AllowUnstable;
3940
use rustc_middle::mir::interpret::LitToConstInput;
4041
use rustc_middle::ty::print::PrintPolyTraitRefExt as _;
4142
use rustc_middle::ty::{
42-
self, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, Ty, TyCtxt,
43+
self, Const, FieldId, GenericArgKind, GenericArgsRef, GenericParamDefKind, Ty, TyCtxt,
4344
TypeSuperFoldable, TypeVisitableExt, TypingMode, Upcast, fold_regions,
4445
};
4546
use rustc_middle::{bug, span_bug};
@@ -52,11 +53,11 @@ use rustc_trait_selection::traits::{self, FulfillmentError};
5253
use tracing::{debug, instrument};
5354

5455
use crate::check::check_abi;
55-
use crate::check_c_variadic_abi;
56-
use crate::errors::{AmbiguousLifetimeBound, BadReturnTypeNotation};
56+
use crate::errors::{AmbiguousLifetimeBound, BadReturnTypeNotation, NoFieldOnType};
5757
use crate::hir_ty_lowering::errors::{GenericsArgsErrExtend, prohibit_assoc_item_constraint};
5858
use crate::hir_ty_lowering::generics::{check_generic_arg_count, lower_generic_args};
5959
use crate::middle::resolve_bound_vars as rbv;
60+
use crate::{NoVariantNamed, check_c_variadic_abi};
6061

6162
/// The context in which an implied bound is being added to a item being lowered (i.e. a sizedness
6263
/// trait or a default trait)
@@ -3004,8 +3005,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
30043005
self.record_ty(pat.hir_id, ty, pat.span);
30053006
pat_ty
30063007
}
3007-
hir::TyKind::FieldOf(ty, hir::TyFieldPath { variant, field }) => ty::lower_field_of(
3008-
self.tcx(),
3008+
hir::TyKind::FieldOf(ty, hir::TyFieldPath { variant, field }) => self.lower_field_of(
30093009
self.lower_ty(ty),
30103010
self.item_def_id(),
30113011
ty.span,
@@ -3054,6 +3054,168 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
30543054
}
30553055
}
30563056

3057+
fn lower_field_of(
3058+
&self,
3059+
ty: Ty<'tcx>,
3060+
item_def_id: LocalDefId,
3061+
ty_span: Span,
3062+
hir_id: HirId,
3063+
variant: Option<Ident>,
3064+
field: Ident,
3065+
) -> Ty<'tcx> {
3066+
let dcx = self.dcx();
3067+
let tcx = self.tcx();
3068+
match ty.kind() {
3069+
ty::Adt(def, _) => {
3070+
let base_did = def.did();
3071+
let kind_name = tcx.def_descr(base_did);
3072+
let (variant_idx, variant) = if def.is_enum() {
3073+
let Some(variant) = variant else {
3074+
let err = dcx
3075+
.create_err(NoVariantNamed { span: field.span, ident: field, ty })
3076+
.with_span_help(
3077+
field.span.shrink_to_lo(),
3078+
"you might be missing a variant here: `Variant.`",
3079+
)
3080+
.emit();
3081+
return Ty::new_error(tcx, err);
3082+
};
3083+
3084+
if let Some(res) = def
3085+
.variants()
3086+
.iter_enumerated()
3087+
.find(|(_, f)| f.ident(tcx).normalize_to_macros_2_0() == variant)
3088+
{
3089+
res
3090+
} else {
3091+
let err = dcx
3092+
.create_err(NoVariantNamed { span: variant.span, ident: variant, ty })
3093+
.emit();
3094+
return Ty::new_error(tcx, err);
3095+
}
3096+
} else {
3097+
if let Some(variant) = variant {
3098+
let adt_path = tcx.def_path_str(base_did);
3099+
struct_span_code_err!(
3100+
dcx,
3101+
variant.span,
3102+
E0609,
3103+
"{kind_name} `{adt_path}` does not have any variants",
3104+
)
3105+
.with_span_label(variant.span, "variant unknown")
3106+
.emit();
3107+
}
3108+
(FIRST_VARIANT, def.non_enum_variant())
3109+
};
3110+
let block = tcx.local_def_id_to_hir_id(item_def_id);
3111+
let (ident, def_scope) = tcx.adjust_ident_and_get_scope(field, def.did(), block);
3112+
if let Some((field_idx, field)) = variant
3113+
.fields
3114+
.iter_enumerated()
3115+
.find(|(_, f)| f.ident(tcx).normalize_to_macros_2_0() == ident)
3116+
{
3117+
if field.vis.is_accessible_from(def_scope, tcx) {
3118+
tcx.check_stability(field.did, Some(hir_id), ident.span, None);
3119+
} else {
3120+
let adt_path = tcx.def_path_str(base_did);
3121+
struct_span_code_err!(
3122+
dcx,
3123+
ident.span,
3124+
E0616,
3125+
"field `{ident}` of {kind_name} `{adt_path}` is private",
3126+
)
3127+
.with_span_label(ident.span, "private field")
3128+
.emit();
3129+
}
3130+
Ty::new_field_representing_type(
3131+
tcx,
3132+
ty,
3133+
FieldId { variant: variant_idx, field: field_idx },
3134+
)
3135+
} else {
3136+
let err =
3137+
dcx.create_err(NoFieldOnType { span: ident.span, field: ident, ty }).emit();
3138+
Ty::new_error(tcx, err)
3139+
}
3140+
}
3141+
ty::Tuple(tys) => {
3142+
let index = match field.as_str().parse::<usize>() {
3143+
Ok(idx) => idx,
3144+
Err(_) => {
3145+
let err =
3146+
dcx.create_err(NoFieldOnType { span: field.span, field, ty }).emit();
3147+
return Ty::new_error(tcx, err);
3148+
}
3149+
};
3150+
if field.name != sym::integer(index) {
3151+
bug!("we parsed above, but now not equal?");
3152+
}
3153+
if tys.get(index).is_some() {
3154+
Ty::new_field_representing_type(
3155+
tcx,
3156+
ty,
3157+
FieldId { variant: FIRST_VARIANT, field: index.into() },
3158+
)
3159+
} else {
3160+
let err = dcx.create_err(NoFieldOnType { span: field.span, field, ty }).emit();
3161+
Ty::new_error(tcx, err)
3162+
}
3163+
}
3164+
// FIXME(FRTs): support type aliases
3165+
/*
3166+
ty::Alias(AliasTyKind::Free, ty) => {
3167+
return self.lower_field_of(
3168+
ty,
3169+
item_def_id,
3170+
ty_span,
3171+
hir_id,
3172+
variant,
3173+
field,
3174+
);
3175+
}*/
3176+
ty::Alias(..) => Ty::new_error(
3177+
tcx,
3178+
dcx.span_err(ty_span, format!("could not resolve fields of `{ty}`")),
3179+
),
3180+
ty::Error(err) => Ty::new_error(tcx, *err),
3181+
ty::Bool
3182+
| ty::Char
3183+
| ty::Int(_)
3184+
| ty::Uint(_)
3185+
| ty::Float(_)
3186+
| ty::Foreign(_)
3187+
| ty::Str
3188+
| ty::FRT(_, _)
3189+
| ty::RawPtr(_, _)
3190+
| ty::Ref(_, _, _)
3191+
| ty::FnDef(_, _)
3192+
| ty::FnPtr(_, _)
3193+
| ty::UnsafeBinder(_)
3194+
| ty::Dynamic(_, _)
3195+
| ty::Closure(_, _)
3196+
| ty::CoroutineClosure(_, _)
3197+
| ty::Coroutine(_, _)
3198+
| ty::CoroutineWitness(_, _)
3199+
| ty::Never
3200+
| ty::Param(_)
3201+
| ty::Bound(_, _)
3202+
| ty::Placeholder(_)
3203+
| ty::Slice(..) => Ty::new_error(
3204+
tcx,
3205+
dcx.span_err(ty_span, format!("type `{ty}` doesn't have fields")),
3206+
),
3207+
ty::Infer(_) => Ty::new_error(
3208+
tcx,
3209+
dcx.span_err(ty_span, format!("cannot use `{ty}` in this position")),
3210+
),
3211+
// FIXME(FRTs): support these types?
3212+
ty::Array(..) | ty::Pat(..) => Ty::new_error(
3213+
tcx,
3214+
dcx.span_err(ty_span, format!("type `{ty}` is not yet supported in `field_of!`")),
3215+
),
3216+
}
3217+
}
3218+
30573219
/// Lower an opaque type (i.e., an existential impl-Trait type) from the HIR.
30583220
#[instrument(level = "debug", skip(self), ret)]
30593221
fn lower_opaque_ty(&self, def_id: LocalDefId, in_trait: Option<LocalDefId>) -> Ty<'tcx> {

compiler/rustc_hir_analysis/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ mod impl_wf_check;
8282
mod outlives;
8383
mod variance;
8484

85-
pub use errors::NoVariantNamed;
85+
pub use errors::{NoFieldOnType, NoVariantNamed};
8686
use rustc_abi::{CVariadicStatus, ExternAbi};
8787
use rustc_hir::attrs::AttributeKind;
8888
use rustc_hir::def::DefKind;

compiler/rustc_hir_typeck/messages.ftl

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -193,8 +193,6 @@ hir_typeck_no_associated_item = no {$item_kind} named `{$item_ident}` found for
193193
*[other] {" "}in the current scope
194194
}
195195
196-
hir_typeck_no_field_on_type = no field `{$field}` on type `{$ty}`
197-
198196
hir_typeck_no_field_on_variant = no field named `{$field}` on enum variant `{$container}::{$ident}`
199197
hir_typeck_no_field_on_variant_enum = this enum variant...
200198
hir_typeck_no_field_on_variant_field = ...does not have this field

compiler/rustc_hir_typeck/src/errors.rs

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -450,15 +450,6 @@ impl HelpUseLatestEdition {
450450
}
451451
}
452452

453-
#[derive(Diagnostic)]
454-
#[diag(hir_typeck_no_field_on_type, code = E0609)]
455-
pub(crate) struct NoFieldOnType<'tcx> {
456-
#[primary_span]
457-
pub(crate) span: Span,
458-
pub(crate) ty: Ty<'tcx>,
459-
pub(crate) field: Ident,
460-
}
461-
462453
#[derive(Diagnostic)]
463454
#[diag(hir_typeck_no_field_on_variant, code = E0609)]
464455
pub(crate) struct NoFieldOnVariant<'tcx> {

compiler/rustc_hir_typeck/src/expr.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ use rustc_hir::def::{CtorKind, DefKind, Res};
2020
use rustc_hir::def_id::DefId;
2121
use rustc_hir::lang_items::LangItem;
2222
use rustc_hir::{ExprKind, HirId, QPath, find_attr, is_range_literal};
23-
use rustc_hir_analysis::NoVariantNamed;
2423
use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer as _;
24+
use rustc_hir_analysis::{NoFieldOnType, NoVariantNamed};
2525
use rustc_infer::infer::{self, DefineOpaqueTypes, InferOk, RegionVariableOrigin};
2626
use rustc_infer::traits::query::NoSolution;
2727
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase};
@@ -44,7 +44,7 @@ use crate::coercion::CoerceMany;
4444
use crate::errors::{
4545
AddressOfTemporaryTaken, BaseExpressionDoubleDot, BaseExpressionDoubleDotAddExpr,
4646
BaseExpressionDoubleDotRemove, CantDereference, FieldMultiplySpecifiedInInitializer,
47-
FunctionalRecordUpdateOnNonStruct, HelpUseLatestEdition, NakedAsmOutsideNakedFn, NoFieldOnType,
47+
FunctionalRecordUpdateOnNonStruct, HelpUseLatestEdition, NakedAsmOutsideNakedFn,
4848
NoFieldOnVariant, ReturnLikeStatementKind, ReturnStmtOutsideOfFnBody, StructExprNonExhaustive,
4949
TypeMismatchFruTypo, YieldExprOutsideOfCoroutine,
5050
};

0 commit comments

Comments
 (0)