Skip to content

Commit 8662946

Browse files
authored
Rollup merge of rust-lang#56850 - alexreg:fix-self-in-typedefs, r=petrochenkov
Fixed issue with using `Self` ctor in typedefs Added two regression tests. This is definitely suitable for a beta backport. CC @Centril
2 parents 75d4eda + 0211856 commit 8662946

File tree

7 files changed

+176
-55
lines changed

7 files changed

+176
-55
lines changed

src/librustc/ty/mod.rs

Lines changed: 52 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1754,17 +1754,19 @@ bitflags! {
17541754
pub struct AdtFlags: u32 {
17551755
const NO_ADT_FLAGS = 0;
17561756
const IS_ENUM = 1 << 0;
1757-
const IS_PHANTOM_DATA = 1 << 1;
1758-
const IS_FUNDAMENTAL = 1 << 2;
1759-
const IS_UNION = 1 << 3;
1760-
const IS_BOX = 1 << 4;
1757+
const IS_UNION = 1 << 1;
1758+
const IS_STRUCT = 1 << 2;
1759+
const HAS_CTOR = 1 << 3;
1760+
const IS_PHANTOM_DATA = 1 << 4;
1761+
const IS_FUNDAMENTAL = 1 << 5;
1762+
const IS_BOX = 1 << 6;
17611763
/// Indicates whether the type is an `Arc`.
1762-
const IS_ARC = 1 << 5;
1764+
const IS_ARC = 1 << 7;
17631765
/// Indicates whether the type is an `Rc`.
1764-
const IS_RC = 1 << 6;
1766+
const IS_RC = 1 << 8;
17651767
/// Indicates whether the variant list of this ADT is `#[non_exhaustive]`.
17661768
/// (i.e., this flag is never set unless this ADT is an enum).
1767-
const IS_VARIANT_LIST_NON_EXHAUSTIVE = 1 << 7;
1769+
const IS_VARIANT_LIST_NON_EXHAUSTIVE = 1 << 9;
17681770
}
17691771
}
17701772

