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

Don't allow opaque ty aliases in ADT fields #86928

Closed
Show file tree
Hide file tree
Changes from 2 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
119 changes: 118 additions & 1 deletion compiler/rustc_typeck/src/check/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::intravisit::Visitor;
use rustc_hir::lang_items::LangItem;
use rustc_hir::{def::Res, ItemKind, Node, PathSegment};
use rustc_hir::{def::DefKind, def::Res, ItemKind, Node, PathSegment};
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt};
use rustc_middle::ty::fold::TypeFoldable;
Expand Down Expand Up @@ -414,7 +414,12 @@ pub(super) fn check_fn<'a, 'tcx>(
}

fn check_struct(tcx: TyCtxt<'_>, def_id: LocalDefId, span: Span) {
debug!("check_struct(def_id: {:?}, span: {:?})", def_id, span);

let def = tcx.adt_def(def_id);

check_fields_for_opaque_types(tcx, def, def_id, span);

def.destructor(tcx); // force the destructor to be evaluated
check_representable(tcx, span, def_id);

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

fn check_fields_for_opaque_types(
tcx: TyCtxt<'tcx>,
adt_def: &ty::AdtDef,
def_id: LocalDefId,
span: Span,
) {
fn find_span_of_field_def_and_ty_alias(
tcx: TyCtxt<'tcx>,
field_def: &ty::FieldDef,
) -> (Option<Span>, Option<Span>) {
let field_def_def_id = field_def.did;
if let Some(field_def_local_id) = field_def_def_id.as_local() {
let field_def_hir_id = tcx.hir().local_def_id_to_hir_id(field_def_local_id);
if let hir::Node::Field(hir::FieldDef {
span: field_def_span, ty: field_def_ty, ..
}) = tcx.hir().get(field_def_hir_id)
{
if let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = field_def_ty.kind {
if let Res::Def(DefKind::TyAlias, ty_alias_def_id) = path.res {
if let Some(ty_alias_local_id) = ty_alias_def_id.as_local() {
let ty_alias_hir_id =
tcx.hir().local_def_id_to_hir_id(ty_alias_local_id);
let node = tcx.hir().get(ty_alias_hir_id);
match node {
hir::Node::Item(hir::Item {
kind, span: ty_alias_span, ..
}) => match kind {
hir::ItemKind::TyAlias(_, _) => {
return (Some(*field_def_span), Some(*ty_alias_span));
}
_ => bug!("expected an item of kind TyAlias"),
},
_ => return (Some(*field_def_span), None),
}
}
}
}
}
}
(None, None)
}

debug!("check_fields_of_opaque_types(adt_def: {:?}, span: {:?})", adt_def, span);

let item_type = tcx.type_of(def_id);
let substs = match item_type.kind() {
ty::Adt(_, substs) => substs,
_ => bug!("check_fields_for_opaque_types should only be called on Adts"),
};
adt_def.all_fields().for_each(|field_def| {
debug!("field_def: {:?}", field_def);

let field_ty = field_def.ty(tcx, substs);
match field_ty.kind() {
ty::Opaque(..) => {
use ty::AdtKind::*;
let adt_kind = match adt_def.adt_kind() {
Struct => "struct",
Enum => "enum",
Union => "union",
};

let mut diag;
match find_span_of_field_def_and_ty_alias(tcx, field_def) {
(Some(field_def_span), Some(ty_alias_span)) => {
diag = tcx.sess.struct_span_err(
span,
&format!(
"type alias impl traits are not allowed as field types in {}s",
adt_kind
),
);
diag.span_label(
field_def_span,
"this field contains a type alias impl trait",
);
diag.span_label(ty_alias_span, "type alias defined here");
}
(Some(field_def_span), None) => {
diag = tcx.sess.struct_span_err(
span,
&format!(
"type alias impl traits are not allowed as field types in {}s",
adt_kind
),
);

diag.span_label(
field_def_span,
"this field contains a type alias impl trait",
);
}
_ => {
diag = tcx.sess.struct_span_err(
span,
&format!(
"type alias impl traits are not allowed as field types in {}s",
adt_kind
),
);
}
}

diag.emit();
}
_ => {}
}
});
}

fn check_union(tcx: TyCtxt<'_>, def_id: LocalDefId, span: Span) {
let def = tcx.adt_def(def_id);
check_fields_for_opaque_types(tcx, def, def_id, span);
def.destructor(tcx); // force the destructor to be evaluated
check_representable(tcx, span, def_id);
check_transparent(tcx, span, def);
Expand Down Expand Up @@ -1408,6 +1524,7 @@ fn check_enum<'tcx>(
def_id: LocalDefId,
) {
let def = tcx.adt_def(def_id);
check_fields_for_opaque_types(tcx, def, def_id, sp);
def.destructor(tcx); // force the destructor to be evaluated

if vs.is_empty() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ type Foo = impl Debug;
//~^ ERROR could not find defining uses

struct Bar(Foo);
//~^ ERROR type alias impl traits are not allowed as field types in structs
fn define() -> Bar {
Bar(42) //~ ERROR mismatched types
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error[E0308]: mismatched types
--> $DIR/feature-gate-type_alias_impl_trait.rs:10:9
--> $DIR/feature-gate-type_alias_impl_trait.rs:11:9
|
LL | type Foo = impl Debug;
| ---------- the expected opaque type
Expand All @@ -11,7 +11,7 @@ LL | Bar(42)
found type `{integer}`

error[E0658]: type alias impl trait is not permitted here
--> $DIR/feature-gate-type_alias_impl_trait.rs:16:19
--> $DIR/feature-gate-type_alias_impl_trait.rs:17:19
|
LL | let x = || -> Foo2 { 42 };
| ^^^^
Expand All @@ -20,7 +20,7 @@ LL | let x = || -> Foo2 { 42 };
= help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable

error[E0308]: mismatched types
--> $DIR/feature-gate-type_alias_impl_trait.rs:23:18
--> $DIR/feature-gate-type_alias_impl_trait.rs:24:18
|
LL | type Foo3 = impl Debug;
| ---------- the found opaque type
Expand All @@ -34,7 +34,7 @@ LL | let y: i32 = x;
found opaque type `impl Debug`

error[E0308]: mismatched types
--> $DIR/feature-gate-type_alias_impl_trait.rs:26:13
--> $DIR/feature-gate-type_alias_impl_trait.rs:27:13
|
LL | type Foo3 = impl Debug;
| ---------- the expected opaque type
Expand All @@ -46,7 +46,7 @@ LL | define3(42)
found type `{integer}`

error[E0658]: type alias impl trait is not permitted here
--> $DIR/feature-gate-type_alias_impl_trait.rs:33:12
--> $DIR/feature-gate-type_alias_impl_trait.rs:34:12
|
LL | let y: Foo4 = 42;
| ^^^^
Expand All @@ -60,19 +60,30 @@ error: could not find defining uses
LL | type Foo = impl Debug;
| ^^^^^^^^^^

error: type alias impl traits are not allowed as field types in structs
--> $DIR/feature-gate-type_alias_impl_trait.rs:8:1
|
LL | type Foo = impl Debug;
| ---------------------- type alias defined here
...
LL | struct Bar(Foo);
| ^^^^^^^^^^^---^^
| |
| this field contains a type alias impl trait

error: could not find defining uses
--> $DIR/feature-gate-type_alias_impl_trait.rs:19:13
--> $DIR/feature-gate-type_alias_impl_trait.rs:20:13
|
LL | type Foo3 = impl Debug;
| ^^^^^^^^^^

error: could not find defining uses
--> $DIR/feature-gate-type_alias_impl_trait.rs:29:13
--> $DIR/feature-gate-type_alias_impl_trait.rs:30:13
|
LL | type Foo4 = impl Debug;
| ^^^^^^^^^^

error: aborting due to 8 previous errors
error: aborting due to 9 previous errors

Some errors have detailed explanations: E0308, E0658.
For more information about an error, try `rustc --explain E0308`.
42 changes: 42 additions & 0 deletions src/test/ui/impl-trait/reject-opaque_types-in-fields.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#![feature(min_type_alias_impl_trait)]

type ImplCopy = impl Copy;
//~^ ERROR could not find defining uses

enum Wrapper {
//~^ ERROR type alias impl traits are not allowed as field types in enums
First(ImplCopy),
Second
}

type X = impl Iterator<Item = u64> + Unpin;
//~^ ERROR could not find defining uses

struct Foo(X);
//~^ ERROR type alias impl traits are not allowed as field types in structs

impl Foo {
fn new(z: Vec<u64>) -> Self {
Foo(z.into_iter())
//~^ ERROR mismatched types
}
}

struct Bar {a : X}
//~^ ERROR type alias impl traits are not allowed as field types in structs

impl Bar {
fn new(z: Vec<u64>) -> Self {
Bar {a: z.into_iter() }
//~^ ERROR mismatched types
}
}

union MyUnion {
//~^ ERROR type alias impl traits are not allowed as field types in unions
a: X,
//~^ ERROR unions may not contain fields that need dropping
}


fn main() {}
102 changes: 102 additions & 0 deletions src/test/ui/impl-trait/reject-opaque_types-in-fields.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
error[E0308]: mismatched types
--> $DIR/reject-opaque_types-in-fields.rs:20:13
|
LL | type X = impl Iterator<Item = u64> + Unpin;
| --------------------------------- the expected opaque type
...
LL | Foo(z.into_iter())
| ^^^^^^^^^^^^^ expected opaque type, found struct `std::vec::IntoIter`
|
= note: expected opaque type `impl Iterator+Unpin`
found struct `std::vec::IntoIter<u64>`

error[E0308]: mismatched types
--> $DIR/reject-opaque_types-in-fields.rs:30:13
|
LL | type X = impl Iterator<Item = u64> + Unpin;
| --------------------------------- the expected opaque type
...
LL | Bar {a: z.into_iter() }
| ^^^^^^^^^^^^^ expected opaque type, found struct `std::vec::IntoIter`
|
= note: expected opaque type `impl Iterator+Unpin`
found struct `std::vec::IntoIter<u64>`

error: could not find defining uses
--> $DIR/reject-opaque_types-in-fields.rs:3:17
|
LL | type ImplCopy = impl Copy;
| ^^^^^^^^^

error: type alias impl traits are not allowed as field types in enums
--> $DIR/reject-opaque_types-in-fields.rs:6:1
|
LL | type ImplCopy = impl Copy;
| -------------------------- type alias defined here
...
LL | / enum Wrapper {
LL | |
LL | | First(ImplCopy),
| | -------- this field contains a type alias impl trait
LL | | Second
LL | | }
| |_^

error: could not find defining uses
--> $DIR/reject-opaque_types-in-fields.rs:12:10
|
LL | type X = impl Iterator<Item = u64> + Unpin;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: type alias impl traits are not allowed as field types in structs
--> $DIR/reject-opaque_types-in-fields.rs:15:1
|
LL | type X = impl Iterator<Item = u64> + Unpin;
| ------------------------------------------- type alias defined here
...
LL | struct Foo(X);
| ^^^^^^^^^^^-^^
| |
| this field contains a type alias impl trait

error: type alias impl traits are not allowed as field types in structs
--> $DIR/reject-opaque_types-in-fields.rs:25:1
|
LL | type X = impl Iterator<Item = u64> + Unpin;
| ------------------------------------------- type alias defined here
...
LL | struct Bar {a : X}
| ^^^^^^^^^^^^-----^
| |
| this field contains a type alias impl trait
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be worthwhile to put the name of the type alias in this message, if the alias is part of some larger nested type then identifying it might be helpful.

e.g. this field contains a type alias impl trait: `X`


error: type alias impl traits are not allowed as field types in unions
--> $DIR/reject-opaque_types-in-fields.rs:35:1
|
LL | type X = impl Iterator<Item = u64> + Unpin;
| ------------------------------------------- type alias defined here
...
LL | / union MyUnion {
LL | |
LL | | a: X,
| | ---- this field contains a type alias impl trait
LL | |
LL | | }
| |_^

error[E0740]: unions may not contain fields that need dropping
--> $DIR/reject-opaque_types-in-fields.rs:37:3
|
LL | a: X,
| ^^^^
|
note: `std::mem::ManuallyDrop` can be used to wrap the type
--> $DIR/reject-opaque_types-in-fields.rs:37:3
|
LL | a: X,
| ^^^^

error: aborting due to 9 previous errors

Some errors have detailed explanations: E0308, E0740.
For more information about an error, try `rustc --explain E0308`.
Loading