Preparations and cleanup
Diagnostics for struct path resolution errors in resolve and typeck are unified. Self type is treated as a type alias in few places (not reachable yet). Unsafe cell is seen in constants even through type aliases. All checks for struct paths in typeck work on type level.
This commit is contained in:
parent
07436946b6
commit
a9f91b1b0e
@ -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);
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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};
|
||||
@ -802,6 +802,34 @@ impl<'tcx> fmt::Display for ty::TraitRef<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ty::TypeVariants<'tcx> {
|
||||
pub fn descr(&self) -> &'static str {
|
||||
match *self {
|
||||
TyInt(..) | TyUint(..) | TyFloat(..) |
|
||||
TyBool | TyChar | TyStr => "builtin type",
|
||||
TyRawPtr(..) => "pointer",
|
||||
TyRef(..) => "reference",
|
||||
TyTuple(..) => "tuple",
|
||||
TyFnDef(..) => "function type",
|
||||
TyFnPtr(..) => "function pointer",
|
||||
TyArray(..) => "array",
|
||||
TySlice(..) => "slice",
|
||||
TyParam(..) => "type parameter",
|
||||
TyProjection(..) => "associated type",
|
||||
TyTrait(..) => "trait type",
|
||||
TyClosure(..) => "closure type",
|
||||
TyBox(..) => "struct",
|
||||
TyAdt(def, ..) => match def.adt_kind() {
|
||||
ty::AdtKind::Struct => "struct",
|
||||
ty::AdtKind::Union => "union",
|
||||
ty::AdtKind::Enum => "enum",
|
||||
},
|
||||
TyInfer(..) | TyAnon(..) |
|
||||
TyNever | TyError => "type",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> fmt::Display for ty::TypeVariants<'tcx> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
@ -879,8 +907,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.
|
||||
|
@ -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 @@ 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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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: {:?}",
|
||||
|
@ -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,22 @@ 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);
|
||||
let mut ty = self.ast_path_to_ty(rscope,
|
||||
span,
|
||||
param_mode,
|
||||
tcx.parent_def_id(did).unwrap(),
|
||||
base_segments.last().unwrap());
|
||||
if ty.is_fn() {
|
||||
// Tuple variants have fn type even in type namespace,
|
||||
// extract true variant type from it.
|
||||
ty = tcx.no_late_bound_regions(&ty.fn_ret()).unwrap();
|
||||
}
|
||||
ty
|
||||
}
|
||||
Def::TyParam(did) => {
|
||||
tcx.prohibit_type_params(base_segments);
|
||||
|
||||
@ -1604,7 +1621,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 +1637,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 +1794,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 {
|
||||
|
@ -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 {
|
||||
|
@ -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());
|
||||
}
|
||||
@ -3252,46 +3217,56 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
|
||||
pub fn check_struct_path(&self,
|
||||
path: &hir::Path,
|
||||
node_id: ast::NodeId,
|
||||
span: Span)
|
||||
node_id: ast::NodeId)
|
||||
-> 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 {
|
||||
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(..) => {
|
||||
match ty.sty {
|
||||
ty::TyAdt(adt, substs) if !adt.is_enum() => {
|
||||
Some((adt.struct_variant(), adt.did, substs))
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
_ => None
|
||||
// Self is not supported yet.
|
||||
Def::SelfTy(..) => 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.sty.descr(), ty)
|
||||
.span_label(path.span, &format!("not a struct"))
|
||||
.emit();
|
||||
None
|
||||
@ -3305,12 +3280,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 +3779,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
}
|
||||
err.emit();
|
||||
self.tcx().types.err
|
||||
self.tcx.types.err
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3815,29 +3789,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 +3820,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 +3834,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 +3855,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 +4280,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
|
||||
|
@ -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 @@ 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`
|
||||
}
|
||||
}
|
||||
|
@ -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 @@ 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`
|
||||
}
|
||||
|
@ -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 `<T as Tr>::A`
|
||||
let z = T::A::<u8> {};
|
||||
//~^ ERROR expected struct, variant or union type, found associated type `<T as Tr>::A`
|
||||
//~| ERROR type parameters are not allowed on this type
|
||||
match S {
|
||||
T::A {} => {}
|
||||
//~^ ERROR expected struct, variant or union type, found associated type `<T as Tr>::A`
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
@ -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,7 @@ fn main() {
|
||||
if let None::<u8> = Some(8) {
|
||||
panic!();
|
||||
}
|
||||
if let 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>();
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user