@@ -2079,31 +2081,43 @@ impl<'a, 'gcx, 'tcx> AdtDef {
20792081
repr: ReprOptions) -> Self {
20802082
debug!("AdtDef::new({:?}, {:?}, {:?}, {:?})", did, kind, variants, repr);
20812083
let mut flags = AdtFlags::NO_ADT_FLAGS;
2084+
2085+
if kind == AdtKind::Enum && tcx.has_attr(did, "non_exhaustive") {
2086+
debug!("found non-exhaustive variant list for {:?}", did);
2087+
flags = flags | AdtFlags::IS_VARIANT_LIST_NON_EXHAUSTIVE;
2088+
}
2089+
flags |= match kind {
2090+
AdtKind::Enum => AdtFlags::IS_ENUM,
2091+
AdtKind::Union => AdtFlags::IS_UNION,
2092+
AdtKind::Struct => AdtFlags::IS_STRUCT,
2093+
};
2094+
2095+
if let AdtKind::Struct = kind {
2096+
let variant_def = &variants[VariantIdx::new(0)];
2097+
let def_key = tcx.def_key(variant_def.did);
2098+
match def_key.disambiguated_data.data {
2099+
DefPathData::StructCtor => flags |= AdtFlags::HAS_CTOR,
2100+
_ => (),
2101+
}
2102+
}
2103+
20822104
let attrs = tcx.get_attrs(did);
20832105
if attr::contains_name(&attrs, "fundamental") {
2084-
flags = flags | AdtFlags::IS_FUNDAMENTAL;
2106+
flags |= AdtFlags::IS_FUNDAMENTAL;
20852107
}
20862108
if Some(did) == tcx.lang_items().phantom_data() {
2087-
flags = flags | AdtFlags::IS_PHANTOM_DATA;
2109+
flags |= AdtFlags::IS_PHANTOM_DATA;
20882110
}
20892111
if Some(did) == tcx.lang_items().owned_box() {
2090-
flags = flags | AdtFlags::IS_BOX;
2112+
flags |= AdtFlags::IS_BOX;
20912113
}
20922114
if Some(did) == tcx.lang_items().arc() {
2093-
flags = flags | AdtFlags::IS_ARC;
2115+
flags |= AdtFlags::IS_ARC;
20942116
}
20952117
if Some(did) == tcx.lang_items().rc() {
2096-
flags = flags | AdtFlags::IS_RC;
2097-
}
2098-
if kind == AdtKind::Enum && tcx.has_attr(did, "non_exhaustive") {
2099-
debug!("found non-exhaustive variant list for {:?}", did);
2100-
flags = flags | AdtFlags::IS_VARIANT_LIST_NON_EXHAUSTIVE;
2101-
}
2102-
match kind {
2103-
AdtKind::Enum => flags = flags | AdtFlags::IS_ENUM,
2104-
AdtKind::Union => flags = flags | AdtFlags::IS_UNION,
2105-
AdtKind::Struct => {}
2118+
flags |= AdtFlags::IS_RC;
21062119
}
2120+
21072121
AdtDef {
21082122
did,
21092123
variants,
@@ -2114,25 +2128,25 @@ impl<'a, 'gcx, 'tcx> AdtDef {
21142128

21152129
#[inline]
21162130
pub fn is_struct(&self) -> bool {
2117-
!self.is_union() && !self.is_enum()
2131+
self.flags.contains(AdtFlags::IS_STRUCT)
21182132
}
21192133

21202134
#[inline]
21212135
pub fn is_union(&self) -> bool {
2122-
self.flags.intersects(AdtFlags::IS_UNION)
2136+
self.flags.contains(AdtFlags::IS_UNION)
21232137
}
21242138

21252139
#[inline]
21262140
pub fn is_enum(&self) -> bool {
2127-
self.flags.intersects(AdtFlags::IS_ENUM)
2141+
self.flags.contains(AdtFlags::IS_ENUM)
21282142
}
21292143

21302144
#[inline]
21312145
pub fn is_variant_list_non_exhaustive(&self) -> bool {
2132-
self.flags.intersects(AdtFlags::IS_VARIANT_LIST_NON_EXHAUSTIVE)
2146+
self.flags.contains(AdtFlags::IS_VARIANT_LIST_NON_EXHAUSTIVE)
21332147
}
21342148

2135-
/// Returns the kind of the ADT - Struct or Enum.
2149+
/// Returns the kind of the ADT.
21362150
#[inline]
21372151
pub fn adt_kind(&self) -> AdtKind {
21382152
if self.is_enum() {
@@ -2161,33 +2175,39 @@ impl<'a, 'gcx, 'tcx> AdtDef {
21612175
}
21622176
}
21632177

2164-
/// Returns whether this type is #[fundamental] for the purposes
2178+
/// If this function returns `true`, it implies that `is_struct` must return `true`.
2179+
#[inline]
2180+
pub fn has_ctor(&self) -> bool {
2181+
self.flags.contains(AdtFlags::HAS_CTOR)
2182+
}
2183+
2184+
/// Returns whether this type is `#[fundamental]` for the purposes
21652185
/// of coherence checking.
21662186
#[inline]
21672187
pub fn is_fundamental(&self) -> bool {
2168-
self.flags.intersects(AdtFlags::IS_FUNDAMENTAL)
2188+
self.flags.contains(AdtFlags::IS_FUNDAMENTAL)
21692189
}
21702190

21712191
/// Returns `true` if this is PhantomData<T>.
21722192
#[inline]
21732193
pub fn is_phantom_data(&self) -> bool {
2174-
self.flags.intersects(AdtFlags::IS_PHANTOM_DATA)
2194+
self.flags.contains(AdtFlags::IS_PHANTOM_DATA)
21752195
}
21762196

21772197
/// Returns `true` if this is `Arc<T>`.
21782198
pub fn is_arc(&self) -> bool {
2179-
self.flags.intersects(AdtFlags::IS_ARC)
2199+
self.flags.contains(AdtFlags::IS_ARC)
21802200
}
21812201

21822202
/// Returns `true` if this is `Rc<T>`.
21832203
pub fn is_rc(&self) -> bool {
2184-
self.flags.intersects(AdtFlags::IS_RC)
2204+
self.flags.contains(AdtFlags::IS_RC)
21852205
}
21862206

21872207
/// Returns `true` if this is Box<T>.
21882208
#[inline]
21892209
pub fn is_box(&self) -> bool {
2190-
self.flags.intersects(AdtFlags::IS_BOX)
2210+
self.flags.contains(AdtFlags::IS_BOX)
21912211
}
21922212

21932213
/// Returns whether this type has a destructor.

src/librustc_typeck/check/callee.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
280280
Def::Local(id) | Def::Upvar(id, ..) => {
281281
Some(self.tcx.hir().span(id))
282282
}
283-
_ => self.tcx.hir().span_if_local(def.def_id())
283+
_ => def.opt_def_id().and_then(|did| self.tcx.hir().span_if_local(did)),
284284
};
285285
if let Some(span) = def_span {
286286
let label = match (unit_variant, inner_callee_path) {

src/librustc_typeck/check/mod.rs

Lines changed: 45 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ mod op;
9595

9696
use astconv::AstConv;
9797
use errors::{Applicability, DiagnosticBuilder, DiagnosticId};
98-
use rustc::hir::{self, GenericArg, Node, ItemKind, PatKind};
98+
use rustc::hir::{self, GenericArg, ItemKind, Node, PatKind};
9999
use rustc::hir::def::Def;
100100
use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
101101
use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
@@ -113,7 +113,8 @@ use rustc::mir::interpret::{ConstValue, GlobalId};
113113
use rustc::ty::subst::{CanonicalUserSubsts, UnpackedKind, Subst, Substs,
114114
UserSelfTy, UserSubsts};
115115
use rustc::traits::{self, ObligationCause, ObligationCauseCode, TraitEngine};
116-
use rustc::ty::{self, Ty, TyCtxt, GenericParamDefKind, Visibility, ToPredicate, RegionKind};
116+
use rustc::ty::{self, AdtKind, Ty, TyCtxt, GenericParamDefKind, Visibility, ToPredicate,
117+
RegionKind};
117118
use rustc::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability};
118119
use rustc::ty::fold::TypeFoldable;
119120
use rustc::ty::query::Providers;
@@ -3217,8 +3218,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
32173218
return_expr_ty);
32183219
}
32193220

