Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add field_of! macro and field representing types #118658

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions compiler/rustc_ast/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2093,6 +2093,8 @@ pub enum TyKind {
/// generate `NodeId`s on the fly, which would complicate
/// the generation of opaque `type Foo = impl Trait` items significantly.
ImplTrait(NodeId, GenericBounds),
/// `field_of!($ty, $field)` type.
FieldInfo(P<Ty>, Ident),
/// No-op; kept solely so that we can pretty-print faithfully.
Paren(P<Ty>),
/// Unused for now.
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_ast/src/mut_visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -513,6 +513,10 @@ pub fn noop_visit_ty<T: MutVisitor>(ty: &mut P<Ty>, vis: &mut T) {
vis.visit_id(id);
visit_vec(bounds, |bound| vis.visit_param_bound(bound));
}
TyKind::FieldInfo(container, field) => {
vis.visit_ty(container);
vis.visit_ident(field);
}
TyKind::MacCall(mac) => vis.visit_mac_call(mac),
TyKind::AnonStruct(fields) | TyKind::AnonUnion(fields) => {
fields.flat_map_in_place(|field| vis.flat_map_field_def(field));
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_ast/src/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,10 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) {
TyKind::ImplTrait(_, bounds) => {
walk_list!(visitor, visit_param_bound, bounds, BoundKind::Impl);
}
TyKind::FieldInfo(container, field) => {
visitor.visit_ty(container);
visitor.visit_ident(*field);
}
TyKind::Typeof(expression) => visitor.visit_anon_const(expression),
TyKind::Infer | TyKind::ImplicitSelf | TyKind::Err => {}
TyKind::MacCall(mac) => visitor.visit_mac_call(mac),
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_ast_lowering/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1373,6 +1373,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
TyKind::Path(qself, path) => {
return self.lower_path_ty(t, qself, path, ParamMode::Explicit, itctx);
}
TyKind::FieldInfo(container, field) => {
hir::TyKind::FieldInfo(self.lower_ty(container, itctx), self.lower_ident(*field))
}
TyKind::ImplicitSelf => {
let hir_id = self.next_id();
let res = self.expect_full_res(t.id);
Expand Down
8 changes: 8 additions & 0 deletions compiler/rustc_ast_pretty/src/pprust/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1003,6 +1003,14 @@ impl<'a> State<'a> {
self.word_nbsp("impl");
self.print_type_bounds(bounds);
}
ast::TyKind::FieldInfo(container, field) => {
self.word("builtin # field_of!");
self.popen();
self.print_type(container);
self.word(",");
self.print_ident(*field);
self.pclose();
}
ast::TyKind::Array(ty, length) => {
self.word("[");
self.print_type(ty);
Expand Down
6 changes: 4 additions & 2 deletions compiler/rustc_borrowck/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1621,7 +1621,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
| ty::Bound(_, _)
| ty::Infer(_)
| ty::Error(_)
| ty::Placeholder(_) => {
| ty::Placeholder(_)
| ty::FieldInfo(..) => {
bug!("When Place is Deref it's type shouldn't be {place_ty:#?}")
}
},
Expand Down Expand Up @@ -1658,7 +1659,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
| ty::Bound(_, _)
| ty::Infer(_)
| ty::Error(_)
| ty::Placeholder(_) => bug!(
| ty::Placeholder(_)
| ty::FieldInfo(..) => bug!(
"When Place contains ProjectionElem::Field it's type shouldn't be {place_ty:#?}"
),
},
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
Original file line number Diff line number Diff line change
Expand Up @@ -426,7 +426,8 @@ fn push_debuginfo_type_name<'tcx>(
| ty::Placeholder(..)
| ty::Alias(..)
| ty::Bound(..)
| ty::CoroutineWitness(..) => {
| ty::CoroutineWitness(..)
| ty::FieldInfo(..) => {
bug!(
"debuginfo: Trying to create type name for \
unexpected type: {:?}",
Expand Down
6 changes: 4 additions & 2 deletions compiler/rustc_const_eval/src/const_eval/valtrees.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,8 @@ pub(crate) fn const_to_valtree_inner<'tcx>(
// FIXME(oli-obk): we can probably encode closures just like structs
| ty::Closure(..)
| ty::Coroutine(..)
| ty::CoroutineWitness(..) => Err(ValTreeCreationError::NonSupportedType),
| ty::CoroutineWitness(..)
| ty::FieldInfo(..) => Err(ValTreeCreationError::NonSupportedType),
}
}

Expand Down Expand Up @@ -306,7 +307,8 @@ pub fn valtree_to_const_value<'tcx>(
| ty::FnPtr(_)
| ty::Str
| ty::Slice(_)
| ty::Dynamic(..) => bug!("no ValTree should have been created for type {:?}", ty.kind()),
| ty::Dynamic(..)
| ty::FieldInfo(..) => bug!("no ValTree should have been created for type {:?}", ty.kind()),
}
}

Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_const_eval/src/interpret/eval_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1013,7 +1013,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
| ty::Array(..)
| ty::Closure(..)
| ty::Never
| ty::Error(_) => true,
| ty::Error(_)
| ty::FieldInfo(..) => true,

ty::Str | ty::Slice(_) | ty::Dynamic(..) | ty::Foreign(..) => false,

Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_const_eval/src/interpret/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,8 @@ pub(crate) fn eval_nullary_intrinsic<'tcx>(
| ty::CoroutineWitness(..)
| ty::Never
| ty::Tuple(_)
| ty::Error(_) => ConstValue::from_target_usize(0u64, &tcx),
| ty::Error(_)
| ty::FieldInfo(..) => ConstValue::from_target_usize(0u64, &tcx),
},
other => bug!("`{}` is not a zero arg intrinsic", other),
})
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_const_eval/src/interpret/validity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -580,7 +580,8 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
| ty::Str
| ty::Dynamic(..)
| ty::Closure(..)
| ty::Coroutine(..) => Ok(false),
| ty::Coroutine(..)
| ty::FieldInfo(..) => Ok(false),
// Some types only occur during typechecking, they have no layout.
// We should not see them here and we could not check them anyway.
ty::Error(_)
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_const_eval/src/util/type_name.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> {
| ty::FnPtr(_)
| ty::Never
| ty::Tuple(_)
| ty::Dynamic(_, _, _) => self.pretty_print_type(ty),
| ty::Dynamic(_, _, _)
| ty::FieldInfo(..) => self.pretty_print_type(ty),

// Placeholders (all printed as `_` to uniformize them).
ty::Param(_) | ty::Bound(..) | ty::Placeholder(_) | ty::Infer(_) | ty::Error(_) => {
Expand Down
12 changes: 9 additions & 3 deletions compiler/rustc_hir/src/def.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,8 @@ pub enum DefKind {
of_trait: bool,
},
Closure,
/// Field Representing type from `field_of!`.
FieldInfo,
}

impl DefKind {
Expand Down Expand Up @@ -160,6 +162,7 @@ impl DefKind {
DefKind::Closure => "closure",
DefKind::ExternCrate => "extern crate",
DefKind::GlobalAsm => "global assembly block",
DefKind::FieldInfo => "field info type",
}
}

Expand Down Expand Up @@ -197,7 +200,8 @@ impl DefKind {
| DefKind::ForeignTy
| DefKind::TraitAlias
| DefKind::AssocTy
| DefKind::TyParam => Some(Namespace::TypeNS),
| DefKind::TyParam
| DefKind::FieldInfo => Some(Namespace::TypeNS),

DefKind::Fn
| DefKind::Const
Expand Down Expand Up @@ -236,7 +240,8 @@ impl DefKind {
| DefKind::TraitAlias
| DefKind::AssocTy
| DefKind::TyParam
| DefKind::ExternCrate => DefPathData::TypeNs(name),
| DefKind::ExternCrate
| DefKind::FieldInfo => DefPathData::TypeNs(name),
DefKind::Fn
| DefKind::Const
| DefKind::ConstParam
Expand Down Expand Up @@ -295,7 +300,8 @@ impl DefKind {
| DefKind::AnonConst
| DefKind::InlineConst
| DefKind::GlobalAsm
| DefKind::ExternCrate => false,
| DefKind::ExternCrate
| DefKind::FieldInfo => false,
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_hir/src/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2542,6 +2542,8 @@ pub enum TyKind<'hir> {
/// A trait object type `Bound1 + Bound2 + Bound3`
/// where `Bound` is a trait or a lifetime.
TraitObject(&'hir [PolyTraitRef<'hir>], &'hir Lifetime, TraitObjectSyntax),
/// `field_of!($ty, $field)`.
FieldInfo(&'hir Ty<'hir>, Ident),
/// Unused for now.
Typeof(AnonConst),
/// `TyKind::Infer` means the type should be inferred instead of it having been
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_hir/src/intravisit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -860,6 +860,10 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) {
}
visitor.visit_lifetime(lifetime);
}
TyKind::FieldInfo(container, field) => {
visitor.visit_ty(container);
visitor.visit_ident(field);
}
TyKind::Typeof(ref expression) => visitor.visit_anon_const(expression),
TyKind::Infer | TyKind::Err(_) => {}
}
Expand Down
25 changes: 25 additions & 0 deletions compiler/rustc_hir_analysis/src/astconv/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2538,6 +2538,31 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
);
tcx.at(span).type_of(def_id).instantiate(tcx, args)
}
hir::TyKind::FieldInfo(container, field) => {
let span = container.span;
let container = self.ast_ty_to_ty(container);
match container.kind() {
ty::Adt(adt_def, args) if adt_def.is_struct() => {
if let Some(field_def) = adt_def
.non_enum_variant()
.fields
.iter()
.find(|f| f.ident(tcx) == *field)
{
tcx.type_of(field_def.field_repr).instantiate(tcx, args)
} else {
Ty::new_error(
tcx,
tcx.sess.err(format!("field `{field:?}` not found.")),
)
}
}
_ => Ty::new_error(
tcx,
tcx.sess.span_err(span, format!("`field_of!` only supports structs.")),
),
}
}
hir::TyKind::Array(ty, length) => {
let length = match length {
&hir::ArrayLen::Infer(_, span) => self.ct_infer(tcx.types.usize, None, span),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ impl<'tcx> InherentCollect<'tcx> {
let self_ty = self.tcx.type_of(id).instantiate_identity();
match *self_ty.kind() {
ty::Adt(def, _) => self.check_def_id(id, self_ty, def.did()),
ty::FieldInfo(def, ..) => self.check_def_id(id, self_ty, def.did()),
ty::Foreign(did) => self.check_def_id(id, self_ty, did),
ty::Dynamic(data, ..) if data.principal_def_id().is_some() => {
self.check_def_id(id, self_ty, data.principal_def_id().unwrap());
Expand Down
8 changes: 8 additions & 0 deletions compiler/rustc_hir_analysis/src/coherence/orphan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,14 @@ fn do_orphan_check_impl<'tcx>(
NonlocalImpl::DisallowBecauseNonlocal
},
),
ty::FieldInfo(def, ..) => (
LocalImpl::Allow,
if def.container().is_local() {
NonlocalImpl::Allow
} else {
NonlocalImpl::DisallowBecauseNonlocal
},
),

// extern { type OpaqueType; }
// impl AutoTrait for OpaqueType {}
Expand Down
31 changes: 30 additions & 1 deletion compiler/rustc_hir_analysis/src/collect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ pub fn provide(providers: &mut Providers) {
type_param_predicates: predicates_of::type_param_predicates,
trait_def,
adt_def,
field_info_def,
fn_sig,
impl_trait_ref,
impl_polarity,
Expand Down Expand Up @@ -781,6 +782,26 @@ fn convert_enum_variant_types(tcx: TyCtxt<'_>, def_id: DefId) {
}
}

fn convert_field_repr(
tcx: TyCtxt<'_>,
f: &hir::FieldDef<'_>,
parent_did: LocalDefId,
ident: Ident,
) -> DefId {
let field_repr = tcx.at(f.span).create_def(
f.def_id,
Symbol::intern(&format!("{ident:?}->{:?}", f.ident)),
DefKind::FieldInfo,
);
field_repr.opt_local_def_id_to_hir_id(None);
field_repr.def_ident_span(Some(f.span));
field_repr.visibility(tcx.visibility(f.def_id));
field_repr.generics_of(tcx.generics_of(parent_did).clone());
field_repr.inferred_outlives_of(&[]);
//field_repr.type_of();
field_repr.def_id().to_def_id()
}

fn convert_variant(
tcx: TyCtxt<'_>,
variant_did: Option<LocalDefId>,
Expand All @@ -805,8 +826,9 @@ fn convert_variant(
} else {
seen_fields.insert(f.ident.normalize_to_macros_2_0(), f.span);
}

let field_repr = convert_field_repr(tcx, f, parent_did, ident);
ty::FieldDef {
field_repr,
did: f.def_id.to_def_id(),
name: f.ident.name,
vis: tcx.visibility(f.def_id),
Expand Down Expand Up @@ -893,6 +915,13 @@ fn adt_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AdtDef<'_> {
tcx.mk_adt_def(def_id.to_def_id(), kind, variants, repr)
}

fn field_info_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::FieldInfoDef<'_> {
let parent_field = tcx.parent(def_id.to_def_id());
let field_hir = tcx.local_def_id_to_hir_id(parent_field.as_local().unwrap());
let item_id = tcx.hir().get_parent_item(field_hir);
tcx.mk_field_info_def(def_id.to_def_id(), item_id.def_id.to_def_id())
}

fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
let item = tcx.hir().expect_item(def_id);

Expand Down
7 changes: 7 additions & 0 deletions compiler/rustc_hir_analysis/src/collect/predicates_of.rs
Original file line number Diff line number Diff line change
Expand Up @@ -502,6 +502,13 @@ pub(super) fn explicit_predicates_of<'tcx>(
}
}
} else {
if matches!(def_kind, DefKind::FieldInfo) {
let parent = tcx.parent(def_id.to_def_id());
let parent_hir_id = tcx.local_def_id_to_hir_id(parent.as_local().unwrap());
let item_def_id = tcx.hir().get_parent_item(parent_hir_id);

return tcx.explicit_predicates_of(item_def_id);
}
if matches!(def_kind, DefKind::AnonConst) && tcx.features().generic_const_exprs {
let hir_id = tcx.local_def_id_to_hir_id(def_id);
let parent_def_id = tcx.hir().get_parent_item(hir_id);
Expand Down
12 changes: 12 additions & 0 deletions compiler/rustc_hir_analysis/src/collect/type_of.rs
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,18 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty
}
}

