about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2016-10-27 18:18:56 -0700
committerGitHub <noreply@github.com>2016-10-27 18:18:56 -0700
commit5530030420d09588f32d6317cdd868e755621302 (patch)
treeeff8148f0d9f49d8a091c570eb67b539a3113fa3 /src
parent3f4408347d2109803edbf53c89c8bce575de4b67 (diff)
parent8a38928b44e26d4d7b9bdacb207a85878058cac8 (diff)
downloadrust-5530030420d09588f32d6317cdd868e755621302.tar.gz
rust-5530030420d09588f32d6317cdd868e755621302.zip
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 https://github.com/rust-lang/rust/issues/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](https://github.com/rust-lang/rust/issues/26264#issuecomment-250603946).

r? @eddyb
Diffstat (limited to 'src')
-rw-r--r--src/librustc/middle/expr_use_visitor.rs2
-rw-r--r--src/librustc/ty/mod.rs2
-rw-r--r--src/librustc/util/ppaux.rs6
-rw-r--r--src/librustc_const_eval/pattern.rs2
-rw-r--r--src/librustc_passes/consts.rs8
-rw-r--r--src/librustc_resolve/diagnostics.rs26
-rw-r--r--src/librustc_resolve/lib.rs49
-rw-r--r--src/librustc_save_analysis/dump_visitor.rs3
-rw-r--r--src/librustc_typeck/astconv.rs22
-rw-r--r--src/librustc_typeck/check/_match.rs3
-rw-r--r--src/librustc_typeck/check/mod.rs139
-rw-r--r--src/librustc_typeck/diagnostics.rs11
-rw-r--r--src/test/compile-fail-fulldeps/issue-18986.rs2
-rw-r--r--src/test/compile-fail/E0071.rs9
-rw-r--r--src/test/compile-fail/enums-are-namespaced-xc.rs3
-rw-r--r--src/test/compile-fail/issue-16058.rs2
-rw-r--r--src/test/compile-fail/issue-17001.rs2
-rw-r--r--src/test/compile-fail/issue-17405.rs2
-rw-r--r--src/test/compile-fail/issue-17518.rs2
-rw-r--r--src/test/compile-fail/issue-21449.rs3
-rw-r--r--src/test/compile-fail/issue-26459.rs2
-rw-r--r--src/test/compile-fail/issue-27815.rs8
-rw-r--r--src/test/compile-fail/lexical-scopes.rs2
-rw-r--r--src/test/compile-fail/struct-path-alias-bounds.rs (renamed from src/test/compile-fail/E0422.rs)14
-rw-r--r--src/test/compile-fail/struct-path-associated-type.rs48
-rw-r--r--src/test/compile-fail/struct-path-self-type-mismatch.rs38
-rw-r--r--src/test/compile-fail/struct-path-self.rs47
-rw-r--r--src/test/compile-fail/trait-as-struct-constructor.rs3
-rw-r--r--src/test/run-pass/issue-22546.rs6
-rw-r--r--src/test/run-pass/struct-path-associated-type.rs (renamed from src/test/compile-fail/struct-pat-associated-path.rs)30
-rw-r--r--src/test/run-pass/struct-path-self.rs54
31 files changed, 341 insertions, 209 deletions
diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs
index 799c02b7403..c37b6df369d 100644
--- a/src/librustc/middle/expr_use_visitor.rs
+++ b/src/librustc/middle/expr_use_visitor.rs
@@ -1017,7 +1017,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
                     delegate.matched_pat(pat, downcast_cmt, match_mode);
                 }
                 Some(Def::Struct(..)) | Some(Def::StructCtor(..)) | Some(Def::Union(..)) |
-                Some(Def::TyAlias(..)) | Some(Def::AssociatedTy(..)) => {
+                Some(Def::TyAlias(..)) | Some(Def::AssociatedTy(..)) | Some(Def::SelfTy(..)) => {
                     debug!("struct cmt_pat={:?} pat={:?}", cmt_pat, pat);
                     delegate.matched_pat(pat, cmt_pat, match_mode);
                 }
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index f65976a8c11..96700a8da86 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -1698,7 +1698,7 @@ impl<'a, 'gcx, 'tcx, 'container> AdtDefData<'gcx, 'container> {
         match def {
             Def::Variant(vid) | Def::VariantCtor(vid, ..) => self.variant_with_id(vid),
             Def::Struct(..) | Def::StructCtor(..) | Def::Union(..) |
-            Def::TyAlias(..) | Def::AssociatedTy(..) => self.struct_variant(),
+            Def::TyAlias(..) | Def::AssociatedTy(..) | Def::SelfTy(..) => self.struct_variant(),
             _ => bug!("unexpected def {:?} in variant_of_def", def)
         }
     }
diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs
index af92569cc35..13202a454fe 100644
--- a/src/librustc/util/ppaux.rs
+++ b/src/librustc/util/ppaux.rs
@@ -14,7 +14,7 @@ use ty::{BrAnon, BrEnv, BrFresh, BrNamed};
 use ty::{TyBool, TyChar, TyAdt};
 use ty::{TyError, TyStr, TyArray, TySlice, TyFloat, TyFnDef, TyFnPtr};
 use ty::{TyParam, TyRawPtr, TyRef, TyNever, TyTuple};
-use ty::TyClosure;
+use ty::{TyClosure, TyProjection, TyAnon};
 use ty::{TyBox, TyTrait, TyInt, TyUint, TyInfer};
 use ty::{self, Ty, TyCtxt, TypeFoldable};
 use ty::fold::{TypeFolder, TypeVisitor};
@@ -879,8 +879,8 @@ impl<'tcx> fmt::Display for ty::TypeVariants<'tcx> {
                 })
             }
             TyTrait(ref data) => write!(f, "{}", data),
