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
This commit is contained in:
bors 2016-10-27 18:18:56 -07:00 committed by GitHub
commit 5530030420
31 changed files with 341 additions and 209 deletions

View File

@ -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);
}

View File

@ -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)
}
}

View File

@ -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.

View File

@ -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 }
}

View File

@ -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);
}
}
}

View File

@ -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

View File

@ -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);
}

View File

@ -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: {:?}",

View File

@ -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 {

View File

@ -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 {

View File

@ -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::Variant(..) => {
match ty.sty {
ty::TyAdt(adt, substs) => {
Some((adt.variant_of_def(def), adt.did, substs))
}
_ => bug!("unexpected type: {:?}", ty.sty)
}
}
Def::Struct(type_did) | Def::Union(type_did) => {
Some((type_did, self.tcx.expect_variant_def(def)))
}
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

View File

@ -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

View File

@ -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`
}
}

View File

@ -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
}

View File

@ -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`
}

View File

@ -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
}

View File

@ -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`
}

View File

@ -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`
}
}

View File

@ -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`
}

View File

@ -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`
}

View File

@ -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`
};
}

View File

@ -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`
}
}

View File

@ -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 {

View File

@ -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
}

View File

@ -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
}
}

View File

@ -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() {}

View File

@ -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() {}

View File

@ -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`
}

View File

@ -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!();
}
}

View File

@ -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;
impl Tr for u8 {
type A = S<u8, u16>;
}
fn f<T: Tr>() {
match S {
T::A {} => {} //~ ERROR `T::A` does not name a struct or a struct variant
}
}
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>();
}

View File

@ -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);
}