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:
commit
5530030420
|
@ -1017,7 +1017,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
|
||||||
delegate.matched_pat(pat, downcast_cmt, match_mode);
|
delegate.matched_pat(pat, downcast_cmt, match_mode);
|
||||||
}
|
}
|
||||||
Some(Def::Struct(..)) | Some(Def::StructCtor(..)) | Some(Def::Union(..)) |
|
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);
|
debug!("struct cmt_pat={:?} pat={:?}", cmt_pat, pat);
|
||||||
delegate.matched_pat(pat, cmt_pat, match_mode);
|
delegate.matched_pat(pat, cmt_pat, match_mode);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1698,7 +1698,7 @@ impl<'a, 'gcx, 'tcx, 'container> AdtDefData<'gcx, 'container> {
|
||||||
match def {
|
match def {
|
||||||
Def::Variant(vid) | Def::VariantCtor(vid, ..) => self.variant_with_id(vid),
|
Def::Variant(vid) | Def::VariantCtor(vid, ..) => self.variant_with_id(vid),
|
||||||
Def::Struct(..) | Def::StructCtor(..) | Def::Union(..) |
|
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)
|
_ => bug!("unexpected def {:?} in variant_of_def", def)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ use ty::{BrAnon, BrEnv, BrFresh, BrNamed};
|
||||||
use ty::{TyBool, TyChar, TyAdt};
|
use ty::{TyBool, TyChar, TyAdt};
|
||||||
use ty::{TyError, TyStr, TyArray, TySlice, TyFloat, TyFnDef, TyFnPtr};
|
use ty::{TyError, TyStr, TyArray, TySlice, TyFloat, TyFnDef, TyFnPtr};
|
||||||
use ty::{TyParam, TyRawPtr, TyRef, TyNever, TyTuple};
|
use ty::{TyParam, TyRawPtr, TyRef, TyNever, TyTuple};
|
||||||
use ty::TyClosure;
|
use ty::{TyClosure, TyProjection, TyAnon};
|
||||||
use ty::{TyBox, TyTrait, TyInt, TyUint, TyInfer};
|
use ty::{TyBox, TyTrait, TyInt, TyUint, TyInfer};
|
||||||
use ty::{self, Ty, TyCtxt, TypeFoldable};
|
use ty::{self, Ty, TyCtxt, TypeFoldable};
|
||||||
use ty::fold::{TypeFolder, TypeVisitor};
|
use ty::fold::{TypeFolder, TypeVisitor};
|
||||||
|
@ -879,8 +879,8 @@ impl<'tcx> fmt::Display for ty::TypeVariants<'tcx> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
TyTrait(ref data) => write!(f, "{}", data),
|
TyTrait(ref data) => write!(f, "{}", data),
|
||||||
ty::TyProjection(ref data) => write!(f, "{}", data),
|
TyProjection(ref data) => write!(f, "{}", data),
|
||||||
ty::TyAnon(def_id, substs) => {
|
TyAnon(def_id, substs) => {
|
||||||
ty::tls::with(|tcx| {
|
ty::tls::with(|tcx| {
|
||||||
// Grab the "TraitA + TraitB" from `impl TraitA + TraitB`,
|
// Grab the "TraitA + TraitB" from `impl TraitA + TraitB`,
|
||||||
// by looking up the projections associated with the def_id.
|
// by looking up the projections associated with the def_id.
|
||||||
|
|
|
@ -436,7 +436,7 @@ impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
Def::Struct(..) | Def::StructCtor(..) | Def::Union(..) |
|
Def::Struct(..) | Def::StructCtor(..) | Def::Union(..) |
|
||||||
Def::TyAlias(..) | Def::AssociatedTy(..) => {
|
Def::TyAlias(..) | Def::AssociatedTy(..) | Def::SelfTy(..) => {
|
||||||
PatternKind::Leaf { subpatterns: subpatterns }
|
PatternKind::Leaf { subpatterns: subpatterns }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -565,11 +565,13 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
hir::ExprStruct(..) => {
|
hir::ExprStruct(..) => {
|
||||||
|
if let ty::TyAdt(adt, ..) = v.tcx.expr_ty(e).sty {
|
||||||
// unsafe_cell_type doesn't necessarily exist with no_core
|
// 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() {
|
if Some(adt.did) == v.tcx.lang_items.unsafe_cell_type() {
|
||||||
v.add_qualif(ConstQualif::MUTABLE_MEM);
|
v.add_qualif(ConstQualif::MUTABLE_MEM);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
hir::ExprLit(_) |
|
hir::ExprLit(_) |
|
||||||
hir::ExprAddrOf(..) => {
|
hir::ExprAddrOf(..) => {
|
||||||
|
|
|
@ -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##"
|
E0423: r##"
|
||||||
A `struct` variant name was used like a function name.
|
A `struct` variant name was used like a function name.
|
||||||
|
|
||||||
|
@ -1503,6 +1478,7 @@ register_diagnostics! {
|
||||||
// E0419, merged into 531
|
// E0419, merged into 531
|
||||||
// E0420, merged into 532
|
// E0420, merged into 532
|
||||||
// E0421, merged into 531
|
// E0421, merged into 531
|
||||||
|
// E0422, merged into 531/532
|
||||||
E0531, // unresolved pattern path kind `name`
|
E0531, // unresolved pattern path kind `name`
|
||||||
E0532, // expected pattern path kind, found another pattern path kind
|
E0532, // expected pattern path kind, found another pattern path kind
|
||||||
// E0427, merged into 530
|
// E0427, merged into 530
|
||||||
|
|
|
@ -129,8 +129,6 @@ enum ResolutionError<'a> {
|
||||||
IdentifierBoundMoreThanOnceInParameterList(&'a str),
|
IdentifierBoundMoreThanOnceInParameterList(&'a str),
|
||||||
/// error E0416: identifier is bound more than once in the same pattern
|
/// error E0416: identifier is bound more than once in the same pattern
|
||||||
IdentifierBoundMoreThanOnceInSamePattern(&'a str),
|
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
|
/// error E0423: is a struct variant name, but this expression uses it like a function name
|
||||||
StructVariantUsedAsFunction(&'a str),
|
StructVariantUsedAsFunction(&'a str),
|
||||||
/// error E0424: `self` is not available in a static method
|
/// 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.span_label(span, &format!("used in a pattern more than once"));
|
||||||
err
|
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) => {
|
ResolutionError::StructVariantUsedAsFunction(path_name) => {
|
||||||
let mut err = struct_span_err!(resolver.session,
|
let mut err = struct_span_err!(resolver.session,
|
||||||
span,
|
span,
|
||||||
|
@ -2383,6 +2372,18 @@ impl<'a> Resolver<'a> {
|
||||||
self.record_def(pat_id, resolution);
|
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,
|
fn resolve_pattern(&mut self,
|
||||||
pat: &Pat,
|
pat: &Pat,
|
||||||
pat_src: PatternSource,
|
pat_src: PatternSource,
|
||||||
|
@ -2460,13 +2461,7 @@ impl<'a> Resolver<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
PatKind::Struct(ref path, ..) => {
|
PatKind::Struct(ref path, ..) => {
|
||||||
self.resolve_pattern_path(pat.id, None, path, TypeNS, |def| {
|
self.resolve_struct_path(pat.id, path);
|
||||||
match def {
|
|
||||||
Def::Struct(..) | Def::Union(..) | Def::Variant(..) |
|
|
||||||
Def::TyAlias(..) | Def::AssociatedTy(..) => true,
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}, "variant, struct or type alias");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => {}
|
_ => {}
|
||||||
|
@ -3024,23 +3019,7 @@ impl<'a> Resolver<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
ExprKind::Struct(ref path, ..) => {
|
ExprKind::Struct(ref path, ..) => {
|
||||||
// Resolve the path to the structure it goes to. We don't
|
self.resolve_struct_path(expr.id, path);
|
||||||
// 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());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
visit::walk_expr(self, expr);
|
visit::walk_expr(self, expr);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1493,7 +1493,8 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor for DumpVisitor<'l, 'tcx, 'll, D>
|
||||||
Def::StructCtor(..) | Def::VariantCtor(..) |
|
Def::StructCtor(..) | Def::VariantCtor(..) |
|
||||||
Def::Const(..) | Def::AssociatedConst(..) |
|
Def::Const(..) | Def::AssociatedConst(..) |
|
||||||
Def::Struct(..) | Def::Variant(..) |
|
Def::Struct(..) | Def::Variant(..) |
|
||||||
Def::TyAlias(..) | Def::AssociatedTy(..) => {
|
Def::TyAlias(..) | Def::AssociatedTy(..) |
|
||||||
|
Def::SelfTy(..) => {
|
||||||
paths_to_process.push((id, p.clone(), Some(ref_kind)))
|
paths_to_process.push((id, p.clone(), Some(ref_kind)))
|
||||||
}
|
}
|
||||||
def => error!("unexpected definition kind when processing collected paths: {:?}",
|
def => error!("unexpected definition kind when processing collected paths: {:?}",
|
||||||
|
|
|
@ -1484,7 +1484,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
||||||
def: Def,
|
def: Def,
|
||||||
opt_self_ty: Option<Ty<'tcx>>,
|
opt_self_ty: Option<Ty<'tcx>>,
|
||||||
base_path_ref_id: ast::NodeId,
|
base_path_ref_id: ast::NodeId,
|
||||||
base_segments: &[hir::PathSegment])
|
base_segments: &[hir::PathSegment],
|
||||||
|
permit_variants: bool)
|
||||||
-> Ty<'tcx> {
|
-> Ty<'tcx> {
|
||||||
let tcx = self.tcx();
|
let tcx = self.tcx();
|
||||||
|
|
||||||
|
@ -1515,6 +1516,16 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
||||||
did,
|
did,
|
||||||
base_segments.last().unwrap())
|
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) => {
|
Def::TyParam(did) => {
|
||||||
tcx.prohibit_type_params(base_segments);
|
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>>,
|
opt_self_ty: Option<Ty<'tcx>>,
|
||||||
base_path_ref_id: ast::NodeId,
|
base_path_ref_id: ast::NodeId,
|
||||||
base_segments: &[hir::PathSegment],
|
base_segments: &[hir::PathSegment],
|
||||||
assoc_segments: &[hir::PathSegment])
|
assoc_segments: &[hir::PathSegment],
|
||||||
|
permit_variants: bool)
|
||||||
-> (Ty<'tcx>, Def) {
|
-> (Ty<'tcx>, Def) {
|
||||||
// Convert the base type.
|
// Convert the base type.
|
||||||
debug!("finish_resolving_def_to_ty(base_def={:?}, \
|
debug!("finish_resolving_def_to_ty(base_def={:?}, \
|
||||||
|
@ -1619,7 +1631,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
||||||
base_def,
|
base_def,
|
||||||
opt_self_ty,
|
opt_self_ty,
|
||||||
base_path_ref_id,
|
base_path_ref_id,
|
||||||
base_segments);
|
base_segments,
|
||||||
|
permit_variants);
|
||||||
debug!("finish_resolving_def_to_ty: base_def_to_ty returned {:?}", base_ty);
|
debug!("finish_resolving_def_to_ty: base_def_to_ty returned {:?}", base_ty);
|
||||||
|
|
||||||
// If any associated type segments remain, attempt to resolve them.
|
// 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,
|
opt_self_ty,
|
||||||
ast_ty.id,
|
ast_ty.id,
|
||||||
&path.segments[..base_ty_end],
|
&path.segments[..base_ty_end],
|
||||||
&path.segments[base_ty_end..]);
|
&path.segments[base_ty_end..],
|
||||||
|
false);
|
||||||
|
|
||||||
// Write back the new resolution.
|
// Write back the new resolution.
|
||||||
if path_res.depth != 0 {
|
if path_res.depth != 0 {
|
||||||
|
|
|
@ -489,8 +489,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
expected: Ty<'tcx>) -> Ty<'tcx>
|
expected: Ty<'tcx>) -> Ty<'tcx>
|
||||||
{
|
{
|
||||||
// Resolve the path and check the definition for errors.
|
// 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,
|
let (variant, pat_ty) = if let Some(variant_ty) = self.check_struct_path(path, pat.id) {
|
||||||
pat.span) {
|
|
||||||
variant_ty
|
variant_ty
|
||||||
} else {
|
} else {
|
||||||
for field in fields {
|
for field in fields {
|
||||||
|
|
|
@ -1686,41 +1686,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
cause)
|
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) {
|
pub fn write_nil(&self, node_id: ast::NodeId) {
|
||||||
self.write_ty(node_id, self.tcx.mk_nil());
|
self.write_ty(node_id, self.tcx.mk_nil());
|
||||||
}
|
}
|
||||||
|
@ -3252,46 +3217,54 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
|
|
||||||
pub fn check_struct_path(&self,
|
pub fn check_struct_path(&self,
|
||||||
path: &hir::Path,
|
path: &hir::Path,
|
||||||
node_id: ast::NodeId,
|
node_id: ast::NodeId)
|
||||||
span: Span)
|
|
||||||
-> Option<(ty::VariantDef<'tcx>, Ty<'tcx>)> {
|
-> Option<(ty::VariantDef<'tcx>, Ty<'tcx>)> {
|
||||||
let def = self.finish_resolving_struct_path(path, node_id, span);
|
let (def, ty) = self.finish_resolving_struct_path(path, node_id);
|
||||||
let variant = match def {
|
let variant = match def {
|
||||||
Def::Err => {
|
Def::Err => {
|
||||||
self.set_tainted_by_errors();
|
self.set_tainted_by_errors();
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
Def::Variant(did) => {
|
Def::Variant(..) => {
|
||||||
let type_did = self.tcx.parent_def_id(did).unwrap();
|
match ty.sty {
|
||||||
Some((type_did, self.tcx.expect_variant_def(def)))
|
ty::TyAdt(adt, substs) => {
|
||||||
|
Some((adt.variant_of_def(def), adt.did, substs))
|
||||||
}
|
}
|
||||||
Def::Struct(type_did) | Def::Union(type_did) => {
|
_ => bug!("unexpected type: {:?}", ty.sty)
|
||||||
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) {
|
Def::Struct(..) | Def::Union(..) | Def::TyAlias(..) |
|
||||||
Some(&ty::TyAdt(adt, _)) if !adt.is_enum() => {
|
Def::AssociatedTy(..) | Def::SelfTy(..) => {
|
||||||
Some((did, adt.struct_variant()))
|
match ty.sty {
|
||||||
|
ty::TyAdt(adt, substs) if !adt.is_enum() => {
|
||||||
|
Some((adt.struct_variant(), adt.did, substs))
|
||||||
}
|
}
|
||||||
_ => None,
|
_ => 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 &&
|
if variant.ctor_kind == CtorKind::Fn &&
|
||||||
!self.tcx.sess.features.borrow().relaxed_adts {
|
!self.tcx.sess.features.borrow().relaxed_adts {
|
||||||
emit_feature_err(&self.tcx.sess.parse_sess,
|
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");
|
"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))
|
Some((variant, ty))
|
||||||
} else {
|
} else {
|
||||||
struct_span_err!(self.tcx.sess, path.span, E0071,
|
struct_span_err!(self.tcx.sess, path.span, E0071,
|
||||||
"`{}` does not name a struct or a struct variant",
|
"expected struct, variant or union type, found {}",
|
||||||
pprust::path_to_string(path))
|
ty.sort_string(self.tcx))
|
||||||
.span_label(path.span, &format!("not a struct"))
|
.span_label(path.span, &format!("not a struct"))
|
||||||
.emit();
|
.emit();
|
||||||
None
|
None
|
||||||
|
@ -3305,12 +3278,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
base_expr: &'gcx Option<P<hir::Expr>>) -> Ty<'tcx>
|
base_expr: &'gcx Option<P<hir::Expr>>) -> Ty<'tcx>
|
||||||
{
|
{
|
||||||
// Find the relevant variant
|
// Find the relevant variant
|
||||||
let (variant, struct_ty) = if let Some(variant_ty) = self.check_struct_path(path, expr.id,
|
let (variant, struct_ty) = if let Some(variant_ty) = self.check_struct_path(path, expr.id) {
|
||||||
expr.span) {
|
|
||||||
variant_ty
|
variant_ty
|
||||||
} else {
|
} else {
|
||||||
self.check_struct_fields_on_error(fields, base_expr);
|
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,
|
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();
|
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.
|
// Finish resolving a path in a struct expression or pattern `S::A { .. }` if necessary.
|
||||||
// The newly resolved definition is written into `def_map`.
|
// The newly resolved definition is written into `def_map`.
|
||||||
pub fn finish_resolving_struct_path(&self,
|
fn finish_resolving_struct_path(&self,
|
||||||
path: &hir::Path,
|
path: &hir::Path,
|
||||||
node_id: ast::NodeId,
|
node_id: ast::NodeId)
|
||||||
span: Span)
|
-> (Def, Ty<'tcx>)
|
||||||
-> Def
|
|
||||||
{
|
{
|
||||||
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
|
|
||||||
} else {
|
|
||||||
let base_ty_end = path.segments.len() - path_res.depth;
|
let base_ty_end = path.segments.len() - path_res.depth;
|
||||||
let (_ty, def) = AstConv::finish_resolving_def_to_ty(self, self, span,
|
let (ty, def) = AstConv::finish_resolving_def_to_ty(self, self, path.span,
|
||||||
PathParamMode::Optional,
|
PathParamMode::Optional,
|
||||||
path_res.base_def,
|
path_res.base_def,
|
||||||
None,
|
None,
|
||||||
node_id,
|
node_id,
|
||||||
&path.segments[..base_ty_end],
|
&path.segments[..base_ty_end],
|
||||||
&path.segments[base_ty_end..]);
|
&path.segments[base_ty_end..],
|
||||||
|
true);
|
||||||
// Write back the new resolution.
|
// Write back the new resolution.
|
||||||
self.tcx().def_map.borrow_mut().insert(node_id, PathResolution::new(def));
|
if path_res.depth != 0 {
|
||||||
def
|
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.
|
// 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)
|
span: Span)
|
||||||
-> (Def, Option<Ty<'tcx>>, &'b [hir::PathSegment])
|
-> (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 path_res.depth == 0 {
|
||||||
// If fully resolved already, we don't have to do anything.
|
// If fully resolved already, we don't have to do anything.
|
||||||
(path_res.base_def, opt_self_ty, &path.segments)
|
(path_res.base_def, opt_self_ty, &path.segments)
|
||||||
|
@ -3863,7 +3832,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
opt_self_ty,
|
opt_self_ty,
|
||||||
node_id,
|
node_id,
|
||||||
&ty_segments[..base_ty_end],
|
&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.
|
// Resolve an associated constant or method on the previously resolved type.
|
||||||
let item_segment = path.segments.last().unwrap();
|
let item_segment = path.segments.last().unwrap();
|
||||||
|
@ -3883,7 +3853,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Write back the new resolution.
|
// 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))
|
(def, Some(ty), slice::ref_slice(item_segment))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4308,7 +4278,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
// the referenced item.
|
// the referenced item.
|
||||||
let ty_substituted = self.instantiate_type_scheme(span, &substs, &scheme.ty);
|
let ty_substituted = self.instantiate_type_scheme(span, &substs, &scheme.ty);
|
||||||
|
|
||||||
|
|
||||||
if let Some((ty::ImplContainer(impl_def_id), self_ty)) = ufcs_associated {
|
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`
|
// In the case of `Foo<T>::method` and `<Foo<T>>::method`, if `method`
|
||||||
// is inherent, there is no `Self` parameter, instead, the impl needs
|
// is inherent, there is no `Self` parameter, instead, the impl needs
|
||||||
|
|
|
@ -895,17 +895,14 @@ fn some_func(x: &mut i32) {
|
||||||
|
|
||||||
E0071: r##"
|
E0071: r##"
|
||||||
You tried to use structure-literal syntax to create an item that is
|
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:
|
Example of erroneous code:
|
||||||
|
|
||||||
```compile_fail,E0071
|
```compile_fail,E0071
|
||||||
enum Foo { FirstValue(i32) };
|
type U32 = u32;
|
||||||
|
let t = U32 { value: 4 }; // error: expected struct, variant or union type,
|
||||||
let u = Foo::FirstValue { value: 0 }; // error: Foo::FirstValue
|
// found builtin type `u32`
|
||||||
// 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.
|
|
||||||
```
|
```
|
||||||
|
|
||||||
To fix this, ensure that the name was correctly spelled, and that
|
To fix this, ensure that the name was correctly spelled, and that
|
||||||
|
|
|
@ -15,6 +15,6 @@ pub use use_from_trait_xc::Trait;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
match () {
|
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`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,13 +9,10 @@
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
enum Foo {}
|
enum Foo {}
|
||||||
|
type FooAlias = Foo;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let u = Foo { value: 0 };
|
let u = FooAlias { value: 0 };
|
||||||
//~^ ERROR `Foo` does not name a struct or a struct variant [E0071]
|
//~^ ERROR expected struct, variant or union type, found enum `Foo` [E0071]
|
||||||
//~| NOTE not a struct
|
|
||||||
|
|
||||||
let t = u32 { value: 4 };
|
|
||||||
//~^ ERROR `u32` does not name a struct or a struct variant [E0071]
|
|
||||||
//~| NOTE not a struct
|
//~| NOTE not a struct
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,5 +14,6 @@ extern crate namespaced_enums;
|
||||||
fn main() {
|
fn main() {
|
||||||
let _ = namespaced_enums::A; //~ ERROR unresolved name
|
let _ = namespaced_enums::A; //~ ERROR unresolved name
|
||||||
let _ = namespaced_enums::B(10); //~ 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`
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@ pub struct GslResult {
|
||||||
|
|
||||||
impl GslResult {
|
impl GslResult {
|
||||||
pub fn new() -> 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,
|
val: 0f64,
|
||||||
err: 0f64
|
err: 0f64
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,5 +11,5 @@
|
||||||
mod foo {}
|
mod foo {}
|
||||||
|
|
||||||
fn main() {
|
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`
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,6 @@ enum Foo {
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
match Foo::Bar(1) {
|
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`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,5 +13,5 @@ enum SomeEnum {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
E { name: "foobar" }; //~ ERROR `E` does not name a structure
|
E { name: "foobar" }; //~ ERROR unresolved struct, variant or union type `E`
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,5 +11,6 @@
|
||||||
mod MyMod {}
|
mod MyMod {}
|
||||||
|
|
||||||
fn main() {
|
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`
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,6 @@
|
||||||
fn main() {
|
fn main() {
|
||||||
match 'a' {
|
match 'a' {
|
||||||
char{ch} => true
|
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`
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,12 +11,12 @@
|
||||||
mod A {}
|
mod A {}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let u = A { x: 1 }; //~ ERROR `A` 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 `u32` does not name a struct or a struct variant
|
let v = u32 { x: 1 }; //~ ERROR expected struct, variant or union type, found builtin type `u32`
|
||||||
match () {
|
match () {
|
||||||
A { x: 1 } => {}
|
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 } => {}
|
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`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
|
|
||||||
struct T { i: i32 }
|
struct T { i: i32 }
|
||||||
fn f<T>() {
|
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 {
|
mod Foo {
|
||||||
|
|
|
@ -8,8 +8,14 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
|
// issue #36286
|
||||||
|
|
||||||
|
struct S<T: Clone> { a: T }
|
||||||
|
|
||||||
|
struct NoClone;
|
||||||
|
type A = S<NoClone>;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let x = Foo { x: 1, y: 2 };
|
let s = A { a: NoClone };
|
||||||
//~^ ERROR E0422
|
//~^ ERROR the trait bound `NoClone: std::clone::Clone` is not satisfied
|
||||||
//~| NOTE not a structure
|
|
||||||
}
|
}
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
|
@ -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() {}
|
|
@ -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() {}
|
|
@ -12,6 +12,5 @@ trait TraitNotAStruct {}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
TraitNotAStruct{ value: 0 };
|
TraitNotAStruct{ value: 0 };
|
||||||
//~^ ERROR: `TraitNotAStruct` does not name a struct or a struct variant [E0071]
|
//~^ ERROR expected struct, variant or union type, found trait `TraitNotAStruct`
|
||||||
//~| NOTE not a struct
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,4 +51,10 @@ fn main() {
|
||||||
if let None::<u8> = Some(8) {
|
if let None::<u8> = Some(8) {
|
||||||
panic!();
|
panic!();
|
||||||
}
|
}
|
||||||
|
if let None::<u8> { .. } = Some(8) {
|
||||||
|
panic!();
|
||||||
|
}
|
||||||
|
if let Option::None::<u8> { .. } = Some(8) {
|
||||||
|
panic!();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,30 +8,28 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
struct S;
|
struct S<T, U = u16> {
|
||||||
|
a: T,
|
||||||
|
b: U,
|
||||||
|
}
|
||||||
|
|
||||||
trait Tr {
|
trait Tr {
|
||||||
type A;
|
type A;
|
||||||
}
|
}
|
||||||
|
impl Tr for u8 {
|
||||||
impl Tr for S {
|
type A = S<u8, u16>;
|
||||||
type A = S;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn f<T: Tr>() {
|
fn f<T: Tr<A = S<u8>>>() {
|
||||||
match S {
|
let s = T::A { a: 0, b: 1 };
|
||||||
T::A {} => {} //~ ERROR `T::A` does not name a struct or a struct variant
|
match s {
|
||||||
|
T::A { a, b } => {
|
||||||
|
assert_eq!(a, 0);
|
||||||
|
assert_eq!(b, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn g<T: Tr<A = S>>() {
|
|
||||||
match S {
|
|
||||||
T::A {} => {} //~ ERROR `T::A` does not name a struct or a struct variant
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
match S {
|
f::<u8>();
|
||||||
S::A {} => {} //~ ERROR ambiguous associated type
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -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);
|
||||||
|
}
|
Loading…
Reference in New Issue