-            ty::TyProjection(ref data) => write!(f, "{}", data),
-            ty::TyAnon(def_id, substs) => {
+            TyProjection(ref data) => write!(f, "{}", data),
+            TyAnon(def_id, substs) => {
                 ty::tls::with(|tcx| {
                     // Grab the "TraitA + TraitB" from `impl TraitA + TraitB`,
                     // by looking up the projections associated with the def_id.
diff --git a/src/librustc_const_eval/pattern.rs b/src/librustc_const_eval/pattern.rs
index a6c886533c8..f4dedc184d9 100644
--- a/src/librustc_const_eval/pattern.rs
+++ b/src/librustc_const_eval/pattern.rs
@@ -436,7 +436,7 @@ impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> {
             }
 
             Def::Struct(..) | Def::StructCtor(..) | Def::Union(..) |
-            Def::TyAlias(..) | Def::AssociatedTy(..) => {
+            Def::TyAlias(..) | Def::AssociatedTy(..) | Def::SelfTy(..) => {
                 PatternKind::Leaf { subpatterns: subpatterns }
             }
 
diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs
index ee731dd042e..8ad4d7f57a6 100644
--- a/src/librustc_passes/consts.rs
+++ b/src/librustc_passes/consts.rs
@@ -565,9 +565,11 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node
             }
         }
         hir::ExprStruct(..) => {
-            // unsafe_cell_type doesn't necessarily exist with no_core
-            if Some(v.tcx.expect_def(e.id).def_id()) == v.tcx.lang_items.unsafe_cell_type() {
-                v.add_qualif(ConstQualif::MUTABLE_MEM);
+            if let ty::TyAdt(adt, ..) = v.tcx.expr_ty(e).sty {
+                // unsafe_cell_type doesn't necessarily exist with no_core
+                if Some(adt.did) == v.tcx.lang_items.unsafe_cell_type() {
+                    v.add_qualif(ConstQualif::MUTABLE_MEM);
+                }
             }
         }
 
diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs
index f2a5aedbb3a..1fb5db05dd5 100644
--- a/src/librustc_resolve/diagnostics.rs
+++ b/src/librustc_resolve/diagnostics.rs
@@ -860,31 +860,6 @@ match (A, B, C) {
 ```
 "##,
 
-E0422: r##"
-You are trying to use an identifier that is either undefined or not a struct.
-
-Erroneous code example:
-
-``` compile_fail,E0422
-fn main () {
-    let x = Foo { x: 1, y: 2 };
-}
-```
-
-In this case, `Foo` is undefined, so it inherently isn't anything, and
-definitely not a struct.
-
-```compile_fail,E0422
-fn main () {
-    let foo = 1;
-    let x = foo { x: 1, y: 2 };
-}
-```
-
-In this case, `foo` is defined, but is not a struct, so Rust can't use it as
-one.
-"##,
-
 E0423: r##"
 A `struct` variant name was used like a function name.
 
@@ -1503,6 +1478,7 @@ register_diagnostics! {
 //  E0419, merged into 531
 //  E0420, merged into 532
 //  E0421, merged into 531
+//  E0422, merged into 531/532
     E0531, // unresolved pattern path kind `name`
     E0532, // expected pattern path kind, found another pattern path kind
 //  E0427, merged into 530
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index 856eb348eae..d4900be5758 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -129,8 +129,6 @@ enum ResolutionError<'a> {
     IdentifierBoundMoreThanOnceInParameterList(&'a str),
     /// error E0416: identifier is bound more than once in the same pattern
     IdentifierBoundMoreThanOnceInSamePattern(&'a str),
-    /// error E0422: does not name a struct
-    DoesNotNameAStruct(&'a str),
     /// error E0423: is a struct variant name, but this expression uses it like a function name
     StructVariantUsedAsFunction(&'a str),
     /// 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>,
             err.span_label(span, &format!("used in a pattern more than once"));
             err
         }
-        ResolutionError::DoesNotNameAStruct(name) => {
-            let mut err = struct_span_err!(resolver.session,
-                             span,
-                             E0422,
-                             "`{}` does not name a structure",
-                             name);
-            err.span_label(span, &format!("not a structure"));
-            err
-        }
         ResolutionError::StructVariantUsedAsFunction(path_name) => {
             let mut err = struct_span_err!(resolver.session,
                              span,
@@ -2383,6 +2372,18 @@ impl<'a> Resolver<'a> {
         self.record_def(pat_id, resolution);
     }
 
+    fn resolve_struct_path(&mut self, node_id: NodeId, path: &Path) {
+        // Resolution logic is equivalent for expressions and patterns,
+        // reuse `resolve_pattern_path` for both.
+        self.resolve_pattern_path(node_id, None, path, TypeNS, |def| {
+            match def {
+                Def::Struct(..) | Def::Union(..) | Def::Variant(..) |
+                Def::TyAlias(..) | Def::AssociatedTy(..) | Def::SelfTy(..) => true,
+                _ => false,
+            }
+        }, "struct, variant or union type");
+    }
+
     fn resolve_pattern(&mut self,
                        pat: &Pat,
                        pat_src: PatternSource,
@@ -2460,13 +2461,7 @@ impl<'a> Resolver<'a> {
                 }
 
                 PatKind::Struct(ref path, ..) => {
-                    self.resolve_pattern_path(pat.id, None, path, TypeNS, |def| {
-                        match def {
-                            Def::Struct(..) | Def::Union(..) | Def::Variant(..) |
-                            Def::TyAlias(..) | Def::AssociatedTy(..) => true,
-                            _ => false,
-                        }
-                    }, "variant, struct or type alias");
+                    self.resolve_struct_path(pat.id, path);
                 }
 
                 _ => {}
@@ -3024,23 +3019,7 @@ impl<'a> Resolver<'a> {
             }
 
             ExprKind::Struct(ref path, ..) => {
-                // Resolve the path to the structure it goes to. We don't
-                // check to ensure that the path is actually a structure; that
-                // is checked later during typeck.
-                match self.resolve_path(expr.id, path, 0, TypeNS) {
-                    Ok(definition) => self.record_def(expr.id, definition),
-                    Err(true) => self.record_def(expr.id, err_path_resolution()),
-                    Err(false) => {
-                        debug!("(resolving expression) didn't find struct def",);
-
-                        resolve_error(self,
-                                      path.span,
-                                      ResolutionError::DoesNotNameAStruct(
-                                                                &path_names_to_string(path, 0))
-                                     );
-                        self.record_def(expr.id, err_path_resolution());
-                    }
-                }
+                self.resolve_struct_path(expr.id, path);
 
                 visit::walk_expr(self, expr);
             }
diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs
index 1c60ccb9765..53a5f319323 100644
--- a/src/librustc_save_analysis/dump_visitor.rs
+++ b/src/librustc_save_analysis/dump_visitor.rs
@@ -1493,7 +1493,8 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor for DumpVisitor<'l, 'tcx, 'll, D>
                 Def::StructCtor(..) | Def::VariantCtor(..) |
                 Def::Const(..) | Def::AssociatedConst(..) |
                 Def::Struct(..) | Def::Variant(..) |
-                Def::TyAlias(..) | Def::AssociatedTy(..) => {
+                Def::TyAlias(..) | Def::AssociatedTy(..) |
+                Def::SelfTy(..) => {
                     paths_to_process.push((id, p.clone(), Some(ref_kind)))
                 }
                 def => error!("unexpected definition kind when processing collected paths: {:?}",
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index c137fca58af..8799050b1b9 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -1484,7 +1484,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                       def: Def,
                       opt_self_ty: Option<Ty<'tcx>>,
                       base_path_ref_id: ast::NodeId,
-                      base_segments: &[hir::PathSegment])
+                      base_segments: &[hir::PathSegment],
+                      permit_variants: bool)
                       -> Ty<'tcx> {
         let tcx = self.tcx();
 
@@ -1515,6 +1516,16 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                                     did,
                                     base_segments.last().unwrap())
             }
+            Def::Variant(did) if permit_variants => {
+                // Convert "variant type" as if it were a real type.
+                // The resulting `Ty` is type of the variant's enum for now.
+                tcx.prohibit_type_params(base_segments.split_last().unwrap().1);
+                self.ast_path_to_ty(rscope,
+                                    span,
+                                    param_mode,
+                                    tcx.parent_def_id(did).unwrap(),
+                                    base_segments.last().unwrap())
+            }
             Def::TyParam(did) => {
                 tcx.prohibit_type_params(base_segments);
 
@@ -1604,7 +1615,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                                       opt_self_ty: Option<Ty<'tcx>>,
                                       base_path_ref_id: ast::NodeId,
                                       base_segments: &[hir::PathSegment],
-                                      assoc_segments: &[hir::PathSegment])
+                                      assoc_segments: &[hir::PathSegment],
+                                      permit_variants: bool)
                                       -> (Ty<'tcx>, Def) {
         // Convert the base type.
         debug!("finish_resolving_def_to_ty(base_def={:?}, \
@@ -1619,7 +1631,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                                           base_def,
                                           opt_self_ty,
                                           base_path_ref_id,
-                                          base_segments);
+                                          base_segments,
+                                          permit_variants);
         debug!("finish_resolving_def_to_ty: base_def_to_ty returned {:?}", base_ty);
 
         // If any associated type segments remain, attempt to resolve them.
@@ -1775,7 +1788,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                                                                 opt_self_ty,
                                                                 ast_ty.id,
                                                                 &path.segments[..base_ty_end],
-                                                                &path.segments[base_ty_end..]);
+                                                                &path.segments[base_ty_end..],
+                                                                false);
 
                 // Write back the new resolution.
                 if path_res.depth != 0 {
diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs
index d3fef0711b2..c842514227c 100644
--- a/src/librustc_typeck/check/_match.rs
+++ b/src/librustc_typeck/check/_match.rs
@@ -489,8 +489,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                         expected: Ty<'tcx>) -> Ty<'tcx>
     {
         // Resolve the path and check the definition for errors.
-        let (variant, pat_ty) = if let Some(variant_ty) = self.check_struct_path(path, pat.id,
-                                                                                 pat.span) {
+        let (variant, pat_ty) = if let Some(variant_ty) = self.check_struct_path(path, pat.id) {
             variant_ty
         } else {
             for field in fields {
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 21da8cd388c..75a14bb3db9 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -1686,41 +1686,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                        cause)
     }
 
-    /// Instantiates the type in `did` with the generics in `path` and returns
-    /// it (registering the necessary trait obligations along the way).
-    ///
-    /// Note that this function is only intended to be used with type-paths,
-    /// not with value-paths.
-    pub fn instantiate_type_path(&self,
-                                 did: DefId,
-                                 path: &hir::Path,
-                                 node_id: ast::NodeId)
-                                 -> Ty<'tcx> {
-        debug!("instantiate_type_path(did={:?}, path={:?})", did, path);
-        let mut ty = self.tcx.lookup_item_type(did).ty;
-        if ty.is_fn() {
-            // Tuple variants have fn type even in type namespace, extract true variant type from it
-            ty = self.tcx.no_late_bound_regions(&ty.fn_ret()).unwrap();
-        }
-        let type_predicates = self.tcx.lookup_predicates(did);
-        let substs = AstConv::ast_path_substs_for_ty(self, self,
-                                                     path.span,
-                                                     PathParamMode::Optional,
-                                                     did,
-                                                     path.segments.last().unwrap());
-        debug!("instantiate_type_path: ty={:?} substs={:?}", ty, substs);
-        let bounds = self.instantiate_bounds(path.span, substs, &type_predicates);
-        let cause = traits::ObligationCause::new(path.span, self.body_id,
-                                                 traits::ItemObligation(did));
-        self.add_obligations_for_parameters(cause, &bounds);
-
-        let ty_substituted = self.instantiate_type_scheme(path.span, substs, &ty);
-        self.write_substs(node_id, ty::ItemSubsts {
-            substs: substs
-        });
-        ty_substituted
-    }
-
     pub fn write_nil(&self, node_id: ast::NodeId) {
         self.write_ty(node_id, self.tcx.mk_nil());
     }
@@ -3251,47 +3216,55 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     }
 
     pub fn check_struct_path(&self,
-                         path: &hir::Path,
-                         node_id: ast::NodeId,
-                         span: Span)
-                         -> Option<(ty::VariantDef<'tcx>,  Ty<'tcx>)> {
-        let def = self.finish_resolving_struct_path(path, node_id, span);
+                             path: &hir::Path,
+                             node_id: ast::NodeId)
+                             -> Option<(ty::VariantDef<'tcx>,  Ty<'tcx>)> {
+        let (def, ty) = self.finish_resolving_struct_path(path, node_id);
         let variant = match def {
             Def::Err => {
                 self.set_tainted_by_errors();
                 return None;
             }
-            Def::Variant(did) => {
-                let type_did = self.tcx.parent_def_id(did).unwrap();
-                Some((type_did, self.tcx.expect_variant_def(def)))
-            }
-            Def::Struct(type_did) | Def::Union(type_did) => {
-                Some((type_did, self.tcx.expect_variant_def(def)))
+            Def::Variant(..) => {
+                match ty.sty {
+                    ty::TyAdt(adt, substs) => {
+                        Some((adt.variant_of_def(def), adt.did, substs))
+                    }
+                    _ => bug!("unexpected type: {:?}", ty.sty)
+                }
             }
-            Def::TyAlias(did) | Def::AssociatedTy(did) => {
-                match self.tcx.opt_lookup_item_type(did).map(|scheme| &scheme.ty.sty) {
-                    Some(&ty::TyAdt(adt, _)) if !adt.is_enum() => {
-                        Some((did, adt.struct_variant()))
+            Def::Struct(..) | Def::Union(..) | Def::TyAlias(..) |
+            Def::AssociatedTy(..) | Def::SelfTy(..) => {
+                match ty.sty {
+                    ty::TyAdt(adt, substs) if !adt.is_enum() => {
+                        Some((adt.struct_variant(), adt.did, substs))
                     }
                     _ => None,
                 }
             }
-            _ => None
+            _ => bug!("unexpected definition: {:?}", def)
         };
 
-        if let Some((def_id, variant)) = variant {
+        if let Some((variant, did, substs)) = variant {
             if variant.ctor_kind == CtorKind::Fn &&
                     !self.tcx.sess.features.borrow().relaxed_adts {
                 emit_feature_err(&self.tcx.sess.parse_sess,
-                                 "relaxed_adts", span, GateIssue::Language,
+                                 "relaxed_adts", path.span, GateIssue::Language,
                                  "tuple structs and variants in struct patterns are unstable");
             }
-            let ty = self.instantiate_type_path(def_id, path, node_id);
+
+            // Check bounds on type arguments used in the path.
+            let type_predicates = self.tcx.lookup_predicates(did);
+            let bounds = self.instantiate_bounds(path.span, substs, &type_predicates);
+            let cause = traits::ObligationCause::new(path.span, self.body_id,
+                                                     traits::ItemObligation(did));
+            self.add_obligations_for_parameters(cause, &bounds);
+
             Some((variant, ty))
         } else {
             struct_span_err!(self.tcx.sess, path.span, E0071,
-                             "`{}` does not name a struct or a struct variant",
-                             pprust::path_to_string(path))
+                             "expected struct, variant or union type, found {}",
+                             ty.sort_string(self.tcx))
                 .span_label(path.span, &format!("not a struct"))
                 .emit();
             None
@@ -3305,12 +3278,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                          base_expr: &'gcx Option<P<hir::Expr>>) -> Ty<'tcx>
     {
         // Find the relevant variant
-        let (variant, struct_ty) = if let Some(variant_ty) = self.check_struct_path(path, expr.id,
-                                                                                    expr.span) {
+        let (variant, struct_ty) = if let Some(variant_ty) = self.check_struct_path(path, expr.id) {
             variant_ty
         } else {
             self.check_struct_fields_on_error(fields, base_expr);
-            return self.tcx().types.err;
+            return self.tcx.types.err;
         };
 
         self.check_expr_struct_fields(struct_ty, path.span, variant, fields,
@@ -3805,7 +3777,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                               }
                           }
                           err.emit();
-                          self.tcx().types.err
+                          self.tcx.types.err
                       }
                   }
               }
@@ -3815,29 +3787,26 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
     // Finish resolving a path in a struct expression or pattern `S::A { .. }` if necessary.
     // The newly resolved definition is written into `def_map`.
-    pub fn finish_resolving_struct_path(&self,
-                                        path: &hir::Path,
-                                        node_id: ast::NodeId,
-                                        span: Span)
-                                        -> Def
+    fn finish_resolving_struct_path(&self,
+                                    path: &hir::Path,
+                                    node_id: ast::NodeId)
+                                    -> (Def, Ty<'tcx>)
     {
-        let path_res = self.tcx().expect_resolution(node_id);
-        if path_res.depth == 0 {
-            // If fully resolved already, we don't have to do anything.
-            path_res.base_def
-        } else {
-            let base_ty_end = path.segments.len() - path_res.depth;
-            let (_ty, def) = AstConv::finish_resolving_def_to_ty(self, self, span,
-                                                                 PathParamMode::Optional,
-                                                                 path_res.base_def,
-                                                                 None,
-                                                                 node_id,
-                                                                 &path.segments[..base_ty_end],
-                                                                 &path.segments[base_ty_end..]);
-            // Write back the new resolution.
-            self.tcx().def_map.borrow_mut().insert(node_id, PathResolution::new(def));
-            def
+        let path_res = self.tcx.expect_resolution(node_id);
+        let base_ty_end = path.segments.len() - path_res.depth;
+        let (ty, def) = AstConv::finish_resolving_def_to_ty(self, self, path.span,
+                                                            PathParamMode::Optional,
+                                                            path_res.base_def,
+                                                            None,
+                                                            node_id,
+                                                            &path.segments[..base_ty_end],
+                                                            &path.segments[base_ty_end..],
+                                                            true);
+        // Write back the new resolution.
+        if path_res.depth != 0 {
+            self.tcx.def_map.borrow_mut().insert(node_id, PathResolution::new(def));
         }
+        (def, ty)
     }
 
     // Resolve associated value path into a base type and associated constant or method definition.
@@ -3849,7 +3818,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                        span: Span)
                                        -> (Def, Option<Ty<'tcx>>, &'b [hir::PathSegment])
     {
-        let path_res = self.tcx().expect_resolution(node_id);
+        let path_res = self.tcx.expect_resolution(node_id);
         if path_res.depth == 0 {
             // If fully resolved already, we don't have to do anything.
             (path_res.base_def, opt_self_ty, &path.segments)
@@ -3863,7 +3832,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                                                  opt_self_ty,
                                                                  node_id,
                                                                  &ty_segments[..base_ty_end],
-                                                                 &ty_segments[base_ty_end..]);
+                                                                 &ty_segments[base_ty_end..],
+                                                                 false);
 
             // Resolve an associated constant or method on the previously resolved type.
             let item_segment = path.segments.last().unwrap();
@@ -3883,7 +3853,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             };
 
             // Write back the new resolution.
-            self.tcx().def_map.borrow_mut().insert(node_id, PathResolution::new(def));
+            self.tcx.def_map.borrow_mut().insert(node_id, PathResolution::new(def));
             (def, Some(ty), slice::ref_slice(item_segment))
         }
     }
@@ -4308,7 +4278,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         // the referenced item.
         let ty_substituted = self.instantiate_type_scheme(span, &substs, &scheme.ty);
 
-
         if let Some((ty::ImplContainer(impl_def_id), self_ty)) = ufcs_associated {
             // In the case of `Foo<T>::method` and `<Foo<T>>::method`, if `method`
             // is inherent, there is no `Self` parameter, instead, the impl needs
diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs
index 189f8490f6c..7dd850180d4 100644
--- a/src/librustc_typeck/diagnostics.rs
+++ b/src/librustc_typeck/diagnostics.rs
@@ -895,17 +895,14 @@ fn some_func(x: &mut i32) {
 
 E0071: r##"
 You tried to use structure-literal syntax to create an item that is
-not a struct-style structure or enum variant.
+not a structure or enum variant.
 
 Example of erroneous code:
 
 ```compile_fail,E0071
-enum Foo { FirstValue(i32) };
-
-let u = Foo::FirstValue { value: 0 }; // error: Foo::FirstValue
-                                         // isn't a structure!
-// or even simpler, if the name doesn't refer to a structure at all.
-let t = u32 { value: 4 }; // error: `u32` does not name a structure.
+type U32 = u32;
+let t = U32 { value: 4 }; // error: expected struct, variant or union type,
+                          // found builtin type `u32`
 ```
 
 To fix this, ensure that the name was correctly spelled, and that
diff --git a/src/test/compile-fail-fulldeps/issue-18986.rs b/src/test/compile-fail-fulldeps/issue-18986.rs
index 3c32cb947b3..95af3760544 100644
--- a/src/test/compile-fail-fulldeps/issue-18986.rs
+++ b/src/test/compile-fail-fulldeps/issue-18986.rs
@@ -15,6 +15,6 @@ pub use use_from_trait_xc::Trait;
 
 fn main() {
     match () {
-        Trait { x: 42 } => () //~ ERROR expected variant, struct or type alias, found trait `Trait`
+        Trait { x: 42 } => () //~ ERROR expected struct, variant or union type, found trait `Trait`
     }
 }
diff --git a/src/test/compile-fail/E0071.rs b/src/test/compile-fail/E0071.rs
index c13ba7bf136..95653ae83e7 100644
--- a/src/test/compile-fail/E0071.rs
+++ b/src/test/compile-fail/E0071.rs
@@ -9,13 +9,10 @@
 // except according to those terms.
 
 enum Foo {}
+type FooAlias = Foo;
 
 fn main() {
-    let u = Foo { value: 0 };
-    //~^ ERROR `Foo` does not name a struct or a struct variant [E0071]
-    //~| NOTE not a struct
-
-    let t = u32 { value: 4 };
-    //~^ ERROR `u32` does not name a struct or a struct variant [E0071]
+    let u = FooAlias { value: 0 };
+    //~^ ERROR expected struct, variant or union type, found enum `Foo` [E0071]
     //~| NOTE not a struct
 }
diff --git a/src/test/compile-fail/enums-are-namespaced-xc.rs b/src/test/compile-fail/enums-are-namespaced-xc.rs
index 5315e6c834a..02939565f69 100644
--- a/src/test/compile-fail/enums-are-namespaced-xc.rs
+++ b/src/test/compile-fail/enums-are-namespaced-xc.rs
@@ -14,5 +14,6 @@ extern crate namespaced_enums;
 fn main() {
     let _ = namespaced_enums::A; //~ ERROR unresolved name
     let _ = namespaced_enums::B(10); //~ ERROR unresolved name
-    let _ = namespaced_enums::C { a: 10 }; //~ ERROR does not name a structure
+    let _ = namespaced_enums::C { a: 10 };
+    //~^ ERROR unresolved struct, variant or union type `namespaced_enums::C`
 }
diff --git a/src/test/compile-fail/issue-16058.rs b/src/test/compile-fail/issue-16058.rs
index 671232e701f..92c1e4b5f50 100644
--- a/src/test/compile-fail/issue-16058.rs
+++ b/src/test/compile-fail/issue-16058.rs
@@ -16,7 +16,7 @@ pub struct GslResult {
 
 impl GslResult {
     pub fn new() -> GslResult {
-        Result { //~ ERROR: `Result` does not name a struct or a struct variant
+        Result { //~ ERROR: expected struct, variant or union type, found enum `Result`
             val: 0f64,
             err: 0f64
         }
diff --git a/src/test/compile-fail/issue-17001.rs b/src/test/compile-fail/issue-17001.rs
index 218f68714ff..413e8b464ff 100644
--- a/src/test/compile-fail/issue-17001.rs
+++ b/src/test/compile-fail/issue-17001.rs
@@ -11,5 +11,5 @@
 mod foo {}
 
 fn main() {
-    let p = foo { x: () }; //~ ERROR `foo` does not name a struct or a struct variant
+    let p = foo { x: () }; //~ ERROR expected struct, variant or union type, found module `foo`
 }
diff --git a/src/test/compile-fail/issue-17405.rs b/src/test/compile-fail/issue-17405.rs
index 2f2c252b947..5a6bd5ed588 100644
--- a/src/test/compile-fail/issue-17405.rs
+++ b/src/test/compile-fail/issue-17405.rs
@@ -14,6 +14,6 @@ enum Foo {
 
 fn main() {
     match Foo::Bar(1) {
-        Foo { i } => () //~ ERROR expected variant, struct or type alias, found enum `Foo`
+        Foo { i } => () //~ ERROR expected struct, variant or union type, found enum `Foo`
     }
 }
diff --git a/src/test/compile-fail/issue-17518.rs b/src/test/compile-fail/issue-17518.rs
index 0410fadeb78..2113e38c45c 100644
--- a/src/test/compile-fail/issue-17518.rs
+++ b/src/test/compile-fail/issue-17518.rs
@@ -13,5 +13,5 @@ enum SomeEnum {
 }
 
 fn main() {
-    E { name: "foobar" }; //~ ERROR `E` does not name a structure
+    E { name: "foobar" }; //~ ERROR unresolved struct, variant or union type `E`
 }
diff --git a/src/test/compile-fail/issue-21449.rs b/src/test/compile-fail/issue-21449.rs
index 090b8a0d16e..cc44cf88f09 100644
--- a/src/test/compile-fail/issue-21449.rs
+++ b/src/test/compile-fail/issue-21449.rs
@@ -11,5 +11,6 @@
 mod MyMod {}
 
 fn main() {
-    let myVar = MyMod { T: 0 }; //~ ERROR `MyMod` does not name a struct or a struct variant
+    let myVar = MyMod { T: 0 };
+    //~^ ERROR expected struct, variant or union type, found module `MyMod`
 }
diff --git a/src/test/compile-fail/issue-26459.rs b/src/test/compile-fail/issue-26459.rs
index 24b39eeff0f..8be3d88bd5c 100644
--- a/src/test/compile-fail/issue-26459.rs
+++ b/src/test/compile-fail/issue-26459.rs
@@ -11,6 +11,6 @@
 fn main() {
     match 'a' {
         char{ch} => true
-        //~^ ERROR expected variant, struct or type alias, found builtin type `char`
+        //~^ ERROR expected struct, variant or union type, found builtin type `char`
     };
 }
diff --git a/src/test/compile-fail/issue-27815.rs b/src/test/compile-fail/issue-27815.rs
index 33930d1db14..d9840abf0ca 100644
--- a/src/test/compile-fail/issue-27815.rs
+++ b/src/test/compile-fail/issue-27815.rs
@@ -11,12 +11,12 @@
 mod A {}
 
 fn main() {
-    let u = A { x: 1 }; //~ ERROR `A` does not name a struct or a struct variant
-    let v = u32 { x: 1 }; //~ ERROR `u32` does not name a struct or a struct variant
+    let u = A { x: 1 }; //~ ERROR expected struct, variant or union type, found module `A`
+    let v = u32 { x: 1 }; //~ ERROR expected struct, variant or union type, found builtin type `u32`
     match () {
         A { x: 1 } => {}
-        //~^ ERROR expected variant, struct or type alias, found module `A`
+        //~^ ERROR expected struct, variant or union type, found module `A`
         u32 { x: 1 } => {}
-        //~^ ERROR expected variant, struct or type alias, found builtin type `u32`
+        //~^ ERROR expected struct, variant or union type, found builtin type `u32`
     }
 }
diff --git a/src/test/compile-fail/lexical-scopes.rs b/src/test/compile-fail/lexical-scopes.rs
index 505a91f223c..1ab59e790d7 100644
--- a/src/test/compile-fail/lexical-scopes.rs
+++ b/src/test/compile-fail/lexical-scopes.rs
@@ -10,7 +10,7 @@
 
 struct T { i: i32 }
 fn f<T>() {
-    let t = T { i: 0 }; //~ ERROR `T` does not name a struct or a struct variant
+    let t = T { i: 0 }; //~ ERROR expected struct, variant or union type, found type parameter `T`
 }
 
 mod Foo {
diff --git a/src/test/compile-fail/E0422.rs b/src/test/compile-fail/struct-path-alias-bounds.rs
index 61e96b896a6..1b6e51e3703 100644
--- a/src/test/compile-fail/E0422.rs
+++ b/src/test/compile-fail/struct-path-alias-bounds.rs
@@ -8,8 +8,14 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-fn main () {
-    let x = Foo { x: 1, y: 2 };
-    //~^ ERROR E0422
-    //~| NOTE not a structure
+// issue #36286
+
+struct S<T: Clone> { a: T }
+
+struct NoClone;
+type A = S<NoClone>;
+
+fn main() {
+    let s = A { a: NoClone };
+    //~^ ERROR the trait bound `NoClone: std::clone::Clone` is not satisfied
 }
diff --git a/src/test/compile-fail/struct-path-associated-type.rs b/src/test/compile-fail/struct-path-associated-type.rs
new file mode 100644
index 00000000000..660ac44ce0b
--- /dev/null
+++ b/src/test/compile-fail/struct-path-associated-type.rs
@@ -0,0 +1,48 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+struct S;
+
+trait Tr {
+    type A;
+}
+
+impl Tr for S {
+    type A = S;
+}
+
+fn f<T: Tr>() {
+    let s = T::A {};
+    //~^ ERROR expected struct, variant or union type, found associated type
+    let z = T::A::<u8> {};
+    //~^ ERROR expected struct, variant or union type, found associated type
+    //~| ERROR type parameters are not allowed on this type
+    match S {
+        T::A {} => {}
+        //~^ ERROR expected struct, variant or union type, found associated type
+    }
+}
+
+fn g<T: Tr<A = S>>() {
+    let s = T::A {}; // OK
+    let z = T::A::<u8> {}; //~ ERROR type parameters are not allowed on this type
+    match S {
+        T::A {} => {} // OK
+    }
+}
+
+fn main() {
+    let s = S::A {}; //~ ERROR ambiguous associated type
+    let z = S::A::<u8> {}; //~ ERROR ambiguous associated type
+    //~^ ERROR type parameters are not allowed on this type
+    match S {
+        S::A {} => {} //~ ERROR ambiguous associated type
+    }
+}
diff --git a/src/test/compile-fail/struct-path-self-type-mismatch.rs b/src/test/compile-fail/struct-path-self-type-mismatch.rs
new file mode 100644
index 00000000000..f694e7d277c
--- /dev/null
+++ b/src/test/compile-fail/struct-path-self-type-mismatch.rs
@@ -0,0 +1,38 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+struct Foo<A> { inner: A }
+
+trait Bar { fn bar(); }
+
+impl Bar for Foo<i32> {
+    fn bar() {
+        Self { inner: 1.5f32 }; //~ ERROR mismatched types
+                                //~^ NOTE expected i32, found f32
+    }
+}
+
+impl<T> Foo<T> {
+    fn new<U>(u: U) -> Foo<U> {
+        Self {
+        //~^ ERROR mismatched types
+        //~| expected type parameter, found a different type parameter
+        //~| expected type `Foo<U>`
+        //~| found type `Foo<T>`
+            inner: u
+            //~^ ERROR mismatched types
+            //~| expected type parameter, found a different type parameter
+            //~| expected type `T`
+            //~| found type `U`
+        }
+    }
+}
+
+fn main() {}
diff --git a/src/test/compile-fail/struct-path-self.rs b/src/test/compile-fail/struct-path-self.rs
new file mode 100644
index 00000000000..067d6ac22dc
--- /dev/null
+++ b/src/test/compile-fail/struct-path-self.rs
@@ -0,0 +1,47 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+struct S;
+
+trait Tr {
+    fn f() {
+        let s = Self {};
+        //~^ ERROR expected struct, variant or union type, found Self
+        let z = Self::<u8> {};
+        //~^ ERROR expected struct, variant or union type, found Self
+        //~| ERROR type parameters are not allowed on this type
+        match s {
+            Self { .. } => {}
+            //~^ ERROR expected struct, variant or union type, found Self
+        }
+    }
+}
+
+impl Tr for S {
+    fn f() {
+        let s = Self {}; // OK
+        let z = Self::<u8> {}; //~ ERROR type parameters are not allowed on this type
+        match s {
+            Self { .. } => {} // OK
+        }
+    }
+}
+
+impl S {
+    fn g() {
+        let s = Self {}; // OK
+        let z = Self::<u8> {}; //~ ERROR type parameters are not allowed on this type
+        match s {
+            Self { .. } => {} // OK
+        }
+    }
+}
+
+fn main() {}
diff --git a/src/test/compile-fail/trait-as-struct-constructor.rs b/src/test/compile-fail/trait-as-struct-constructor.rs
index c78eebddbfd..49d58580da5 100644
--- a/src/test/compile-fail/trait-as-struct-constructor.rs
+++ b/src/test/compile-fail/trait-as-struct-constructor.rs
@@ -12,6 +12,5 @@ trait TraitNotAStruct {}
 
 fn main() {
     TraitNotAStruct{ value: 0 };
-    //~^ ERROR: `TraitNotAStruct` does not name a struct or a struct variant [E0071]
-    //~| NOTE not a struct
+    //~^ ERROR expected struct, variant or union type, found trait `TraitNotAStruct`
 }
diff --git a/src/test/run-pass/issue-22546.rs b/src/test/run-pass/issue-22546.rs
index b3cb8a78213..8516d344e1c 100644
--- a/src/test/run-pass/issue-22546.rs
+++ b/src/test/run-pass/issue-22546.rs
@@ -51,4 +51,10 @@ fn main() {
     if let None::<u8> = Some(8) {
         panic!();
     }
+    if let None::<u8> { .. } = Some(8) {
+        panic!();
+    }
+    if let Option::None::<u8> { .. } = Some(8) {
+        panic!();
+    }
 }
diff --git a/src/test/compile-fail/struct-pat-associated-path.rs b/src/test/run-pass/struct-path-associated-type.rs
index d3f840f4fe9..b033ed5c802 100644
--- a/src/test/compile-fail/struct-pat-associated-path.rs
+++ b/src/test/run-pass/struct-path-associated-type.rs
@@ -8,30 +8,28 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-struct S;
+struct S<T, U = u16> {
+    a: T,
+    b: U,
+}
 
 trait Tr {
     type A;
 }
-
-impl Tr for S {
-    type A = S;
-}
-
-fn f<T: Tr>() {
-    match S {
-        T::A {} => {} //~ ERROR `T::A` does not name a struct or a struct variant
-    }
+impl Tr for u8 {
+    type A = S<u8, u16>;
 }
 
-fn g<T: Tr<A = S>>() {
-    match S {
-        T::A {} => {} //~ ERROR `T::A` does not name a struct or a struct variant
+fn f<T: Tr<A = S<u8>>>() {
+    let s = T::A { a: 0, b: 1 };
+    match s {
+        T::A { a, b } => {
+            assert_eq!(a, 0);
+            assert_eq!(b, 1);
+        }
     }
 }
 
 fn main() {
-    match S {
-        S::A {} => {} //~ ERROR ambiguous associated type
-    }
+    f::<u8>();
 }
diff --git a/src/test/run-pass/struct-path-self.rs b/src/test/run-pass/struct-path-self.rs
new file mode 100644
index 00000000000..c7a282c2a2f
--- /dev/null
+++ b/src/test/run-pass/struct-path-self.rs
@@ -0,0 +1,54 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::ops::Add;
+
+struct S<T, U = u16> {
+    a: T,
+    b: U,
+}
+
+trait Tr {
+    fn f(&self) -> Self;
+}
+
+impl<T: Default + Add<u8, Output = T>, U: Default> Tr for S<T, U> {
+    fn f(&self) -> Self {
+        let s = Self { a: Default::default(), b: Default::default() };
+        match s {
+            Self { a, b } => Self { a: a + 1, b: b }
+        }
+    }
+}
+
+impl<T: Default, U: Default + Add<u16, Output = U>> S<T, U> {
+    fn g(&self) -> Self {
+        let s = Self { a: Default::default(), b: Default::default() };
+        match s {
+            Self { a, b } => Self { a: a, b: b + 1 }
+        }
+    }
+}
+
+impl S<u8> {
+    fn new() -> Self {
+        Self { a: 0, b: 1 }
+    }
+}
+
+fn main() {
+    let s0 = S::new();
+    let s1 = s0.f();
+    assert_eq!(s1.a, 1);
+    assert_eq!(s1.b, 0);
+    let s2 = s0.g();
+    assert_eq!(s2.a, 0);
+    assert_eq!(s2.b, 1);
+}