Rollup merge of #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
This commit is contained in:
commit
8662946cee
@ -1754,17 +1754,19 @@ bitflags! {
|
||||
pub struct AdtFlags: u32 {
|
||||
const NO_ADT_FLAGS = 0;
|
||||
const IS_ENUM = 1 << 0;
|
||||
const IS_PHANTOM_DATA = 1 << 1;
|
||||
const IS_FUNDAMENTAL = 1 << 2;
|
||||
const IS_UNION = 1 << 3;
|
||||
const IS_BOX = 1 << 4;
|
||||
const IS_UNION = 1 << 1;
|
||||
const IS_STRUCT = 1 << 2;
|
||||
const HAS_CTOR = 1 << 3;
|
||||
const IS_PHANTOM_DATA = 1 << 4;
|
||||
const IS_FUNDAMENTAL = 1 << 5;
|
||||
const IS_BOX = 1 << 6;
|
||||
/// Indicates whether the type is an `Arc`.
|
||||
const IS_ARC = 1 << 5;
|
||||
const IS_ARC = 1 << 7;
|
||||
/// Indicates whether the type is an `Rc`.
|
||||
const IS_RC = 1 << 6;
|
||||
const IS_RC = 1 << 8;
|
||||
/// Indicates whether the variant list of this ADT is `#[non_exhaustive]`.
|
||||
/// (i.e., this flag is never set unless this ADT is an enum).
|
||||
const IS_VARIANT_LIST_NON_EXHAUSTIVE = 1 << 7;
|
||||
const IS_VARIANT_LIST_NON_EXHAUSTIVE = 1 << 9;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2079,31 +2081,43 @@ impl<'a, 'gcx, 'tcx> AdtDef {
|
||||
repr: ReprOptions) -> Self {
|
||||
debug!("AdtDef::new({:?}, {:?}, {:?}, {:?})", did, kind, variants, repr);
|
||||
let mut flags = AdtFlags::NO_ADT_FLAGS;
|
||||
let attrs = tcx.get_attrs(did);
|
||||
if attr::contains_name(&attrs, "fundamental") {
|
||||
flags = flags | AdtFlags::IS_FUNDAMENTAL;
|
||||
}
|
||||
if Some(did) == tcx.lang_items().phantom_data() {
|
||||
flags = flags | AdtFlags::IS_PHANTOM_DATA;
|
||||
}
|
||||
if Some(did) == tcx.lang_items().owned_box() {
|
||||
flags = flags | AdtFlags::IS_BOX;
|
||||
}
|
||||
if Some(did) == tcx.lang_items().arc() {
|
||||
flags = flags | AdtFlags::IS_ARC;
|
||||
}
|
||||
if Some(did) == tcx.lang_items().rc() {
|
||||
flags = flags | AdtFlags::IS_RC;
|
||||
}
|
||||
|
||||
if kind == AdtKind::Enum && tcx.has_attr(did, "non_exhaustive") {
|
||||
debug!("found non-exhaustive variant list for {:?}", did);
|
||||
flags = flags | AdtFlags::IS_VARIANT_LIST_NON_EXHAUSTIVE;
|
||||
}
|
||||
match kind {
|
||||
AdtKind::Enum => flags = flags | AdtFlags::IS_ENUM,
|
||||
AdtKind::Union => flags = flags | AdtFlags::IS_UNION,
|
||||
AdtKind::Struct => {}
|
||||
flags |= match kind {
|
||||
AdtKind::Enum => AdtFlags::IS_ENUM,
|
||||
AdtKind::Union => AdtFlags::IS_UNION,
|
||||
AdtKind::Struct => AdtFlags::IS_STRUCT,
|
||||
};
|
||||
|
||||
if let AdtKind::Struct = kind {
|
||||
let variant_def = &variants[VariantIdx::new(0)];
|
||||
let def_key = tcx.def_key(variant_def.did);
|
||||
match def_key.disambiguated_data.data {
|
||||
DefPathData::StructCtor => flags |= AdtFlags::HAS_CTOR,
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
let attrs = tcx.get_attrs(did);
|
||||
if attr::contains_name(&attrs, "fundamental") {
|
||||
flags |= AdtFlags::IS_FUNDAMENTAL;
|
||||
}
|
||||
if Some(did) == tcx.lang_items().phantom_data() {
|
||||
flags |= AdtFlags::IS_PHANTOM_DATA;
|
||||
}
|
||||
if Some(did) == tcx.lang_items().owned_box() {
|
||||
flags |= AdtFlags::IS_BOX;
|
||||
}
|
||||
if Some(did) == tcx.lang_items().arc() {
|
||||
flags |= AdtFlags::IS_ARC;
|
||||
}
|
||||
if Some(did) == tcx.lang_items().rc() {
|
||||
flags |= AdtFlags::IS_RC;
|
||||
}
|
||||
|
||||
AdtDef {
|
||||
did,
|
||||
variants,
|
||||
@ -2114,25 +2128,25 @@ impl<'a, 'gcx, 'tcx> AdtDef {
|
||||
|
||||
#[inline]
|
||||
pub fn is_struct(&self) -> bool {
|
||||
!self.is_union() && !self.is_enum()
|
||||
self.flags.contains(AdtFlags::IS_STRUCT)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_union(&self) -> bool {
|
||||
self.flags.intersects(AdtFlags::IS_UNION)
|
||||
self.flags.contains(AdtFlags::IS_UNION)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_enum(&self) -> bool {
|
||||
self.flags.intersects(AdtFlags::IS_ENUM)
|
||||
self.flags.contains(AdtFlags::IS_ENUM)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_variant_list_non_exhaustive(&self) -> bool {
|
||||
self.flags.intersects(AdtFlags::IS_VARIANT_LIST_NON_EXHAUSTIVE)
|
||||
self.flags.contains(AdtFlags::IS_VARIANT_LIST_NON_EXHAUSTIVE)
|
||||
}
|
||||
|
||||
/// Returns the kind of the ADT - Struct or Enum.
|
||||
/// Returns the kind of the ADT.
|
||||
#[inline]
|
||||
pub fn adt_kind(&self) -> AdtKind {
|
||||
if self.is_enum() {
|
||||
@ -2161,33 +2175,39 @@ impl<'a, 'gcx, 'tcx> AdtDef {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns whether this type is #[fundamental] for the purposes
|
||||
/// If this function returns `true`, it implies that `is_struct` must return `true`.
|
||||
#[inline]
|
||||
pub fn has_ctor(&self) -> bool {
|
||||
self.flags.contains(AdtFlags::HAS_CTOR)
|
||||
}
|
||||
|
||||
/// Returns whether this type is `#[fundamental]` for the purposes
|
||||
/// of coherence checking.
|
||||
#[inline]
|
||||
pub fn is_fundamental(&self) -> bool {
|
||||
self.flags.intersects(AdtFlags::IS_FUNDAMENTAL)
|
||||
self.flags.contains(AdtFlags::IS_FUNDAMENTAL)
|
||||
}
|
||||
|
||||
/// Returns `true` if this is PhantomData<T>.
|
||||
#[inline]
|
||||
pub fn is_phantom_data(&self) -> bool {
|
||||
self.flags.intersects(AdtFlags::IS_PHANTOM_DATA)
|
||||
self.flags.contains(AdtFlags::IS_PHANTOM_DATA)
|
||||
}
|
||||
|
||||
/// Returns `true` if this is `Arc<T>`.
|
||||
pub fn is_arc(&self) -> bool {
|
||||
self.flags.intersects(AdtFlags::IS_ARC)
|
||||
self.flags.contains(AdtFlags::IS_ARC)
|
||||
}
|
||||
|
||||
/// Returns `true` if this is `Rc<T>`.
|
||||
pub fn is_rc(&self) -> bool {
|
||||
self.flags.intersects(AdtFlags::IS_RC)
|
||||
self.flags.contains(AdtFlags::IS_RC)
|
||||
}
|
||||
|
||||
/// Returns `true` if this is Box<T>.
|
||||
#[inline]
|
||||
pub fn is_box(&self) -> bool {
|
||||
self.flags.intersects(AdtFlags::IS_BOX)
|
||||
self.flags.contains(AdtFlags::IS_BOX)
|
||||
}
|
||||
|
||||
/// Returns whether this type has a destructor.
|
||||
|
@ -280,7 +280,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
Def::Local(id) | Def::Upvar(id, ..) => {
|
||||
Some(self.tcx.hir().span(id))
|
||||
}
|
||||
_ => self.tcx.hir().span_if_local(def.def_id())
|
||||
_ => def.opt_def_id().and_then(|did| self.tcx.hir().span_if_local(did)),
|
||||
};
|
||||
if let Some(span) = def_span {
|
||||
let label = match (unit_variant, inner_callee_path) {
|
||||
|
@ -95,7 +95,7 @@ mod op;
|
||||
|
||||
use astconv::AstConv;
|
||||
use errors::{Applicability, DiagnosticBuilder, DiagnosticId};
|
||||
use rustc::hir::{self, GenericArg, Node, ItemKind, PatKind};
|
||||
use rustc::hir::{self, GenericArg, ItemKind, Node, PatKind};
|
||||
use rustc::hir::def::Def;
|
||||
use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
|
||||
use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
|
||||
@ -113,7 +113,8 @@ use rustc::mir::interpret::{ConstValue, GlobalId};
|
||||
use rustc::ty::subst::{CanonicalUserSubsts, UnpackedKind, Subst, Substs,
|
||||
UserSelfTy, UserSubsts};
|
||||
use rustc::traits::{self, ObligationCause, ObligationCauseCode, TraitEngine};
|
||||
use rustc::ty::{self, Ty, TyCtxt, GenericParamDefKind, Visibility, ToPredicate, RegionKind};
|
||||
use rustc::ty::{self, AdtKind, Ty, TyCtxt, GenericParamDefKind, Visibility, ToPredicate,
|
||||
RegionKind};
|
||||
use rustc::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability};
|
||||
use rustc::ty::fold::TypeFoldable;
|
||||
use rustc::ty::query::Providers;
|
||||
@ -3217,8 +3218,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
return_expr_ty);
|
||||
}
|
||||
|
||||
// A generic function for checking the then and else in an if
|
||||
// or if-else.
|
||||
// A generic function for checking the 'then' and 'else' clauses in an 'if'
|
||||
// or 'if-else' expression.
|
||||
fn check_then_else(&self,
|
||||
cond_expr: &'gcx hir::Expr,
|
||||
then_expr: &'gcx hir::Expr,
|
||||
@ -3544,7 +3545,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
// We don't look at stability attributes on
|
||||
// struct-like enums (yet...), but it's definitely not
|
||||
// a bug to have constructed one.
|
||||
if adt_kind != ty::AdtKind::Enum {
|
||||
if adt_kind != AdtKind::Enum {
|
||||
tcx.check_stability(v_field.did, Some(expr_id), field.span);
|
||||
}
|
||||
|
||||
@ -5156,26 +5157,48 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
}).unwrap_or(false);
|
||||
|
||||
let mut new_def = def;
|
||||
let (def_id, ty) = if let Def::SelfCtor(impl_def_id) = def {
|
||||
let ty = self.impl_self_ty(span, impl_def_id).ty;
|
||||
let (def_id, ty) = match def {
|
||||
Def::SelfCtor(impl_def_id) => {
|
||||
let ty = self.impl_self_ty(span, impl_def_id).ty;
|
||||
let adt_def = ty.ty_adt_def();
|
||||
|
||||
match ty.ty_adt_def() {
|
||||
Some(adt_def) if adt_def.is_struct() => {
|
||||
let variant = adt_def.non_enum_variant();
|
||||
new_def = Def::StructCtor(variant.did, variant.ctor_kind);
|
||||
(variant.did, self.tcx.type_of(variant.did))
|
||||
}
|
||||
_ => {
|
||||
(impl_def_id, self.tcx.types.err)
|
||||
match adt_def {
|
||||
Some(adt_def) if adt_def.has_ctor() => {
|
||||
let variant = adt_def.non_enum_variant();
|
||||
new_def = Def::StructCtor(variant.did, variant.ctor_kind);
|
||||
(variant.did, self.tcx.type_of(variant.did))
|
||||
}
|
||||
_ => {
|
||||
let mut err = self.tcx.sess.struct_span_err(span,
|
||||
"the `Self` constructor can only be used with tuple or unit structs");
|
||||
if let Some(adt_def) = adt_def {
|
||||
match adt_def.adt_kind() {
|
||||
AdtKind::Enum => {
|
||||
err.note("did you mean to use one of the enum's variants?");
|
||||
},
|
||||
AdtKind::Struct |
|
||||
AdtKind::Union => {
|
||||
err.span_label(
|
||||
span,
|
||||
format!("did you mean `Self {{ /* fields */ }}`?"),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
err.emit();
|
||||
|
||||
(impl_def_id, self.tcx.types.err)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let def_id = def.def_id();
|
||||
_ => {
|
||||
let def_id = def.def_id();
|
||||
|
||||
// The things we are substituting into the type should not contain
|
||||
// escaping late-bound regions, and nor should the base type scheme.
|
||||
let ty = self.tcx.type_of(def_id);
|
||||
(def_id, ty)
|
||||
// The things we are substituting into the type should not contain
|
||||
// escaping late-bound regions, and nor should the base type scheme.
|
||||
let ty = self.tcx.type_of(def_id);
|
||||
(def_id, ty)
|
||||
}
|
||||
};
|
||||
|
||||
let substs = AstConv::create_substs_for_generic_args(
|
||||
|
23
src/test/ui/issues/issue-56199.rs
Normal file
23
src/test/ui/issues/issue-56199.rs
Normal file
@ -0,0 +1,23 @@
|
||||
|
||||
enum Foo {}
|
||||
struct Bar {}
|
||||
|
||||
impl Foo {
|
||||
fn foo() {
|
||||
let _ = Self;
|
||||
//~^ ERROR the `Self` constructor can only be used with tuple or unit structs
|
||||
let _ = Self();
|
||||
//~^ ERROR the `Self` constructor can only be used with tuple or unit structs
|
||||
}
|
||||
}
|
||||
|
||||
impl Bar {
|
||||
fn bar() {
|
||||
let _ = Self;
|
||||
//~^ ERROR the `Self` constructor can only be used with tuple or unit structs
|
||||
let _ = Self();
|
||||
//~^ ERROR the `Self` constructor can only be used with tuple or unit structs
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
30
src/test/ui/issues/issue-56199.stderr
Normal file
30
src/test/ui/issues/issue-56199.stderr
Normal file
@ -0,0 +1,30 @@
|
||||
error: the `Self` constructor can only be used with tuple or unit structs
|
||||
--> $DIR/issue-56199.rs:7:17
|
||||
|
|
||||
LL | let _ = Self;
|
||||
| ^^^^
|
||||
|
|
||||
= note: did you mean to use one of the enum's variants?
|
||||
|
||||
error: the `Self` constructor can only be used with tuple or unit structs
|
||||
--> $DIR/issue-56199.rs:9:17
|
||||
|
|
||||
LL | let _ = Self();
|
||||
| ^^^^
|
||||
|
|
||||
= note: did you mean to use one of the enum's variants?
|
||||
|
||||
error: the `Self` constructor can only be used with tuple or unit structs
|
||||
--> $DIR/issue-56199.rs:16:17
|
||||
|
|
||||
LL | let _ = Self;
|
||||
| ^^^^ did you mean `Self { /* fields */ }`?
|
||||
|
||||
error: the `Self` constructor can only be used with tuple or unit structs
|
||||
--> $DIR/issue-56199.rs:18:17
|
||||
|
|
||||
LL | let _ = Self();
|
||||
| ^^^^ did you mean `Self { /* fields */ }`?
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
10
src/test/ui/issues/issue-56835.rs
Normal file
10
src/test/ui/issues/issue-56835.rs
Normal file
@ -0,0 +1,10 @@
|
||||
|
||||
pub struct Foo {}
|
||||
|
||||
impl Foo {
|
||||
fn bar(Self(foo): Self) {}
|
||||
//~^ ERROR the `Self` constructor can only be used with tuple or unit structs
|
||||
//~^^ ERROR expected tuple struct/variant, found self constructor `Self` [E0164]
|
||||
}
|
||||
|
||||
fn main() {}
|
15
src/test/ui/issues/issue-56835.stderr
Normal file
15
src/test/ui/issues/issue-56835.stderr
Normal file
@ -0,0 +1,15 @@
|
||||
error: the `Self` constructor can only be used with tuple or unit structs
|
||||
--> $DIR/issue-56835.rs:5:12
|
||||
|
|
||||
LL | fn bar(Self(foo): Self) {}
|
||||
| ^^^^^^^^^ did you mean `Self { /* fields */ }`?
|
||||
|
||||
error[E0164]: expected tuple struct/variant, found self constructor `Self`
|
||||
--> $DIR/issue-56835.rs:5:12
|
||||
|
|
||||
LL | fn bar(Self(foo): Self) {}
|
||||
| ^^^^^^^^^ not a tuple variant or struct
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0164`.
|
Loading…
x
Reference in New Issue
Block a user