if let crate::DefKind::FieldInfo = tcx.def_kind(def_id.to_def_id()) {
let parent_field = tcx.parent(def_id.to_def_id());
let field = tcx.local_def_id_to_hir_id(parent_field.as_local().unwrap());
let parent_struct = tcx.hir().get_parent_item(field).to_def_id();
let args = ty::GenericArgs::identity_for_item(tcx, parent_struct);
return ty::EarlyBinder::bind(Ty::new_field_of(
tcx,
tcx.field_info_def(def_id.to_def_id()),
args,
));
}

let hir_id = tcx.local_def_id_to_hir_id(def_id);

let icx = ItemCtxt::new(tcx, def_id);
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_hir_analysis/src/variance/constraints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,10 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
self.add_constraints_from_sig(current, sig, variance);
}

ty::FieldInfo(_, args) => {
self.add_constraints_from_invariant_args(current, args, variance);
}

ty::Error(_) => {
// we encounter this when walking the trait references for object
// types, where we use Error as the Self type
Expand Down
8 changes: 8 additions & 0 deletions compiler/rustc_hir_analysis/src/variance/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,14 @@ fn variances_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Variance] {
let crate_map = tcx.crate_variances(());
return crate_map.variances.get(&item_def_id.to_def_id()).copied().unwrap_or(&[]);
}
DefKind::FieldInfo => {
// These are inferred.
let crate_map = tcx.crate_variances(());
let parent_field = tcx.parent(item_def_id.to_def_id());
let field_hir = tcx.local_def_id_to_hir_id(parent_field.as_local().unwrap());
let parent_struct = tcx.hir().get_parent_item(field_hir);
return crate_map.variances.get(&parent_struct.to_def_id()).copied().unwrap_or(&[]);
}
DefKind::OpaqueTy => {
return variance_of_opaque(tcx, item_def_id);
}
Expand Down
Loading
Loading