Skip to content

Commit c0bd0c6

Browse files
committed
reject type alias impl traits as field types
1 parent 8cb207a commit c0bd0c6

File tree

1 file changed

+118
-1
lines changed

1 file changed

+118
-1
lines changed

compiler/rustc_typeck/src/check/check.rs

Lines changed: 118 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use rustc_hir as hir;
99
use rustc_hir::def_id::{DefId, LocalDefId};
1010
use rustc_hir::intravisit::Visitor;
1111
use rustc_hir::lang_items::LangItem;
12-
use rustc_hir::{def::Res, ItemKind, Node, PathSegment};
12+
use rustc_hir::{def::DefKind, def::Res, ItemKind, Node, PathSegment};
1313
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
1414
use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt};
1515
use rustc_middle::ty::fold::TypeFoldable;
@@ -414,7 +414,12 @@ pub(super) fn check_fn<'a, 'tcx>(
414414
}
415415

416416
fn check_struct(tcx: TyCtxt<'_>, def_id: LocalDefId, span: Span) {
417+
debug!("check_struct(def_id: {:?}, span: {:?})", def_id, span);
418+
417419
let def = tcx.adt_def(def_id);
420+
421+
check_fields_for_opaque_types(tcx, def, def_id, span);
422+
418423
def.destructor(tcx); // force the destructor to be evaluated
419424
check_representable(tcx, span, def_id);
420425

@@ -426,8 +431,119 @@ fn check_struct(tcx: TyCtxt<'_>, def_id: LocalDefId, span: Span) {
426431
check_packed(tcx, span, def);
427432
}
428433

434+
fn check_fields_for_opaque_types(
435+
tcx: TyCtxt<'tcx>,
436+
adt_def: &ty::AdtDef,
437+
def_id: LocalDefId,
438+
span: Span,
439+
) {
440+
fn find_span_of_field_def_and_ty_alias(
441+
tcx: TyCtxt<'tcx>,
442+
field_def: &ty::FieldDef,
443+
) -> (Option<Span>, Option<Span>) {
444+
let field_def_def_id = field_def.did;
445+
if let Some(field_def_local_id) = field_def_def_id.as_local() {
446+
let field_def_hir_id = tcx.hir().local_def_id_to_hir_id(field_def_local_id);
447+
if let hir::Node::Field(hir::FieldDef {
448+
span: field_def_span, ty: field_def_ty, ..
449+
}) = tcx.hir().get(field_def_hir_id)
450+
{
451+
if let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = field_def_ty.kind {
452+
if let Res::Def(DefKind::TyAlias, ty_alias_def_id) = path.res {
453+
if let Some(ty_alias_local_id) = ty_alias_def_id.as_local() {
454+
let ty_alias_hir_id =
455+
tcx.hir().local_def_id_to_hir_id(ty_alias_local_id);
456+
let node = tcx.hir().get(ty_alias_hir_id);
457+
match node {
458+
hir::Node::Item(hir::Item {
459+
kind, span: ty_alias_span, ..
460+
}) => match kind {
461+
hir::ItemKind::TyAlias(_, _) => {
462+
return (Some(*field_def_span), Some(*ty_alias_span));
463+
}
464+
_ => bug!("expected an item of kind TyAlias"),
465+
},
466+
_ => return (Some(*field_def_span), None),
467+
}
468+
}
469+
}
470+
}
471+
}
472+
}
473+
(None, None)
474+
}
475+
476+
debug!("check_fields_of_opaque_types(adt_def: {:?}, span: {:?})", adt_def, span);
477+
478+
let item_type = tcx.type_of(def_id);
479+
let substs = match item_type.kind() {
480+
ty::Adt(_, substs) => substs,
481+
_ => bug!("check_fields_for_opaque_types should only be called on Adts"),
482+
};
483+
adt_def.all_fields().for_each(|field_def| {
484+
debug!("field_def: {:?}", field_def);
485+
486+
let field_ty = field_def.ty(tcx, substs);
487+
match field_ty.kind() {
488+
ty::Opaque(..) => {
489+
use ty::AdtKind::*;
490+
let adt_kind = match adt_def.adt_kind() {
491+
Struct => "struct",
492+
Enum => "enum",
493+
Union => "union",
494+
};
495+
496+
let mut diag;
497+
match find_span_of_field_def_and_ty_alias(tcx, field_def) {
498+
(Some(field_def_span), Some(ty_alias_span)) => {
499+
diag = tcx.sess.struct_span_err(
500+
span,
501+
&format!(
502+
"type alias impl traits are not allowed as field types in {}s",
503+
adt_kind
504+
),
505+
);
506+
diag.span_label(
507+
field_def_span,
508+
"this field contains a type alias impl trait",
509+
);
510+
diag.span_label(ty_alias_span, "type alias defined here");
511+
}
512+
(Some(field_def_span), None) => {
513+
diag = tcx.sess.struct_span_err(
514+
span,
515+
&format!(
516+
"type alias impl traits are not allowed as field types in {}s",
517+
adt_kind
518+
),
519+
);
520+
521+
diag.span_label(
522+
field_def_span,
523+
"this field contains a type alias impl trait",
524+
);
525+
}
526+
_ => {
527+
diag = tcx.sess.struct_span_err(
528+
span,
529+
&format!(
530+
"type alias impl traits are not allowed as field types in {}s",
531+
adt_kind
532+
),
533+
);
534+
}
535+
}
536+
537+
diag.emit();
538+
}
539+
_ => {}
540+
}
541+
});
542+
}
543+
429544
fn check_union(tcx: TyCtxt<'_>, def_id: LocalDefId, span: Span) {
430545
let def = tcx.adt_def(def_id);
546+
check_fields_for_opaque_types(tcx, def, def_id, span);
431547
def.destructor(tcx); // force the destructor to be evaluated
432548
check_representable(tcx, span, def_id);
433549
check_transparent(tcx, span, def);
@@ -1408,6 +1524,7 @@ fn check_enum<'tcx>(
14081524
def_id: LocalDefId,
14091525
) {
14101526
let def = tcx.adt_def(def_id);
1527+
check_fields_for_opaque_types(tcx, def, def_id, sp);
14111528
def.destructor(tcx); // force the destructor to be evaluated
14121529

14131530
if vs.is_empty() {

0 commit comments

Comments
 (0)