mirror of
https://github.com/rust-lang/rust
synced 2024-09-15 22:50:55 +00:00
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 @@ fn walk_pat(&mut self, cmt_discr: mc::cmt<'tcx>, pat: &hir::Pat, match_mode: Mat
|
|||
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);
|
||||
}
|
||||
|
|
|
@ -1698,7 +1698,7 @@ pub fn variant_of_def(&self, def: Def) -> &VariantDefData<'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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
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 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|||
})
|
||||
}
|
||||
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.
|
||||
|
|
|
@ -436,7 +436,7 @@ fn lower_variant_or_leaf(
|
|||
}
|
||||
|
||||
Def::Struct(..) | Def::StructCtor(..) | Def::Union(..) |
|
||||
Def::TyAlias(..) | Def::AssociatedTy(..) => {
|
||||
Def::TyAlias(..) | Def::AssociatedTy(..) | Def::SelfTy(..) => {
|
||||
PatternKind::Leaf { subpatterns: subpatterns }
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -860,31 +860,6 @@ fn foo(f: i32, g: i32) {} // ok!
|
|||
```
|
||||
"##,
|
||||
|
||||
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 @@ macro_rules! drink {
|
|||
// 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
|
||||
|
|
|
@ -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 @@ fn resolve_pattern_path<ExpectedFn>(&mut self,
|
|||
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 @@ fn resolve_pattern(&mut self,
|
|||
}
|
||||
|
||||
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 @@ fn resolve_expr(&mut self, expr: &Expr, parent: Option<&Expr>) {
|
|||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -1493,7 +1493,8 @@ fn visit_arm(&mut self, arm: &ast::Arm) {
|
|||
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: {:?}",
|
||||
|
|
|
@ -1484,7 +1484,8 @@ fn base_def_to_ty(&self,
|
|||
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 @@ fn base_def_to_ty(&self,
|
|||
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 @@ pub fn finish_resolving_def_to_ty(&self,
|
|||
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 @@ pub fn finish_resolving_def_to_ty(&self,
|
|||
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 @@ pub fn ast_ty_to_ty(&self, rscope: &RegionScope, ast_ty: &hir::Ty) -> Ty<'tcx> {
|
|||
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 {
|
||||
|
|
|
@ -489,8 +489,7 @@ fn check_pat_struct(&self,
|
|||
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 {
|
||||
|
|
|
@ -1686,41 +1686,6 @@ fn normalize_associated_type(&self,
|
|||
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 @@ fn check_struct_fields_on_error(&self,
|
|||
}
|
||||
|
||||
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 @@ fn check_expr_struct(&self,
|
|||
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 @@ fn check_expr_kind(&self,
|
|||
}
|
||||
}
|
||||
err.emit();
|
||||
self.tcx().types.err
|
||||
self.tcx.types.err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3815,29 +3787,26 @@ fn check_expr_kind(&self,
|
|||
|
||||
// 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 @@ pub fn resolve_ty_and_def_ufcs<'b>(&self,
|
|||
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 @@ pub fn resolve_ty_and_def_ufcs<'b>(&self,
|
|||
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 @@ pub fn resolve_ty_and_def_ufcs<'b>(&self,
|
|||
};
|
||||
|
||||
// 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 @@ pub fn instantiate_value_path(&self,
|
|||
// 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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -15,6 +15,6 @@
|
|||
|
||||
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`
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -14,5 +14,6 @@
|
|||
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`
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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`
|
||||
}
|
||||
|
|
|
@ -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`
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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`
|
||||
}
|
||||
|
|
|
@ -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`
|
||||
}
|
||||
|
|
|
@ -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`
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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`
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
}
|
48
src/test/compile-fail/struct-path-associated-type.rs
Normal file
48
src/test/compile-fail/struct-path-associated-type.rs
Normal 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
|
||||
}
|
||||
}
|
38
src/test/compile-fail/struct-path-self-type-mismatch.rs
Normal file
38
src/test/compile-fail/struct-path-self-type-mismatch.rs
Normal 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() {}
|
47
src/test/compile-fail/struct-path-self.rs
Normal file
47
src/test/compile-fail/struct-path-self.rs
Normal 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() {}
|
|
@ -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`
|
||||
}
|
||||
|
|
|
@ -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!();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>();
|
||||
}
|
54
src/test/run-pass/struct-path-self.rs
Normal file
54
src/test/run-pass/struct-path-self.rs
Normal 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);
|
||||
}
|
Loading…
Reference in a new issue