Skip to content

Commit

Permalink
Auto merge of #53751 - F001:tuple-struct-self-ctor, r=petrochenkov,va…
Browse files Browse the repository at this point in the history
…rkor

Implement RFC 2302: tuple_struct_self_ctor

Tracking issue: #51994
  • Loading branch information
bors committed Sep 13, 2018
2 parents 90d36fb + 2157958 commit a294236
Show file tree
Hide file tree
Showing 27 changed files with 469 additions and 149 deletions.
33 changes: 33 additions & 0 deletions src/doc/unstable-book/src/language-features/self-struct-ctor.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# `self_struct_ctor`

The tracking issue for this feature is: [#51994]
[#51994]: https://github.com/rust-lang/rust/issues/51994

------------------------

The `self_struct_ctor` feature gate lets you use the special `Self`
identifier as a constructor and a pattern.

A simple example is:

```rust
#![feature(self_struct_ctor)]

struct ST(i32, i32);

impl ST {
fn new() -> Self {
ST(0, 1)
}

fn ctor() -> Self {
Self(1,2) // constructed by `Self`, it is the same as `ST(1, 2)`
}

fn pattern(self) {
match self {
Self(x, y) => println!("{} {}", x, y), // used as a pattern
}
}
}
```
5 changes: 4 additions & 1 deletion src/librustc/hir/def.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ pub enum Def {
Static(DefId, bool /* is_mutbl */),
StructCtor(DefId, CtorKind), // DefId refers to NodeId of the struct's constructor
VariantCtor(DefId, CtorKind), // DefId refers to the enum variant
SelfCtor(DefId /* impl */), // DefId refers to the impl
Method(DefId),
AssociatedConst(DefId),

Expand Down Expand Up @@ -272,7 +273,8 @@ impl Def {
Def::AssociatedTy(id) | Def::TyParam(id) | Def::Struct(id) | Def::StructCtor(id, ..) |
Def::Union(id) | Def::Trait(id) | Def::Method(id) | Def::Const(id) |
Def::AssociatedConst(id) | Def::Macro(id, ..) |
Def::Existential(id) | Def::AssociatedExistential(id) | Def::ForeignTy(id) => {
Def::Existential(id) | Def::AssociatedExistential(id) | Def::ForeignTy(id) |
Def::SelfCtor(id) => {
id
}

Expand Down Expand Up @@ -309,6 +311,7 @@ impl Def {
Def::StructCtor(.., CtorKind::Fn) => "tuple struct",
Def::StructCtor(.., CtorKind::Const) => "unit struct",
Def::StructCtor(.., CtorKind::Fictive) => bug!("impossible struct constructor"),
Def::SelfCtor(..) => "self constructor",
Def::Union(..) => "union",
Def::Trait(..) => "trait",
Def::ForeignTy(..) => "foreign type",
Expand Down
50 changes: 36 additions & 14 deletions src/librustc/hir/lowering.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ use syntax::ast;
use syntax::ast::*;
use syntax::errors;
use syntax::ext::hygiene::{Mark, SyntaxContext};
use syntax::feature_gate::{emit_feature_err, GateIssue};
use syntax::print::pprust;
use syntax::ptr::P;
use syntax::source_map::{self, respan, CompilerDesugaringKind, Spanned};
Expand Down Expand Up @@ -3429,19 +3430,24 @@ impl<'a> LoweringContext<'a> {
ParamMode::Optional,
ImplTraitContext::Disallowed,
);
self.check_self_struct_ctor_feature(&qpath);
hir::PatKind::TupleStruct(
qpath,
pats.iter().map(|x| self.lower_pat(x)).collect(),
ddpos,
)
}
PatKind::Path(ref qself, ref path) => hir::PatKind::Path(self.lower_qpath(
p.id,
qself,
path,
ParamMode::Optional,
ImplTraitContext::Disallowed,
)),
PatKind::Path(ref qself, ref path) => {
let qpath = self.lower_qpath(
p.id,
qself,
path,
ParamMode::Optional,
ImplTraitContext::Disallowed,
);
self.check_self_struct_ctor_feature(&qpath);
hir::PatKind::Path(qpath)
}
PatKind::Struct(ref path, ref fields, etc) => {
let qpath = self.lower_qpath(
p.id,
Expand Down Expand Up @@ -3828,13 +3834,17 @@ impl<'a> LoweringContext<'a> {
attrs: e.attrs.clone(),
};
}
ExprKind::Path(ref qself, ref path) => hir::ExprKind::Path(self.lower_qpath(
e.id,
qself,
path,
ParamMode::Optional,
ImplTraitContext::Disallowed,
)),
ExprKind::Path(ref qself, ref path) => {
let qpath = self.lower_qpath(
e.id,
qself,
path,
ParamMode::Optional,
ImplTraitContext::Disallowed,
);
self.check_self_struct_ctor_feature(&qpath);
hir::ExprKind::Path(qpath)
}
ExprKind::Break(opt_label, ref opt_expr) => {
let destination = if self.is_in_loop_condition && opt_label.is_none() {
hir::Destination {
Expand Down Expand Up @@ -4815,6 +4825,18 @@ impl<'a> LoweringContext<'a> {
ThinVec::new()));
P(self.expr_call(e.span, from_err, hir_vec![e]))
}

fn check_self_struct_ctor_feature(&self, qp: &hir::QPath) {
if let hir::QPath::Resolved(_, ref p) = qp {
if p.segments.len() == 1 &&
p.segments[0].ident.name == keywords::SelfType.name() &&
!self.sess.features_untracked().self_struct_ctor {
emit_feature_err(&self.sess.parse_sess, "self_struct_ctor",
p.span, GateIssue::Language,
"`Self` struct constructors are unstable");
}
}
}
}

fn body_ids(bodies: &BTreeMap<hir::BodyId, hir::Body>) -> Vec<hir::BodyId> {
Expand Down
1 change: 1 addition & 0 deletions src/librustc/ich/impls_hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1021,6 +1021,7 @@ impl_stable_hash_for!(enum hir::def::Def {
Const(def_id),
Static(def_id, is_mutbl),
StructCtor(def_id, ctor_kind),
SelfCtor(impl_def_id),
VariantCtor(def_id, ctor_kind),
Method(def_id),
AssociatedConst(def_id),
Expand Down
4 changes: 2 additions & 2 deletions src/librustc/middle/mem_categorization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -708,7 +708,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {

match def {
Def::StructCtor(..) | Def::VariantCtor(..) | Def::Const(..) |
Def::AssociatedConst(..) | Def::Fn(..) | Def::Method(..) => {
Def::AssociatedConst(..) | Def::Fn(..) | Def::Method(..) | Def::SelfCtor(..) => {
Ok(self.cat_rvalue_node(hir_id, span, expr_ty))
}

Expand Down Expand Up @@ -1288,7 +1288,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
(self.cat_downcast_if_needed(pat, cmt, def_id),
self.tcx.adt_def(enum_def).variant_with_id(def_id).fields.len())
}
Def::StructCtor(_, CtorKind::Fn) => {
Def::StructCtor(_, CtorKind::Fn) | Def::SelfCtor(..) => {
match self.pat_ty_unadjusted(&pat)?.sty {
ty::Adt(adt_def, _) => {
(cmt, adt_def.non_enum_variant().fields.len())
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/stability.rs
Original file line number Diff line number Diff line change
Expand Up @@ -783,7 +783,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
fn visit_path(&mut self, path: &'tcx hir::Path, id: hir::HirId) {
let id = self.tcx.hir.hir_to_node_id(id);
match path.def {
Def::Local(..) | Def::Upvar(..) |
Def::Local(..) | Def::Upvar(..) | Def::SelfCtor(..) |
Def::PrimTy(..) | Def::SelfTy(..) | Def::Err => {}
_ => self.tcx.check_stability(path.def.def_id(), Some(id), path.span)
}
Expand Down
3 changes: 2 additions & 1 deletion src/librustc/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2134,7 +2134,8 @@ impl<'a, 'gcx, 'tcx> AdtDef {
match def {
Def::Variant(vid) | Def::VariantCtor(vid, ..) => self.variant_with_id(vid),
Def::Struct(..) | Def::StructCtor(..) | Def::Union(..) |
Def::TyAlias(..) | Def::AssociatedTy(..) | Def::SelfTy(..) => self.non_enum_variant(),
Def::TyAlias(..) | Def::AssociatedTy(..) | Def::SelfTy(..) |
Def::SelfCtor(..) => self.non_enum_variant(),
_ => bug!("unexpected def {:?} in variant_of_def", def)
}
}
Expand Down
25 changes: 23 additions & 2 deletions src/librustc_mir/hair/cx/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,8 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
Def::VariantCtor(variant_id, CtorKind::Fn) => {
Some((adt_def, adt_def.variant_index_with_id(variant_id)))
}
Def::StructCtor(_, CtorKind::Fn) => Some((adt_def, 0)),
Def::StructCtor(_, CtorKind::Fn) |
Def::SelfCtor(..) => Some((adt_def, 0)),
_ => None,
}
})
Expand Down Expand Up @@ -759,6 +760,25 @@ fn user_annotated_ty_for_def(
sty => bug!("unexpected sty: {:?}", sty),
},

// `Self` is used in expression as a tuple struct constructor or an unit struct constructor
Def::SelfCtor(_) => {
let sty = &cx.tables().node_id_to_type(hir_id).sty;
match sty {
ty::FnDef(ref def_id, _) => {
Some(cx.tables().user_substs(hir_id)?.unchecked_map(|user_substs| {
// Here, we just pair a `DefId` with the
// `user_substs`, so no new types etc are introduced.
cx.tcx().mk_fn_def(*def_id, user_substs)
}))
}
ty::Adt(ref adt_def, _) => {
user_annotated_ty_for_adt(cx, hir_id, adt_def)
}
_ => {
bug!("unexpected sty: {:?}", sty)
}
}
}
_ =>
bug!("user_annotated_ty_for_def: unexpected def {:?} at {:?}", def, hir_id)
}
Expand Down Expand Up @@ -857,7 +877,8 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
Def::Fn(_) |
Def::Method(_) |
Def::StructCtor(_, CtorKind::Fn) |
Def::VariantCtor(_, CtorKind::Fn) => {
Def::VariantCtor(_, CtorKind::Fn) |
Def::SelfCtor(..) => {
let user_ty = user_annotated_ty_for_def(cx, expr.hir_id, &def);
ExprKind::Literal {
literal: ty::Const::zero_sized(
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_mir/hair/pattern/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -667,7 +667,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
}

Def::Struct(..) | Def::StructCtor(..) | Def::Union(..) |
Def::TyAlias(..) | Def::AssociatedTy(..) | Def::SelfTy(..) => {
Def::TyAlias(..) | Def::AssociatedTy(..) | Def::SelfTy(..) | Def::SelfCtor(..) => {
PatternKind::Leaf { subpatterns: subpatterns }
}

Expand Down
5 changes: 3 additions & 2 deletions src/librustc_passes/rvalue_promotion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -376,7 +376,7 @@ fn check_expr_kind<'a, 'tcx>(
let def = v.tables.qpath_def(qpath, e.hir_id);
match def {
Def::VariantCtor(..) | Def::StructCtor(..) |
Def::Fn(..) | Def::Method(..) => Promotable,
Def::Fn(..) | Def::Method(..) | Def::SelfCtor(..) => Promotable,

// References to a static that are themselves within a static
// are inherently promotable with the exception
Expand Down Expand Up @@ -441,7 +441,8 @@ fn check_expr_kind<'a, 'tcx>(
};
let def_result = match def {
Def::StructCtor(_, CtorKind::Fn) |
Def::VariantCtor(_, CtorKind::Fn) => Promotable,
Def::VariantCtor(_, CtorKind::Fn) |
Def::SelfCtor(..) => Promotable,
Def::Fn(did) => {
v.handle_const_fn_call(did, node_ty, e.span)
}
Expand Down
Loading

0 comments on commit a294236

Please sign in to comment.