Skip to content

Commit 5530030

Browse files
authored
Auto merge of #37035 - petrochenkov:selfstruct, r=eddyb
Support `Self` in struct expressions and patterns Struct expressions and patterns generally support type aliases `Alias { field: 10 }` i.e. they already have to work with `ty::Ty` to do their job. `Self` is a type alias (when it's not a type parameter) => struct expressions and patterns should support `Self`. Typical example: ``` impl MyStruct { fn new() -> Self { Self { a: 10, b: "Hello" } } } ``` The first commit does some preparations and cleanups, see the commit message for details. This also fixes couple of bugs related to aliases in struct paths (fixes #36286). EDIT: Since struct expressions and patterns always work with `ty::Ty` now, associated paths in them are also supported. If associated type `A::B` successfully resolves to a struct (or union) type, then `A::B { /* fields */ }` is a valid expression/pattern. This will become more important when enum variants are treated as [associated items](#26264 (comment)). r? @eddyb
2 parents 3f44083 + 8a38928 commit 5530030

31 files changed

+341
-209
lines changed

src/librustc/middle/expr_use_visitor.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1017,7 +1017,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
10171017
delegate.matched_pat(pat, downcast_cmt, match_mode);
10181018
}
10191019
Some(Def::Struct(..)) | Some(Def::StructCtor(..)) | Some(Def::Union(..)) |
1020-
Some(Def::TyAlias(..)) | Some(Def::AssociatedTy(..)) => {
1020+
Some(Def::TyAlias(..)) | Some(Def::AssociatedTy(..)) | Some(Def::SelfTy(..)) => {
10211021
debug!("struct cmt_pat={:?} pat={:?}", cmt_pat, pat);
10221022
delegate.matched_pat(pat, cmt_pat, match_mode);
10231023
}

src/librustc/ty/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1698,7 +1698,7 @@ impl<'a, 'gcx, 'tcx, 'container> AdtDefData<'gcx, 'container> {
16981698
match def {
16991699
Def::Variant(vid) | Def::VariantCtor(vid, ..) => self.variant_with_id(vid),
17001700
Def::Struct(..) | Def::StructCtor(..) | Def::Union(..) |
1701-
Def::TyAlias(..) | Def::AssociatedTy(..) => self.struct_variant(),
1701+
Def::TyAlias(..) | Def::AssociatedTy(..) | Def::SelfTy(..) => self.struct_variant(),
17021702
_ => bug!("unexpected def {:?} in variant_of_def", def)
17031703
}
17041704
}

src/librustc/util/ppaux.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use ty::{BrAnon, BrEnv, BrFresh, BrNamed};
1414
use ty::{TyBool, TyChar, TyAdt};
1515
use ty::{TyError, TyStr, TyArray, TySlice, TyFloat, TyFnDef, TyFnPtr};
1616
use ty::{TyParam, TyRawPtr, TyRef, TyNever, TyTuple};
17-
use ty::TyClosure;
17+
use ty::{TyClosure, TyProjection, TyAnon};
1818
use ty::{TyBox, TyTrait, TyInt, TyUint, TyInfer};
1919
use ty::{self, Ty, TyCtxt, TypeFoldable};
2020
use ty::fold::{TypeFolder, TypeVisitor};
@@ -879,8 +879,8 @@ impl<'tcx> fmt::Display for ty::TypeVariants<'tcx> {
879879
})
880880
}
881881
TyTrait(ref data) => write!(f, "{}", data),
882-
ty::TyProjection(ref data) => write!(f, "{}", data),
883-
ty::TyAnon(def_id, substs) => {
882+
TyProjection(ref data) => write!(f, "{}", data),
883+
TyAnon(def_id, substs) => {
884884
ty::tls::with(|tcx| {
885885
// Grab the "TraitA + TraitB" from `impl TraitA + TraitB`,
886886
// by looking up the projections associated with the def_id.

src/librustc_const_eval/pattern.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -436,7 +436,7 @@ impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> {
436436
}
437437

438438
Def::Struct(..) | Def::StructCtor(..) | Def::Union(..) |
439-
Def::TyAlias(..) | Def::AssociatedTy(..) => {
439+
Def::TyAlias(..) | Def::AssociatedTy(..) | Def::SelfTy(..) => {
440440
PatternKind::Leaf { subpatterns: subpatterns }
441441
}
442442

src/librustc_passes/consts.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -565,9 +565,11 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node
565565
}
566566
}
567567
hir::ExprStruct(..) => {
568-
// unsafe_cell_type doesn't necessarily exist with no_core
569-
if Some(v.tcx.expect_def(e.id).def_id()) == v.tcx.lang_items.unsafe_cell_type() {
570-
v.add_qualif(ConstQualif::MUTABLE_MEM);
568+
if let ty::TyAdt(adt, ..) = v.tcx.expr_ty(e).sty {
569+
// unsafe_cell_type doesn't necessarily exist with no_core
570+
if Some(adt.did) == v.tcx.lang_items.unsafe_cell_type() {
571+
v.add_qualif(ConstQualif::MUTABLE_MEM);
572+
}
571573
}
572574
}
573575

src/librustc_resolve/diagnostics.rs

+1-25
Original file line numberDiff line numberDiff line change
@@ -860,31 +860,6 @@ match (A, B, C) {
860860
```
861861
"##,
862862

863-
E0422: r##"
864-
You are trying to use an identifier that is either undefined or not a struct.
865-
866-
Erroneous code example:
867-
868-
``` compile_fail,E0422
869-
fn main () {
870-
let x = Foo { x: 1, y: 2 };
871-
}
872-
```
873-
874-
In this case, `Foo` is undefined, so it inherently isn't anything, and
875-
definitely not a struct.
876-
877-
```compile_fail,E0422
878-
fn main () {
879-
let foo = 1;
880-
let x = foo { x: 1, y: 2 };
881-
}
882-
```
883-
884-
In this case, `foo` is defined, but is not a struct, so Rust can't use it as
885-
one.
886-
"##,
887-
888863
E0423: r##"
889864
A `struct` variant name was used like a function name.
890865
@@ -1503,6 +1478,7 @@ register_diagnostics! {
15031478
// E0419, merged into 531
15041479
// E0420, merged into 532
15051480
// E0421, merged into 531
1481+
// E0422, merged into 531/532
15061482
E0531, // unresolved pattern path kind `name`
15071483
E0532, // expected pattern path kind, found another pattern path kind
15081484
// E0427, merged into 530

src/librustc_resolve/lib.rs

+14-35
Original file line numberDiff line numberDiff line change
@@ -129,8 +129,6 @@ enum ResolutionError<'a> {
129129
IdentifierBoundMoreThanOnceInParameterList(&'a str),
130130
/// error E0416: identifier is bound more than once in the same pattern
131131
IdentifierBoundMoreThanOnceInSamePattern(&'a str),
132-
/// error E0422: does not name a struct
133-
DoesNotNameAStruct(&'a str),
134132
/// error E0423: is a struct variant name, but this expression uses it like a function name
135133
StructVariantUsedAsFunction(&'a str),
136134
/// error E0424: `self` is not available in a static method
@@ -336,15 +334,6 @@ fn resolve_struct_error<'b, 'a: 'b, 'c>(resolver: &'b Resolver<'a>,
336334
err.span_label(span, &format!("used in a pattern more than once"));
337335
err
338336
}
339-
ResolutionError::DoesNotNameAStruct(name) => {
340-
let mut err = struct_span_err!(resolver.session,
341-
span,
342-
E0422,
343-
"`{}` does not name a structure",
344-
name);
345-
err.span_label(span, &format!("not a structure"));
346-
err
347-
}
348337
ResolutionError::StructVariantUsedAsFunction(path_name) => {
349338
let mut err = struct_span_err!(resolver.session,
350339
span,
@@ -2383,6 +2372,18 @@ impl<'a> Resolver<'a> {
23832372
self.record_def(pat_id, resolution);
23842373
}
23852374

2375+
fn resolve_struct_path(&mut self, node_id: NodeId, path: &Path) {
2376+
// Resolution logic is equivalent for expressions and patterns,
2377+
// reuse `resolve_pattern_path` for both.
2378+
self.resolve_pattern_path(node_id, None, path, TypeNS, |def| {
2379+
match def {
2380+
Def::Struct(..) | Def::Union(..) | Def::Variant(..) |
2381+
Def::TyAlias(..) | Def::AssociatedTy(..) | Def::SelfTy(..) => true,
2382+
_ => false,
2383+
}
2384+
}, "struct, variant or union type");
2385+
}
2386+
23862387
fn resolve_pattern(&mut self,
23872388
pat: &Pat,
23882389
pat_src: PatternSource,
@@ -2460,13 +2461,7 @@ impl<'a> Resolver<'a> {
24602461
}
24612462

24622463
PatKind::Struct(ref path, ..) => {
2463-
self.resolve_pattern_path(pat.id, None, path, TypeNS, |def| {
2464-
match def {
2465-
Def::Struct(..) | Def::Union(..) | Def::Variant(..) |
2466-
Def::TyAlias(..) | Def::AssociatedTy(..) => true,
2467-
_ => false,
2468-
}
2469-
}, "variant, struct or type alias");
2464+
self.resolve_struct_path(pat.id, path);
24702465
}
24712466

24722467
_ => {}
@@ -3024,23 +3019,7 @@ impl<'a> Resolver<'a> {
30243019
}
30253020

30263021
ExprKind::Struct(ref path, ..) => {
3027-
// Resolve the path to the structure it goes to. We don't
3028-
// check to ensure that the path is actually a structure; that
3029-
// is checked later during typeck.
3030-
match self.resolve_path(expr.id, path, 0, TypeNS) {
3031-
Ok(definition) => self.record_def(expr.id, definition),
3032-
Err(true) => self.record_def(expr.id, err_path_resolution()),
3033-
Err(false) => {
3034-
debug!("(resolving expression) didn't find struct def",);
3035-
3036-
resolve_error(self,
3037-
path.span,
3038-
ResolutionError::DoesNotNameAStruct(
3039-
&path_names_to_string(path, 0))
3040-
);
3041-
self.record_def(expr.id, err_path_resolution());
3042-
}
3043-
}
3022+
self.resolve_struct_path(expr.id, path);
30443023

30453024
visit::walk_expr(self, expr);
30463025
}

src/librustc_save_analysis/dump_visitor.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1493,7 +1493,8 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor for DumpVisitor<'l, 'tcx, 'll, D>
14931493
Def::StructCtor(..) | Def::VariantCtor(..) |
14941494
Def::Const(..) | Def::AssociatedConst(..) |
14951495
Def::Struct(..) | Def::Variant(..) |
1496-
Def::TyAlias(..) | Def::AssociatedTy(..) => {
1496+
Def::TyAlias(..) | Def::AssociatedTy(..) |
1497+
Def::SelfTy(..) => {
14971498
paths_to_process.push((id, p.clone(), Some(ref_kind)))
14981499
}
14991500
def => error!("unexpected definition kind when processing collected paths: {:?}",

src/librustc_typeck/astconv.rs

+18-4
Original file line numberDiff line numberDiff line change
@@ -1484,7 +1484,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
14841484
def: Def,
14851485
opt_self_ty: Option<Ty<'tcx>>,
14861486
base_path_ref_id: ast::NodeId,
1487-
base_segments: &[hir::PathSegment])
1487+
base_segments: &[hir::PathSegment],
1488+
permit_variants: bool)
14881489
-> Ty<'tcx> {
14891490
let tcx = self.tcx();
14901491

@@ -1515,6 +1516,16 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
15151516
did,
15161517
base_segments.last().unwrap())
15171518
}
1519+
Def::Variant(did) if permit_variants => {
1520+
// Convert "variant type" as if it were a real type.
1521+
// The resulting `Ty` is type of the variant's enum for now.
1522+
tcx.prohibit_type_params(base_segments.split_last().unwrap().1);
1523+
self.ast_path_to_ty(rscope,
1524+
span,
1525+
param_mode,
1526+
tcx.parent_def_id(did).unwrap(),
1527+
base_segments.last().unwrap())
1528+
}
15181529
Def::TyParam(did) => {
15191530
tcx.prohibit_type_params(base_segments);
15201531

@@ -1604,7 +1615,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
16041615
opt_self_ty: Option<Ty<'tcx>>,
16051616
base_path_ref_id: ast::NodeId,
16061617
base_segments: &[hir::PathSegment],
1607-
assoc_segments: &[hir::PathSegment])
1618+
assoc_segments: &[hir::PathSegment],
1619+
permit_variants: bool)
16081620
-> (Ty<'tcx>, Def) {
16091621
// Convert the base type.
16101622
debug!("finish_resolving_def_to_ty(base_def={:?}, \
@@ -1619,7 +1631,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
16191631
base_def,
16201632
opt_self_ty,
16211633
base_path_ref_id,
1622-
base_segments);
1634+
base_segments,
1635+
permit_variants);
16231636
debug!("finish_resolving_def_to_ty: base_def_to_ty returned {:?}", base_ty);
16241637

16251638
// If any associated type segments remain, attempt to resolve them.
@@ -1775,7 +1788,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
17751788
opt_self_ty,
17761789
ast_ty.id,
17771790
&path.segments[..base_ty_end],
1778-
&path.segments[base_ty_end..]);
1791+
&path.segments[base_ty_end..],
1792+
false);
17791793

17801794
// Write back the new resolution.
17811795
if path_res.depth != 0 {

src/librustc_typeck/check/_match.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -489,8 +489,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
489489
expected: Ty<'tcx>) -> Ty<'tcx>
490490
{
491491
// Resolve the path and check the definition for errors.
492-
let (variant, pat_ty) = if let Some(variant_ty) = self.check_struct_path(path, pat.id,
493-
pat.span) {
492+
let (variant, pat_ty) = if let Some(variant_ty) = self.check_struct_path(path, pat.id) {
494493
variant_ty
495494
} else {
496495
for field in fields {

0 commit comments

Comments
 (0)