3220-
// A generic function for checking the then and else in an if
3221-
// or if-else.
3221+
// A generic function for checking the 'then' and 'else' clauses in an 'if'
3222+
// or 'if-else' expression.
32223223
fn check_then_else(&self,
32233224
cond_expr: &'gcx hir::Expr,
32243225
then_expr: &'gcx hir::Expr,
@@ -3544,7 +3545,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
35443545
// We don't look at stability attributes on
35453546
// struct-like enums (yet...), but it's definitely not
35463547
// a bug to have constructed one.
3547-
if adt_kind != ty::AdtKind::Enum {
3548+
if adt_kind != AdtKind::Enum {
35483549
tcx.check_stability(v_field.did, Some(expr_id), field.span);
35493550
}
35503551

@@ -5156,26 +5157,48 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
51565157
}).unwrap_or(false);
51575158

51585159
let mut new_def = def;
5159-
let (def_id, ty) = if let Def::SelfCtor(impl_def_id) = def {
5160-
let ty = self.impl_self_ty(span, impl_def_id).ty;
5161-
5162-
match ty.ty_adt_def() {
5163-
Some(adt_def) if adt_def.is_struct() => {
5164-
let variant = adt_def.non_enum_variant();
5165-
new_def = Def::StructCtor(variant.did, variant.ctor_kind);
5166-
(variant.did, self.tcx.type_of(variant.did))
5167-
}
5168-
_ => {
5169-
(impl_def_id, self.tcx.types.err)
5160+
let (def_id, ty) = match def {
5161+
Def::SelfCtor(impl_def_id) => {
5162+
let ty = self.impl_self_ty(span, impl_def_id).ty;
5163+
let adt_def = ty.ty_adt_def();
5164+
5165+
match adt_def {
5166+
Some(adt_def) if adt_def.has_ctor() => {
5167+
let variant = adt_def.non_enum_variant();
5168+
new_def = Def::StructCtor(variant.did, variant.ctor_kind);
5169+
(variant.did, self.tcx.type_of(variant.did))
5170+
}
5171+
_ => {
5172+
let mut err = self.tcx.sess.struct_span_err(span,
5173+
"the `Self` constructor can only be used with tuple or unit structs");
5174+
if let Some(adt_def) = adt_def {
5175+
match adt_def.adt_kind() {
5176+
AdtKind::Enum => {
5177+
err.note("did you mean to use one of the enum's variants?");
5178+
},
5179+
AdtKind::Struct |
5180+
AdtKind::Union => {
5181+
err.span_label(
5182+
span,
5183+
format!("did you mean `Self {{ /* fields */ }}`?"),
5184+
);
5185+
}
5186+
}
5187+
}
5188+
err.emit();
5189+
5190+
(impl_def_id, self.tcx.types.err)
5191+
}
51705192
}
51715193
}
5172-
} else {
5173-
let def_id = def.def_id();
5194+
_ => {
5195+
let def_id = def.def_id();
51745196

5175-
// The things we are substituting into the type should not contain
5176-
// escaping late-bound regions, and nor should the base type scheme.
5177-
let ty = self.tcx.type_of(def_id);
5178-
(def_id, ty)
5197+
// The things we are substituting into the type should not contain
5198+
// escaping late-bound regions, and nor should the base type scheme.
5199+
let ty = self.tcx.type_of(def_id);
5200+
(def_id, ty)
5201+
}
51795202
};
51805203

51815204
let substs = AstConv::create_substs_for_generic_args(

src/test/ui/issues/issue-56199.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
2+
enum Foo {}
3+
struct Bar {}
4+
5+
impl Foo {
6+
fn foo() {
7+
let _ = Self;
8+
//~^ ERROR the `Self` constructor can only be used with tuple or unit structs
9+
let _ = Self();
10+
//~^ ERROR the `Self` constructor can only be used with tuple or unit structs
11+
}
12+
}
13+
14+
impl Bar {
15+
fn bar() {
16+
let _ = Self;
17+
//~^ ERROR the `Self` constructor can only be used with tuple or unit structs
18+
let _ = Self();
19+
//~^ ERROR the `Self` constructor can only be used with tuple or unit structs
20+
}
21+
}
22+
23+
fn main() {}

src/test/ui/issues/issue-56199.stderr

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
error: the `Self` constructor can only be used with tuple or unit structs
2+
--> $DIR/issue-56199.rs:7:17
3+
|
4+
LL | let _ = Self;
5+
| ^^^^
6+
|
7+
= note: did you mean to use one of the enum's variants?
8+
9+
error: the `Self` constructor can only be used with tuple or unit structs
10+
--> $DIR/issue-56199.rs:9:17
11+
|
12+
LL | let _ = Self();
13+
| ^^^^
14+
|
15+
= note: did you mean to use one of the enum's variants?
16+
17+
error: the `Self` constructor can only be used with tuple or unit structs
18+
--> $DIR/issue-56199.rs:16:17
19+
|
20+
LL | let _ = Self;
21+
| ^^^^ did you mean `Self { /* fields */ }`?
22+
23+
error: the `Self` constructor can only be used with tuple or unit structs
24+
--> $DIR/issue-56199.rs:18:17
25+
|
26+
LL | let _ = Self();
27+
| ^^^^ did you mean `Self { /* fields */ }`?
28+
29+
error: aborting due to 4 previous errors
30+

src/test/ui/issues/issue-56835.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
2+
pub struct Foo {}
3+
4+
impl Foo {
5+
fn bar(Self(foo): Self) {}
6+
//~^ ERROR the `Self` constructor can only be used with tuple or unit structs
7+
//~^^ ERROR expected tuple struct/variant, found self constructor `Self` [E0164]
8+
}
9+
10+
fn main() {}

src/test/ui/issues/issue-56835.stderr

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
error: the `Self` constructor can only be used with tuple or unit structs
2+
--> $DIR/issue-56835.rs:5:12
3+
|
4+
LL | fn bar(Self(foo): Self) {}
5+
| ^^^^^^^^^ did you mean `Self { /* fields */ }`?
6+
7+
error[E0164]: expected tuple struct/variant, found self constructor `Self`
8+
--> $DIR/issue-56835.rs:5:12
9+
|
10+
LL | fn bar(Self(foo): Self) {}
11+
| ^^^^^^^^^ not a tuple variant or struct
12+
13+
error: aborting due to 2 previous errors
14+
15+
For more information about this error, try `rustc --explain E0164`.

0 commit comments

Comments
 (0)