Auto merge of #34365 - petrochenkov:deferr, r=eddyb

Some more pattern cleanup and bugfixing

The next part of https://github.com/rust-lang/rust/pull/34095

The most significant fixed mistake is definitions for partially resolved associated types not being updated after full resolution.
```
fn f<T: Fn()>(arg: T::Output) { .... } // <- the definition of T::Output was not updated in def_map
```
For this reason unstable associated types of stable traits, like `FnOnce::Output`, could be used in stable code when written in unqualified form. Now they are properly checked, this is a **[breaking-change]** (pretty minor one, but a crater run would be nice). The fix is not to use unstable library features in stable code, alternatively `FnOnce::Output` can be stabilized.

Besides that, paths in struct patterns and expressions `S::A { .. }` are now fully resolved as associated types. Such types cannot be identified as structs at the moment, i.e. the change doesn't make previously invalid code valid, but it improves error diagnostics.

Other changes: `Def::Err` is supported better (less chances for ICEs for erroneous code), some incorrect error messages are corrected, some duplicated error messages are not reported, ADT definitions are now available through constructor IDs, everything else is cleanup and code audit.

Fixes https://github.com/rust-lang/rust/issues/34209
Closes https://github.com/rust-lang/rust/issues/22933 (adds tests)

r? @eddyb
This commit is contained in:
bors 2016-07-09 15:16:21 -07:00 committed by GitHub
commit f93aaf84cb
53 changed files with 657 additions and 829 deletions

View File

@ -1929,7 +1929,7 @@ pub trait FnMut<Args> : FnOnce<Args> {
#[fundamental] // so that regex can rely that `&str: !FnMut`
pub trait FnOnce<Args> {
/// The returned type after the call operator is used.
#[unstable(feature = "fn_traits", issue = "29625")]
#[stable(feature = "fn_once_output", since = "1.12.0")]
type Output;
/// This is called when the call operator is used.

View File

@ -101,7 +101,6 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
match pat.node {
PatKind::Binding(_, _, None) |
PatKind::Path(..) |
PatKind::QPath(..) |
PatKind::Lit(..) |
PatKind::Range(..) |
PatKind::Wild => {

View File

@ -137,15 +137,6 @@ impl Def {
}
}
pub fn variant_def_ids(&self) -> Option<(DefId, DefId)> {
match *self {
Def::Variant(enum_id, var_id) => {
Some((enum_id, var_id))
}
_ => None
}
}
pub fn kind_name(&self) -> &'static str {
match *self {
Def::Fn(..) => "function",

View File

@ -930,12 +930,11 @@ pub fn noop_fold_pat<T: Folder>(p: P<Pat>, folder: &mut T) -> P<Pat> {
PatKind::TupleStruct(folder.fold_path(pth),
pats.move_map(|x| folder.fold_pat(x)), ddpos)
}
PatKind::Path(pth) => {
PatKind::Path(folder.fold_path(pth))
}
PatKind::QPath(qself, pth) => {
let qself = QSelf { ty: folder.fold_ty(qself.ty), ..qself };
PatKind::QPath(qself, folder.fold_path(pth))
PatKind::Path(opt_qself, pth) => {
let opt_qself = opt_qself.map(|qself| {
QSelf { ty: folder.fold_ty(qself.ty), position: qself.position }
});
PatKind::Path(opt_qself, folder.fold_path(pth))
}
PatKind::Struct(pth, fields, etc) => {
let pth = folder.fold_path(pth);

View File

@ -460,11 +460,10 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat) {
visitor.visit_path(path, pattern.id);
walk_list!(visitor, visit_pat, children);
}
PatKind::Path(ref path) => {
visitor.visit_path(path, pattern.id);
}
PatKind::QPath(ref qself, ref path) => {
visitor.visit_ty(&qself.ty);
PatKind::Path(ref opt_qself, ref path) => {
if let Some(ref qself) = *opt_qself {
visitor.visit_ty(&qself.ty);
}
visitor.visit_path(path, pattern.id)
}
PatKind::Struct(ref path, ref fields, _) => {

View File

@ -862,7 +862,8 @@ impl<'a> LoweringContext<'a> {
respan(pth1.span, pth1.node.name),
sub.as_ref().map(|x| this.lower_pat(x)))
}
_ => hir::PatKind::Path(hir::Path::from_name(pth1.span, pth1.node.name))
_ => hir::PatKind::Path(None, hir::Path::from_name(pth1.span,
pth1.node.name))
}
})
}
@ -872,15 +873,11 @@ impl<'a> LoweringContext<'a> {
pats.iter().map(|x| self.lower_pat(x)).collect(),
ddpos)
}
PatKind::Path(None, ref pth) => {
hir::PatKind::Path(self.lower_path(pth))
}
PatKind::Path(Some(ref qself), ref pth) => {
let qself = hir::QSelf {
ty: self.lower_ty(&qself.ty),
position: qself.position,
};
hir::PatKind::QPath(qself, self.lower_path(pth))
PatKind::Path(ref opt_qself, ref path) => {
let opt_qself = opt_qself.as_ref().map(|qself| {
hir::QSelf { ty: self.lower_ty(&qself.ty), position: qself.position }
});
hir::PatKind::Path(opt_qself, self.lower_path(path))
}
PatKind::Struct(ref pth, ref fields, etc) => {
let pth = self.lower_path(pth);
@ -1831,7 +1828,7 @@ impl<'a> LoweringContext<'a> {
-> P<hir::Pat> {
let def = self.resolver.resolve_generated_global_path(&path, true);
let pt = if subpats.is_empty() {
hir::PatKind::Path(path)
hir::PatKind::Path(None, path)
} else {
hir::PatKind::TupleStruct(path, subpats, None)
};

View File

@ -487,8 +487,7 @@ impl Pat {
PatKind::Lit(_) |
PatKind::Range(_, _) |
PatKind::Binding(..) |
PatKind::Path(..) |
PatKind::QPath(_, _) => {
PatKind::Path(..) => {
true
}
}
@ -538,15 +537,9 @@ pub enum PatKind {
/// 0 <= position <= subpats.len()
TupleStruct(Path, HirVec<P<Pat>>, Option<usize>),
/// A path pattern.
/// A possibly qualified path pattern.
/// Such pattern can be resolved to a unit struct/variant or a constant.
Path(Path),
/// An associated const named using the qualified path `<T>::CONST` or
/// `<T as Trait>::CONST`. Associated consts from inherent impls can be
/// referred to as simply `T::CONST`, in which case they will end up as
/// PatKind::Path, and the resolver will have to sort that out.
QPath(QSelf, Path),
Path(Option<QSelf>, Path),
/// A tuple pattern `(a, b)`.
/// If the `..` pattern fragment is present, then `Option<usize>` denotes its position.

View File

@ -12,15 +12,12 @@ use hir::def::*;
use hir::def_id::DefId;
use hir::{self, PatKind};
use ty::TyCtxt;
use util::nodemap::FnvHashMap;
use syntax::ast;
use syntax::codemap::Spanned;
use syntax_pos::{Span, DUMMY_SP};
use std::iter::{Enumerate, ExactSizeIterator};
pub type PatIdMap = FnvHashMap<ast::Name, ast::NodeId>;
pub struct EnumerateAndAdjust<I> {
enumerate: Enumerate<I>,
gap_pos: usize,
@ -56,7 +53,7 @@ impl<T: ExactSizeIterator> EnumerateAndAdjustIterator for T {
pub fn pat_is_refutable(dm: &DefMap, pat: &hir::Pat) -> bool {
match pat.node {
PatKind::Lit(_) | PatKind::Range(_, _) | PatKind::QPath(..) => true,
PatKind::Lit(_) | PatKind::Range(_, _) | PatKind::Path(Some(..), _) => true,
PatKind::TupleStruct(..) |
PatKind::Path(..) |
PatKind::Struct(..) => {
@ -70,23 +67,9 @@ pub fn pat_is_refutable(dm: &DefMap, pat: &hir::Pat) -> bool {
}
}
pub fn pat_is_variant_or_struct(dm: &DefMap, pat: &hir::Pat) -> bool {
match pat.node {
PatKind::TupleStruct(..) |
PatKind::Path(..) |
PatKind::Struct(..) => {
match dm.get(&pat.id).map(|d| d.full_def()) {
Some(Def::Variant(..)) | Some(Def::Struct(..)) | Some(Def::TyAlias(..)) => true,
_ => false
}
}
_ => false
}
}
pub fn pat_is_const(dm: &DefMap, pat: &hir::Pat) -> bool {
match pat.node {
PatKind::Path(..) | PatKind::QPath(..) => {
PatKind::Path(..) => {
match dm.get(&pat.id).map(|d| d.full_def()) {
Some(Def::Const(..)) | Some(Def::AssociatedConst(..)) => true,
_ => false
@ -96,22 +79,6 @@ pub fn pat_is_const(dm: &DefMap, pat: &hir::Pat) -> bool {
}
}
// Same as above, except that partially-resolved defs cause `false` to be
// returned instead of a panic.
pub fn pat_is_resolved_const(dm: &DefMap, pat: &hir::Pat) -> bool {
match pat.node {
PatKind::Path(..) | PatKind::QPath(..) => {
match dm.get(&pat.id)
.and_then(|d| if d.depth == 0 { Some(d.base_def) }
else { None } ) {
Some(Def::Const(..)) | Some(Def::AssociatedConst(..)) => true,
_ => false
}
}
_ => false
}
}
/// Call `f` on every "binding" in a pattern, e.g., on `a` in
/// `match foo() { Some(a) => (), None => () }`
pub fn pat_bindings<F>(pat: &hir::Pat, mut f: F)

View File

@ -1750,10 +1750,10 @@ impl<'a> State<'a> {
}
try!(self.pclose());
}
PatKind::Path(ref path) => {
PatKind::Path(None, ref path) => {
self.print_path(path, true, 0)?;
}
PatKind::QPath(ref qself, ref path) => {
PatKind::Path(Some(ref qself), ref path) => {
self.print_qpath(path, qself, false)?;
}
PatKind::Struct(ref path, ref fields, etc) => {

View File

@ -945,52 +945,41 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
/// The core driver for walking a pattern; `match_mode` must be
/// established up front, e.g. via `determine_pat_move_mode` (see
/// also `walk_irrefutable_pat` for patterns that stand alone).
fn walk_pat(&mut self,
cmt_discr: mc::cmt<'tcx>,
pat: &hir::Pat,
match_mode: MatchMode) {
debug!("walk_pat cmt_discr={:?} pat={:?}", cmt_discr,
pat);
fn walk_pat(&mut self, cmt_discr: mc::cmt<'tcx>, pat: &hir::Pat, match_mode: MatchMode) {
debug!("walk_pat cmt_discr={:?} pat={:?}", cmt_discr, pat);
let tcx = &self.tcx();
let mc = &self.mc;
let infcx = self.mc.infcx;
let delegate = &mut self.delegate;
return_if_err!(mc.cat_pattern(cmt_discr.clone(), pat, |mc, cmt_pat, pat| {
match pat.node {
PatKind::Binding(bmode, _, _) => {
debug!("binding cmt_pat={:?} pat={:?} match_mode={:?}",
cmt_pat,
pat,
match_mode);
if let PatKind::Binding(bmode, _, _) = pat.node {
debug!("binding cmt_pat={:?} pat={:?} match_mode={:?}", cmt_pat, pat, match_mode);
// pat_ty: the type of the binding being produced.
let pat_ty = return_if_err!(infcx.node_ty(pat.id));
// pat_ty: the type of the binding being produced.
let pat_ty = return_if_err!(infcx.node_ty(pat.id));
// Each match binding is effectively an assignment to the
// binding being produced.
if let Ok(binding_cmt) = mc.cat_def(pat.id, pat.span, pat_ty,
tcx.expect_def(pat.id)) {
delegate.mutate(pat.id, pat.span, binding_cmt, MutateMode::Init);
// Each match binding is effectively an assignment to the
// binding being produced.
if let Ok(binding_cmt) = mc.cat_def(pat.id, pat.span, pat_ty,
tcx.expect_def(pat.id)) {
delegate.mutate(pat.id, pat.span, binding_cmt, MutateMode::Init);
}
// It is also a borrow or copy/move of the value being matched.
match bmode {
hir::BindByRef(m) => {
if let ty::TyRef(&r, _) = pat_ty.sty {
let bk = ty::BorrowKind::from_mutbl(m);
delegate.borrow(pat.id, pat.span, cmt_pat, r, bk, RefBinding);
}
}
// It is also a borrow or copy/move of the value being matched.
match bmode {
hir::BindByRef(m) => {
if let ty::TyRef(&r, _) = pat_ty.sty {
let bk = ty::BorrowKind::from_mutbl(m);
delegate.borrow(pat.id, pat.span, cmt_pat,
r, bk, RefBinding);
}
}
hir::BindByValue(..) => {
let mode = copy_or_move(infcx, &cmt_pat, PatBindingMove);
debug!("walk_pat binding consuming pat");
delegate.consume_pat(pat, cmt_pat, mode);
}
hir::BindByValue(..) => {
let mode = copy_or_move(infcx, &cmt_pat, PatBindingMove);
debug!("walk_pat binding consuming pat");
delegate.consume_pat(pat, cmt_pat, mode);
}
}
_ => {}
}
}));
@ -999,72 +988,23 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
// to the above loop's visit of than the bindings that form
// the leaves of the pattern tree structure.
return_if_err!(mc.cat_pattern(cmt_discr, pat, |mc, cmt_pat, pat| {
match pat.node {
PatKind::Struct(..) | PatKind::TupleStruct(..) |
PatKind::Path(..) | PatKind::QPath(..) => {
match tcx.expect_def(pat.id) {
Def::Variant(enum_did, variant_did) => {
let downcast_cmt =
if tcx.lookup_adt_def(enum_did).is_univariant() {
cmt_pat
} else {
let cmt_pat_ty = cmt_pat.ty;
mc.cat_downcast(pat, cmt_pat, cmt_pat_ty, variant_did)
};
match tcx.expect_def_or_none(pat.id) {
Some(Def::Variant(enum_did, variant_did)) => {
let downcast_cmt = if tcx.lookup_adt_def(enum_did).is_univariant() {
cmt_pat
} else {
let cmt_pat_ty = cmt_pat.ty;
mc.cat_downcast(pat, cmt_pat, cmt_pat_ty, variant_did)
};
debug!("variant downcast_cmt={:?} pat={:?}",
downcast_cmt,
pat);
delegate.matched_pat(pat, downcast_cmt, match_mode);
}
Def::Struct(..) | Def::TyAlias(..) => {
// A struct (in either the value or type
// namespace; we encounter the former on
// e.g. patterns for unit structs).
debug!("struct cmt_pat={:?} pat={:?}",
cmt_pat,
pat);
delegate.matched_pat(pat, cmt_pat, match_mode);
}
Def::Const(..) | Def::AssociatedConst(..) => {
// This is a leaf (i.e. identifier binding
// or constant value to match); thus no
// `matched_pat` call.
}
def => {
// An enum type should never be in a pattern.
// Remaining cases are e.g. Def::Fn, to
// which identifiers within patterns
// should not resolve. However, we do
// encouter this when using the
// expr-use-visitor during typeck. So just
// ignore it, an error should have been
// reported.
if !tcx.sess.has_errors() {
span_bug!(pat.span,
"Pattern has unexpected def: {:?} and type {:?}",
def,
cmt_pat.ty);
}
}
}
debug!("variant downcast_cmt={:?} pat={:?}", downcast_cmt, pat);
delegate.matched_pat(pat, downcast_cmt, match_mode);
}
PatKind::Wild | PatKind::Tuple(..) | PatKind::Box(..) |
PatKind::Ref(..) | PatKind::Lit(..) | PatKind::Range(..) |
PatKind::Vec(..) | PatKind::Binding(..) => {
// Each of these cases does not
// correspond to an enum variant or struct, so we
// do not do any `matched_pat` calls for these
// cases either.
Some(Def::Struct(..)) | Some(Def::TyAlias(..)) | Some(Def::AssociatedTy(..)) => {
debug!("struct cmt_pat={:?} pat={:?}", cmt_pat, pat);
delegate.matched_pat(pat, cmt_pat, match_mode);
}
_ => {}
}
}));
}

View File

@ -1050,9 +1050,8 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
}
// FIXME(#19596) This is a workaround, but there should be a better way to do this
fn cat_pattern_<F>(&self, cmt: cmt<'tcx>, pat: &hir::Pat, op: &mut F)
-> McResult<()>
where F : FnMut(&MemCategorizationContext<'a, 'gcx, 'tcx>, cmt<'tcx>, &hir::Pat),
fn cat_pattern_<F>(&self, cmt: cmt<'tcx>, pat: &hir::Pat, op: &mut F) -> McResult<()>
where F : FnMut(&MemCategorizationContext<'a, 'gcx, 'tcx>, cmt<'tcx>, &hir::Pat)
{
// Here, `cmt` is the categorization for the value being
// matched and pat is the pattern it is being matched against.
@ -1099,21 +1098,14 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
// step out of sync again. So you'll see below that we always
// get the type of the *subpattern* and use that.
debug!("cat_pattern: {:?} cmt={:?}",
pat,
cmt);
debug!("cat_pattern: {:?} cmt={:?}", pat, cmt);
(*op)(self, cmt.clone(), pat);
let opt_def = self.tcx().expect_def_or_none(pat.id);
if opt_def == Some(Def::Err) {
return Err(());
}
op(self, cmt.clone(), pat);
// Note: This goes up here (rather than within the PatKind::TupleStruct arm
// alone) because struct patterns can refer to struct types or
// to struct variants within enums.
let cmt = match opt_def {
// alone) because PatKind::Struct can also refer to variants.
let cmt = match self.tcx().expect_def_or_none(pat.id) {
Some(Def::Err) => return Err(()),
Some(Def::Variant(enum_did, variant_did))
// univariant enums do not need downcasts
if !self.tcx().lookup_adt_def(enum_did).is_univariant() => {
@ -1123,68 +1115,35 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
};
match pat.node {
PatKind::Wild => {
// _
}
PatKind::TupleStruct(_, ref subpats, ddpos) => {
match opt_def {
Some(Def::Variant(enum_def, def_id)) => {
// variant(x, y, z)
let expected_len = self.tcx().lookup_adt_def(enum_def)
.variant_with_id(def_id).fields.len();
for (i, subpat) in subpats.iter().enumerate_and_adjust(expected_len, ddpos) {
let subpat_ty = self.pat_ty(&subpat)?; // see (*2)
let subcmt =
self.cat_imm_interior(
pat, cmt.clone(), subpat_ty,
InteriorField(PositionalField(i)));
self.cat_pattern_(subcmt, &subpat, op)?;
}
let expected_len = match self.tcx().expect_def(pat.id) {
Def::Variant(enum_def, def_id) => {
self.tcx().lookup_adt_def(enum_def).variant_with_id(def_id).fields.len()
}
Some(Def::Struct(..)) => {
let expected_len = match self.pat_ty(&pat)?.sty {
Def::Struct(..) => {
match self.pat_ty(&pat)?.sty {
ty::TyStruct(adt_def, _) => {
adt_def.struct_variant().fields.len()
}
ref ty => {
span_bug!(pat.span, "tuple struct pattern unexpected type {:?}", ty);
}
};
}
}
def => {
span_bug!(pat.span, "tuple struct pattern didn't resolve \
to variant or struct {:?}", def);
}
};
for (i, subpat) in subpats.iter().enumerate_and_adjust(expected_len, ddpos) {
let subpat_ty = self.pat_ty(&subpat)?; // see (*2)
let cmt_field =
self.cat_imm_interior(
pat, cmt.clone(), subpat_ty,
InteriorField(PositionalField(i)));
self.cat_pattern_(cmt_field, &subpat, op)?;
}
}
Some(Def::Const(..)) | Some(Def::AssociatedConst(..)) => {
for subpat in subpats {
self.cat_pattern_(cmt.clone(), &subpat, op)?;
}
}
_ => {
span_bug!(
pat.span,
"enum pattern didn't resolve to enum or struct {:?}",
opt_def);
}
for (i, subpat) in subpats.iter().enumerate_and_adjust(expected_len, ddpos) {
let subpat_ty = self.pat_ty(&subpat)?; // see (*2)
let subcmt = self.cat_imm_interior(pat, cmt.clone(), subpat_ty,
InteriorField(PositionalField(i)));
self.cat_pattern_(subcmt, &subpat, op)?;
}
}
PatKind::Path(..) | PatKind::QPath(..) | PatKind::Binding(_, _, None) => {
// Lone constant, or unit variant or identifier: ignore
}
PatKind::Binding(_, _, Some(ref subpat)) => {
self.cat_pattern_(cmt, &subpat, op)?;
}
PatKind::Struct(_, ref field_pats, _) => {
// {f1: p1, ..., fN: pN}
for fp in field_pats {
@ -1194,6 +1153,10 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
}
}
PatKind::Binding(_, _, Some(ref subpat)) => {
self.cat_pattern_(cmt, &subpat, op)?;
}
PatKind::Tuple(ref subpats, ddpos) => {
// (p1, ..., pN)
let expected_len = match self.pat_ty(&pat)?.sty {
@ -1202,10 +1165,8 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
};
for (i, subpat) in subpats.iter().enumerate_and_adjust(expected_len, ddpos) {
let subpat_ty = self.pat_ty(&subpat)?; // see (*2)
let subcmt =
self.cat_imm_interior(
pat, cmt.clone(), subpat_ty,
InteriorField(PositionalField(i)));
let subcmt = self.cat_imm_interior(pat, cmt.clone(), subpat_ty,
InteriorField(PositionalField(i)));
self.cat_pattern_(subcmt, &subpat, op)?;
}
}
@ -1215,25 +1176,26 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
// PatKind::Ref since that information is already contained
// in the type.
let subcmt = self.cat_deref(pat, cmt, 0, None)?;
self.cat_pattern_(subcmt, &subpat, op)?;
self.cat_pattern_(subcmt, &subpat, op)?;
}
PatKind::Vec(ref before, ref slice, ref after) => {
let context = InteriorOffsetKind::Pattern;
let elt_cmt = self.cat_index(pat, cmt, context)?;
for before_pat in before {
self.cat_pattern_(elt_cmt.clone(), &before_pat, op)?;
}
if let Some(ref slice_pat) = *slice {
self.cat_pattern_(elt_cmt.clone(), &slice_pat, op)?;
}
for after_pat in after {
self.cat_pattern_(elt_cmt.clone(), &after_pat, op)?;
}
let context = InteriorOffsetKind::Pattern;
let elt_cmt = self.cat_index(pat, cmt, context)?;
for before_pat in before {
self.cat_pattern_(elt_cmt.clone(), &before_pat, op)?;
}
if let Some(ref slice_pat) = *slice {
self.cat_pattern_(elt_cmt.clone(), &slice_pat, op)?;
}
for after_pat in after {
self.cat_pattern_(elt_cmt.clone(), &after_pat, op)?;
}
}
PatKind::Lit(_) | PatKind::Range(_, _) => {
/*always ok*/
PatKind::Path(..) | PatKind::Binding(_, _, None) |
PatKind::Lit(..) | PatKind::Range(..) | PatKind::Wild => {
// always ok
}
}

View File

@ -1063,7 +1063,7 @@ impl<'tcx> Debug for Rvalue<'tcx> {
Some(tcx.lookup_item_type(variant_def.did).generics)
})?;
match variant_def.kind() {
match variant_def.kind {
ty::VariantKind::Unit => Ok(()),
ty::VariantKind::Tuple => fmt_tuple(fmt, lvs),
ty::VariantKind::Struct => {

View File

@ -591,6 +591,13 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
self.global_interners.arenas.trait_defs.alloc(def)
}
pub fn insert_adt_def(self, did: DefId, adt_def: ty::AdtDefMaster<'gcx>) {
// this will need a transmute when reverse-variance is removed
if let Some(prev) = self.adt_defs.borrow_mut().insert(did, adt_def) {
bug!("Tried to overwrite interned AdtDef: {:?}", prev)
}
}
pub fn intern_adt_def(self,
did: DefId,
kind: ty::AdtKind,
@ -598,10 +605,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
-> ty::AdtDefMaster<'gcx> {
let def = ty::AdtDefData::new(self, did, kind, variants);
let interned = self.global_interners.arenas.adt_defs.alloc(def);
// this will need a transmute when reverse-variance is removed
if let Some(prev) = self.adt_defs.borrow_mut().insert(did, interned) {
bug!("Tried to overwrite interned AdtDef: {:?}", prev)
}
self.insert_adt_def(did, interned);
interned
}

View File

@ -1715,7 +1715,7 @@ impl<'a, 'gcx, 'tcx, 'container> AdtDefData<'gcx, 'container> {
pub fn variant_of_def(&self, def: Def) -> &VariantDefData<'gcx, 'container> {
match def {
Def::Variant(_, vid) => self.variant_with_id(vid),
Def::Struct(..) | Def::TyAlias(..) => self.struct_variant(),
Def::Struct(..) | Def::TyAlias(..) | Def::AssociatedTy(..) => self.struct_variant(),
_ => bug!("unexpected def {:?} in variant_of_def", def)
}
}
@ -1925,14 +1925,6 @@ impl<'tcx, 'container> VariantDefData<'tcx, 'container> {
self.fields.iter()
}
pub fn kind(&self) -> VariantKind {
self.kind
}
pub fn is_tuple_struct(&self) -> bool {
self.kind() == VariantKind::Tuple
}
#[inline]
pub fn find_field_named(&self,
name: ast::Name)
@ -2454,6 +2446,20 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
self.def_map.borrow().get(&id).map(|resolution| resolution.full_def())
}
// Returns `ty::VariantDef` if `def` refers to a struct,
// or variant or their constructors, panics otherwise.
pub fn expect_variant_def(self, def: Def) -> VariantDef<'tcx> {
match def {
Def::Variant(enum_did, did) => {
self.lookup_adt_def(enum_did).variant_with_id(did)
}
Def::Struct(did) => {
self.lookup_adt_def(did).struct_variant()
}
_ => bug!("expect_variant_def used with unexpected def {:?}", def)
}
}
pub fn def_key(self, id: DefId) -> ast_map::DefKey {
if id.is_local() {
self.map.def_key(id)

View File

@ -246,9 +246,9 @@ fn check_for_bindings_named_the_same_as_variants(cx: &MatchCheckCtxt, pat: &Pat)
let pat_ty = cx.tcx.pat_ty(p);
if let ty::TyEnum(edef, _) = pat_ty.sty {
if let Def::Local(..) = cx.tcx.expect_def(p.id) {
if edef.variants.iter().any(|variant|
variant.name == name.node && variant.kind() == VariantKind::Unit
) {
if edef.variants.iter().any(|variant| {
variant.name == name.node && variant.kind == VariantKind::Unit
}) {
let ty_path = cx.tcx.item_path_str(edef.did);
let mut err = struct_span_warn!(cx.tcx.sess, p.span, E0170,
"pattern binding `{}` is named the same as one \
@ -489,7 +489,7 @@ impl<'map> IdVisitingOperation for RenamingRecorder<'map> {
impl<'a, 'tcx> Folder for StaticInliner<'a, 'tcx> {
fn fold_pat(&mut self, pat: P<Pat>) -> P<Pat> {
return match pat.node {
PatKind::Path(..) | PatKind::QPath(..) => {
PatKind::Path(..) => {
match self.tcx.expect_def(pat.id) {
Def::AssociatedConst(did) | Def::Const(did) => {
let substs = Some(self.tcx.node_id_item_substs(pat.id).substs);
@ -563,7 +563,7 @@ fn construct_witness<'a,'tcx>(cx: &MatchCheckCtxt<'a,'tcx>, ctor: &Constructor,
ty::TyEnum(adt, _) | ty::TyStruct(adt, _) => {
let v = ctor.variant_for_adt(adt);
match v.kind() {
match v.kind {
VariantKind::Struct => {
let field_pats: hir::HirVec<_> = v.fields.iter()
.zip(pats)
@ -583,7 +583,7 @@ fn construct_witness<'a,'tcx>(cx: &MatchCheckCtxt<'a,'tcx>, ctor: &Constructor,
PatKind::TupleStruct(def_to_path(cx.tcx, v.did), pats.collect(), None)
}
VariantKind::Unit => {
PatKind::Path(def_to_path(cx.tcx, v.did))
PatKind::Path(None, def_to_path(cx.tcx, v.did))
}
}
}
@ -786,16 +786,12 @@ fn pat_constructors(cx: &MatchCheckCtxt, p: &Pat,
match pat.node {
PatKind::Struct(..) | PatKind::TupleStruct(..) | PatKind::Path(..) =>
match cx.tcx.expect_def(pat.id) {
Def::Const(..) | Def::AssociatedConst(..) =>
span_bug!(pat.span, "const pattern should've \
been rewritten"),
Def::Struct(..) | Def::TyAlias(..) => vec![Single],
Def::Variant(_, id) => vec![Variant(id)],
def => span_bug!(pat.span, "pat_constructors: unexpected \
definition {:?}", def),
Def::Struct(..) | Def::TyAlias(..) | Def::AssociatedTy(..) => vec![Single],
Def::Const(..) | Def::AssociatedConst(..) =>
span_bug!(pat.span, "const pattern should've been rewritten"),
def => span_bug!(pat.span, "pat_constructors: unexpected definition {:?}", def),
},
PatKind::QPath(..) =>
span_bug!(pat.span, "const pattern should've been rewritten"),
PatKind::Lit(ref expr) =>
vec![ConstantValue(eval_const_expr(cx.tcx, &expr))],
PatKind::Range(ref lo, ref hi) =>
@ -934,10 +930,6 @@ pub fn specialize<'a, 'b, 'tcx>(
}
}
PatKind::QPath(_, _) => {
span_bug!(pat_span, "const pattern should've been rewritten")
}
PatKind::Struct(_, ref pattern_fields, _) => {
let adt = cx.tcx.node_id_to_type(pat_id).ty_adt_def().unwrap();
let variant = constructor.variant_for_adt(adt);

View File

@ -323,7 +323,7 @@ pub fn const_expr_to_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
hir::ExprPath(_, ref path) => {
match tcx.expect_def(expr.id) {
Def::Struct(..) | Def::Variant(..) => PatKind::Path(path.clone()),
Def::Struct(..) | Def::Variant(..) => PatKind::Path(None, path.clone()),
Def::Const(def_id) | Def::AssociatedConst(def_id) => {
let substs = Some(tcx.node_id_item_substs(expr.id).substs);
let (expr, _ty) = lookup_const_by_id(tcx, def_id, substs).unwrap();

View File

@ -360,7 +360,7 @@ impl LateLintPass for NonUpperCaseGlobals {
fn check_pat(&mut self, cx: &LateContext, p: &hir::Pat) {
// Lint for constants that look like binding identifiers (#7526)
if let PatKind::Path(ref path) = p.node {
if let PatKind::Path(None, ref path) = p.node {
if !path.global && path.segments.len() == 1 && path.segments[0].parameters.is_empty() {
if let Def::Const(..) = cx.tcx.expect_def(p.id) {
NonUpperCaseGlobals::check_upper_case(cx, "constant in pattern",

View File

@ -471,28 +471,34 @@ pub fn get_adt_def<'a, 'tcx>(intr: &IdentInterner,
let doc = cdata.lookup_item(item_id);
let did = DefId { krate: cdata.cnum, index: item_id };
let mut ctor_did = None;
let (kind, variants) = match item_family(doc) {
Enum => {
(ty::AdtKind::Enum,
get_enum_variants(intr, cdata, doc))
}
Struct(..) => {
let ctor_did =
reader::maybe_get_doc(doc, tag_items_data_item_struct_ctor).
map_or(did, |ctor_doc| translated_def_id(cdata, ctor_doc));
// Use separate constructor id for unit/tuple structs and reuse did for braced structs.
ctor_did = reader::maybe_get_doc(doc, tag_items_data_item_struct_ctor).map(|ctor_doc| {
translated_def_id(cdata, ctor_doc)
});
(ty::AdtKind::Struct,
vec![get_struct_variant(intr, cdata, doc, ctor_did)])
vec![get_struct_variant(intr, cdata, doc, ctor_did.unwrap_or(did))])
}
_ => bug!("get_adt_def called on a non-ADT {:?} - {:?}",
item_family(doc), did)
};
let adt = tcx.intern_adt_def(did, kind, variants);
if let Some(ctor_did) = ctor_did {
// Make adt definition available through constructor id as well.
tcx.insert_adt_def(ctor_did, adt);
}
// this needs to be done *after* the variant is interned,
// to support recursive structures
for variant in &adt.variants {
if variant.kind() == ty::VariantKind::Tuple &&
if variant.kind == ty::VariantKind::Tuple &&
adt.adt_kind() == ty::AdtKind::Enum {
// tuple-like enum variant fields aren't real items - get the types
// from the ctor.

View File

@ -217,7 +217,7 @@ fn encode_parent_item(rbml_w: &mut Encoder, id: DefId) {
fn encode_struct_fields(rbml_w: &mut Encoder,
variant: ty::VariantDef) {
for f in &variant.fields {
if variant.is_tuple_struct() {
if variant.kind == ty::VariantKind::Tuple {
rbml_w.start_tag(tag_item_unnamed_field);
} else {
rbml_w.start_tag(tag_item_field);
@ -250,7 +250,7 @@ fn encode_enum_variant_info<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
let _task = index.record(vid, rbml_w);
rbml_w.start_tag(tag_items_data_item);
encode_def_id_and_key(ecx, rbml_w, vid);
encode_family(rbml_w, match variant.kind() {
encode_family(rbml_w, match variant.kind {
ty::VariantKind::Struct => 'V',
ty::VariantKind::Tuple => 'v',
ty::VariantKind::Unit => 'w',

View File

@ -13,7 +13,7 @@ use hair::cx::Cx;
use rustc_data_structures::indexed_vec::Idx;
use rustc_const_eval as const_eval;
use rustc::hir::def::Def;
use rustc::hir::pat_util::{EnumerateAndAdjustIterator, pat_is_resolved_const};
use rustc::hir::pat_util::EnumerateAndAdjustIterator;
use rustc::ty::{self, Ty};
use rustc::mir::repr::*;
use rustc::hir::{self, PatKind};
@ -76,9 +76,7 @@ impl<'patcx, 'cx, 'gcx, 'tcx> PatCx<'patcx, 'cx, 'gcx, 'tcx> {
PatternKind::Range { lo: lo, hi: hi }
},
PatKind::Path(..) | PatKind::QPath(..)
if pat_is_resolved_const(&self.cx.tcx.def_map.borrow(), pat) =>
{
PatKind::Path(..) => {
match self.cx.tcx.expect_def(pat.id) {
Def::Const(def_id) | Def::AssociatedConst(def_id) => {
let tcx = self.cx.tcx.global_tcx();
@ -104,11 +102,9 @@ impl<'patcx, 'cx, 'gcx, 'tcx> PatCx<'patcx, 'cx, 'gcx, 'tcx> {
}
}
}
def =>
span_bug!(
pat.span,
"def not a constant: {:?}",
def),
_ => {
self.variant_or_leaf(pat, vec![])
}
}
}
@ -199,10 +195,6 @@ impl<'patcx, 'cx, 'gcx, 'tcx> PatCx<'patcx, 'cx, 'gcx, 'tcx> {
}
}
PatKind::Path(..) => {
self.variant_or_leaf(pat, vec![])
}
PatKind::TupleStruct(_, ref subpatterns, ddpos) => {
let pat_ty = self.cx.tcx.node_id_to_type(pat.id);
let adt_def = match pat_ty.sty {
@ -253,10 +245,6 @@ impl<'patcx, 'cx, 'gcx, 'tcx> PatCx<'patcx, 'cx, 'gcx, 'tcx> {
self.variant_or_leaf(pat, subpatterns)
}
PatKind::QPath(..) => {
span_bug!(pat.span, "unexpanded macro or bad constant etc");
}
};
Pattern {
@ -325,7 +313,7 @@ impl<'patcx, 'cx, 'gcx, 'tcx> PatCx<'patcx, 'cx, 'gcx, 'tcx> {
}
}
Def::Struct(..) | Def::TyAlias(..) => {
Def::Struct(..) | Def::TyAlias(..) | Def::AssociatedTy(..) => {
PatternKind::Leaf { subpatterns: subpatterns }
}

View File

@ -436,7 +436,6 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> {
}
}
hir::ExprPath(..) => {
if let Def::Struct(..) = self.tcx.expect_def(expr.id) {
let expr_ty = self.tcx.expr_ty(expr);
let def = match expr_ty.sty {

View File

@ -2180,7 +2180,8 @@ impl<'a> Resolver<'a> {
// because that breaks the assumptions later
// passes make about or-patterns.)
let renamed = mtwt::resolve(ident.node);
let def = match bindings.get(&renamed).cloned() {
let mut def = Def::Local(self.definitions.local_def_id(pat_id), pat_id);
match bindings.get(&renamed).cloned() {
Some(id) if id == outer_pat_id => {
// `Variant(a, a)`, error
resolve_error(
@ -2189,7 +2190,6 @@ impl<'a> Resolver<'a> {
ResolutionError::IdentifierBoundMoreThanOnceInSamePattern(
&ident.node.name.as_str())
);
Def::Err
}
Some(..) if pat_src == PatternSource::FnParam => {
// `fn f(a: u8, a: u8)`, error
@ -2199,29 +2199,24 @@ impl<'a> Resolver<'a> {
ResolutionError::IdentifierBoundMoreThanOnceInParameterList(
&ident.node.name.as_str())
);
Def::Err
}
Some(..) if pat_src == PatternSource::Match => {
// `Variant1(a) | Variant2(a)`, ok
// Reuse definition from the first `a`.
self.value_ribs.last_mut().unwrap().bindings[&renamed]
def = self.value_ribs.last_mut().unwrap().bindings[&renamed];
}
Some(..) => {
span_bug!(ident.span, "two bindings with the same name from \
unexpected pattern source {:?}", pat_src);
}
None => {
// A completely fresh binding, add to the lists.
// FIXME: Later stages are not ready to deal with `Def::Err` here yet, so
// define `Invalid` bindings as `Def::Local`, just don't add them to the lists.
let def = Def::Local(self.definitions.local_def_id(pat_id), pat_id);
// A completely fresh binding, add to the lists if it's valid.
if ident.node.name != keywords::Invalid.name() {
bindings.insert(renamed, outer_pat_id);
self.value_ribs.last_mut().unwrap().bindings.insert(renamed, def);
}
def
}
};
}
PathResolution::new(def)
}
@ -2287,43 +2282,41 @@ impl<'a> Resolver<'a> {
PatKind::Ident(bmode, ref ident, ref opt_pat) => {
// First try to resolve the identifier as some existing
// entity, then fall back to a fresh binding.
let local_def = self.resolve_identifier(ident.node, ValueNS, true);
let resolution = if let Some(LocalDef { def, .. }) = local_def {
let resolution = self.resolve_identifier(ident.node, ValueNS, true)
.map(|local_def| PathResolution::new(local_def.def))
.and_then(|resolution| {
let always_binding = !pat_src.is_refutable() || opt_pat.is_some() ||
bmode != BindingMode::ByValue(Mutability::Immutable);
match def {
match resolution.base_def {
Def::Struct(..) | Def::Variant(..) |
Def::Const(..) | Def::AssociatedConst(..) if !always_binding => {
// A constant, unit variant, etc pattern.
PathResolution::new(def)
Some(resolution)
}
Def::Struct(..) | Def::Variant(..) |
Def::Const(..) | Def::AssociatedConst(..) | Def::Static(..) => {
// A fresh binding that shadows something unacceptable.
let kind_name = PathResolution::new(def).kind_name();
resolve_error(
self,
ident.span,
ResolutionError::BindingShadowsSomethingUnacceptable(
pat_src.descr(), kind_name, ident.node.name)
pat_src.descr(), resolution.kind_name(), ident.node.name)
);
err_path_resolution()
None
}
Def::Local(..) | Def::Upvar(..) | Def::Fn(..) | Def::Err => {
Def::Local(..) | Def::Upvar(..) | Def::Fn(..) => {
// These entities are explicitly allowed
// to be shadowed by fresh bindings.
self.fresh_binding(ident, pat.id, outer_pat_id,
pat_src, bindings)
None
}
def => {
span_bug!(ident.span, "unexpected definition for an \
identifier in pattern {:?}", def);
}
}
} else {
// Fall back to a fresh binding.
}).unwrap_or_else(|| {
self.fresh_binding(ident, pat.id, outer_pat_id, pat_src, bindings)
};
});
self.record_def(pat.id, resolution);
}
@ -2331,7 +2324,7 @@ impl<'a> Resolver<'a> {
PatKind::TupleStruct(ref path, _, _) => {
self.resolve_pattern_path(pat.id, None, path, ValueNS, |def| {
match def {
Def::Struct(..) | Def::Variant(..) | Def::Err => true,
Def::Struct(..) | Def::Variant(..) => true,
_ => false,
}
}, "variant or struct");
@ -2341,7 +2334,7 @@ impl<'a> Resolver<'a> {
self.resolve_pattern_path(pat.id, qself.as_ref(), path, ValueNS, |def| {
match def {
Def::Struct(..) | Def::Variant(..) |
Def::Const(..) | Def::AssociatedConst(..) | Def::Err => true,
Def::Const(..) | Def::AssociatedConst(..) => true,
_ => false,
}
}, "variant, struct or constant");
@ -2351,7 +2344,7 @@ impl<'a> Resolver<'a> {
self.resolve_pattern_path(pat.id, None, path, TypeNS, |def| {
match def {
Def::Struct(..) | Def::Variant(..) |
Def::TyAlias(..) | Def::AssociatedTy(..) | Def::Err => true,
Def::TyAlias(..) | Def::AssociatedTy(..) => true,
_ => false,
}
}, "variant, struct or type alias");
@ -2482,7 +2475,7 @@ impl<'a> Resolver<'a> {
record_used: bool)
-> Option<LocalDef> {
if identifier.name == keywords::Invalid.name() {
return Some(LocalDef::from_def(Def::Err));
return None;
}
self.resolve_ident_in_lexical_scope(identifier, namespace, record_used)

View File

@ -796,7 +796,7 @@ fn any_irrefutable_adt_pat(tcx: TyCtxt, m: &[Match], col: usize) -> bool {
PatKind::Tuple(..) => true,
PatKind::Struct(..) | PatKind::TupleStruct(..) | PatKind::Path(..) => {
match tcx.expect_def(pat.id) {
Def::Struct(..) | Def::TyAlias(..) => true,
Def::Struct(..) | Def::TyAlias(..) | Def::AssociatedTy(..) => true,
_ => false,
}
}
@ -2003,7 +2003,7 @@ pub fn bind_irrefutable_pat<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
cleanup_scope)
});
}
PatKind::Path(..) | PatKind::QPath(..) | PatKind::Wild |
PatKind::Path(..) | PatKind::Wild |
PatKind::Lit(..) | PatKind::Range(..) => ()
}
return bcx;

View File

@ -900,7 +900,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
}
Def::Variant(enum_did, variant_did) => {
let vinfo = cx.tcx().lookup_adt_def(enum_did).variant_with_id(variant_did);
match vinfo.kind() {
match vinfo.kind {
ty::VariantKind::Unit => {
let repr = adt::represent_type(cx, ety);
adt::trans_const(cx, &repr, Disr::from(vinfo.disr_val), &[])

View File

@ -313,7 +313,7 @@ fn walk_pattern(cx: &CrateContext,
}
}
PatKind::Path(..) | PatKind::QPath(..) => {
PatKind::Path(..) => {
scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata);
}

View File

@ -1109,7 +1109,7 @@ struct StructMemberDescriptionFactory<'tcx> {
impl<'tcx> StructMemberDescriptionFactory<'tcx> {
fn create_member_descriptions<'a>(&self, cx: &CrateContext<'a, 'tcx>)
-> Vec<MemberDescription> {
if let ty::VariantKind::Unit = self.variant.kind() {
if self.variant.kind == ty::VariantKind::Unit {
return Vec::new();
}
@ -1126,7 +1126,7 @@ impl<'tcx> StructMemberDescriptionFactory<'tcx> {
};
self.variant.fields.iter().enumerate().map(|(i, f)| {
let name = if let ty::VariantKind::Tuple = self.variant.kind() {
let name = if self.variant.kind == ty::VariantKind::Tuple {
format!("__{}", i)
} else {
f.name.to_string()
@ -1356,7 +1356,7 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> {
// For the metadata of the wrapper struct, we need to create a
// MemberDescription of the struct's single field.
let sole_struct_member_description = MemberDescription {
name: match non_null_variant.kind() {
name: match non_null_variant.kind {
ty::VariantKind::Tuple => "__0".to_string(),
ty::VariantKind::Struct => {
non_null_variant.fields[0].name.to_string()
@ -1524,7 +1524,7 @@ fn describe_enum_variant<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
containing_scope);
// Get the argument names from the enum variant info
let mut arg_names: Vec<_> = match variant.kind() {
let mut arg_names: Vec<_> = match variant.kind {
ty::VariantKind::Unit => vec![],
ty::VariantKind::Tuple => {
variant.fields

View File

@ -53,7 +53,7 @@ use rustc_const_eval::{eval_const_expr_partial, ConstEvalErr};
use rustc_const_eval::EvalHint::UncheckedExprHint;
use rustc_const_eval::ErrKind::ErroneousReferencedConstant;
use hir::{self, SelfKind};
use hir::def::{self, Def};
use hir::def::{Def, PathResolution};
use hir::def_id::DefId;
use hir::print as pprust;
use middle::resolve_lifetime as rl;
@ -1327,7 +1327,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
};
if self.ensure_super_predicates(span, trait_did).is_err() {
return (tcx.types.err, ty_path_def);
return (tcx.types.err, Def::Err);
}
let candidates: Vec<ty::PolyTraitRef> =
@ -1341,7 +1341,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
&assoc_name.as_str(),
span) {
Ok(bound) => bound,
Err(ErrorReported) => return (tcx.types.err, ty_path_def),
Err(ErrorReported) => return (tcx.types.err, Def::Err),
}
}
(&ty::TyParam(_), Def::SelfTy(Some(trait_did), None)) => {
@ -1351,7 +1351,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
assoc_name,
span) {
Ok(bound) => bound,
Err(ErrorReported) => return (tcx.types.err, ty_path_def),
Err(ErrorReported) => return (tcx.types.err, Def::Err),
}
}
(&ty::TyParam(_), Def::TyParam(_, _, param_did, param_name)) => {
@ -1361,7 +1361,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
assoc_name,
span) {
Ok(bound) => bound,
Err(ErrorReported) => return (tcx.types.err, ty_path_def),
Err(ErrorReported) => return (tcx.types.err, Def::Err),
}
}
_ => {
@ -1369,7 +1369,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
&ty.to_string(),
"Trait",
&assoc_name.as_str());
return (tcx.types.err, ty_path_def);
return (tcx.types.err, Def::Err);
}
};
@ -1574,45 +1574,46 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
}
}
// Note that both base_segments and assoc_segments may be empty, although not at
// the same time.
// Resolve possibly associated type path into a type and final definition.
// Note that both base_segments and assoc_segments may be empty, although not at same time.
pub fn finish_resolving_def_to_ty(&self,
rscope: &RegionScope,
span: Span,
param_mode: PathParamMode,
mut def: Def,
base_def: Def,
opt_self_ty: Option<Ty<'tcx>>,
base_path_ref_id: ast::NodeId,
base_segments: &[hir::PathSegment],
assoc_segments: &[hir::PathSegment])
-> (Ty<'tcx>, Def) {
debug!("finish_resolving_def_to_ty(def={:?}, \
// Convert the base type.
debug!("finish_resolving_def_to_ty(base_def={:?}, \
base_segments={:?}, \
assoc_segments={:?})",
def,
base_def,
base_segments,
assoc_segments);
let mut ty = self.base_def_to_ty(rscope,
span,
param_mode,
def,
opt_self_ty,
base_path_ref_id,
base_segments);
debug!("finish_resolving_def_to_ty: base_def_to_ty returned {:?}", ty);
let base_ty = self.base_def_to_ty(rscope,
span,
param_mode,
base_def,
opt_self_ty,
base_path_ref_id,
base_segments);
debug!("finish_resolving_def_to_ty: base_def_to_ty returned {:?}", base_ty);
// If any associated type segments remain, attempt to resolve them.
let (mut ty, mut def) = (base_ty, base_def);
for segment in assoc_segments {
debug!("finish_resolving_def_to_ty: segment={:?}", segment);
if ty.sty == ty::TyError {
// This is pretty bad (it will fail except for T::A and Self::A).
let (new_ty, new_def) = self.associated_path_def_to_ty(span, ty, def, segment);
ty = new_ty;
def = new_def;
if def == Def::Err {
break;
}
// This is pretty bad (it will fail except for T::A and Self::A).
let (a_ty, a_def) = self.associated_path_def_to_ty(span,
ty,
def,
segment);
ty = a_ty;
def = a_def;
}
(ty, def)
}
@ -1719,23 +1720,22 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
hir::TyPath(ref maybe_qself, ref path) => {
debug!("ast_ty_to_ty: maybe_qself={:?} path={:?}", maybe_qself, path);
let path_res = tcx.expect_resolution(ast_ty.id);
let def = path_res.base_def;
let base_ty_end = path.segments.len() - path_res.depth;
let opt_self_ty = maybe_qself.as_ref().map(|qself| {
self.ast_ty_to_ty(rscope, &qself.ty)
});
let (ty, _def) = self.finish_resolving_def_to_ty(rscope,
ast_ty.span,
PathParamMode::Explicit,
def,
opt_self_ty,
ast_ty.id,
&path.segments[..base_ty_end],
&path.segments[base_ty_end..]);
let (ty, def) = self.finish_resolving_def_to_ty(rscope,
ast_ty.span,
PathParamMode::Explicit,
path_res.base_def,
opt_self_ty,
ast_ty.id,
&path.segments[..base_ty_end],
&path.segments[base_ty_end..]);
if path_res.depth != 0 && ty.sty != ty::TyError {
// Write back the new resolution.
tcx.def_map.borrow_mut().insert(ast_ty.id, def::PathResolution::new(def));
// Write back the new resolution.
if path_res.depth != 0 {
tcx.def_map.borrow_mut().insert(ast_ty.id, PathResolution::new(def));
}
ty

View File

@ -10,13 +10,12 @@
use hir::def::Def;
use rustc::infer::{self, InferOk, TypeOrigin};
use hir::pat_util::{EnumerateAndAdjustIterator, pat_is_resolved_const};
use hir::pat_util::EnumerateAndAdjustIterator;
use rustc::ty::subst::Substs;
use rustc::ty::{self, Ty, TypeFoldable, LvaluePreference};
use rustc::ty::{self, Ty, TypeFoldable, LvaluePreference, VariantKind};
use check::{FnCtxt, Expectation};
use lint;
use util::nodemap::FnvHashMap;
use session::Session;
use std::collections::hash_map::Entry::{Occupied, Vacant};
use std::cmp;
@ -28,20 +27,6 @@ use syntax_pos::Span;
use rustc::hir::{self, PatKind};
use rustc::hir::print as pprust;
// This function exists due to the warning "diagnostic code E0164 already used"
fn bad_struct_kind_err(sess: &Session, pat: &hir::Pat, path: &hir::Path, lint: bool) {
let name = pprust::path_to_string(path);
let msg = format!("`{}` does not name a tuple variant or a tuple struct", name);
if lint {
sess.add_lint(lint::builtin::MATCH_OF_UNIT_VARIANT_VIA_PAREN_DOTDOT,
pat.id,
pat.span,
msg);
} else {
span_err!(sess, pat.span, E0164, "{}", msg);
}
}
impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
pub fn check_pat(&self, pat: &'gcx hir::Pat, expected: Ty<'tcx>) {
let tcx = self.tcx;
@ -136,22 +121,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
// subtyping doesn't matter here, as the value is some kind of scalar
self.demand_eqtype(pat.span, expected, lhs_ty);
}
PatKind::Path(..) if pat_is_resolved_const(&tcx.def_map.borrow(), pat) => {
let const_did = tcx.expect_def(pat.id).def_id();
let const_scheme = tcx.lookup_item_type(const_did);
assert!(const_scheme.generics.is_empty());
let const_ty = self.instantiate_type_scheme(pat.span,
&Substs::empty(),
&const_scheme.ty);
self.write_ty(pat.id, const_ty);
// FIXME(#20489) -- we should limit the types here to scalars or something!
// As with PatKind::Lit, what we really want here is that there
// exist a LUB, but for the cases that can occur, subtype
// is good enough.
self.demand_suptype(pat.span, expected, const_ty);
}
PatKind::Binding(bm, _, ref sub) => {
let typ = self.local_ty(pat.span, pat.id);
match bm {
@ -197,33 +166,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
}
}
PatKind::TupleStruct(ref path, ref subpats, ddpos) => {
self.check_pat_enum(pat, path, &subpats, ddpos, expected, true);
self.check_pat_tuple_struct(pat, path, &subpats, ddpos, expected);
}
PatKind::Path(ref path) => {
self.check_pat_enum(pat, path, &[], None, expected, false);
}
PatKind::QPath(ref qself, ref path) => {
let self_ty = self.to_ty(&qself.ty);
let path_res = tcx.expect_resolution(pat.id);
if path_res.base_def == Def::Err {
self.set_tainted_by_errors();
self.write_error(pat.id);
return;
}
if let Some((opt_ty, segments, def)) =
self.resolve_ty_and_def_ufcs(path_res, Some(self_ty),
path, pat.span, pat.id) {
if self.check_assoc_item_is_const(def, pat.span) {
let scheme = tcx.lookup_item_type(def.def_id());
let predicates = tcx.lookup_predicates(def.def_id());
self.instantiate_path(segments, scheme, &predicates,
opt_ty, def, pat.span, pat.id);
let const_ty = self.node_ty(pat.id);
self.demand_suptype(pat.span, expected, const_ty);
} else {
self.write_error(pat.id)
}
}
PatKind::Path(ref opt_qself, ref path) => {
let opt_qself_ty = opt_qself.as_ref().map(|qself| self.to_ty(&qself.ty));
self.check_pat_path(pat, opt_qself_ty, path, expected);
}
PatKind::Struct(ref path, ref fields, etc) => {
self.check_pat_struct(pat, path, fields, etc, expected);
@ -403,20 +350,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
// subtyping.
}
fn check_assoc_item_is_const(&self, def: Def, span: Span) -> bool {
match def {
Def::AssociatedConst(..) => true,
Def::Method(..) => {
span_err!(self.tcx.sess, span, E0327,
"associated items in match patterns must be constants");
false
}
_ => {
span_bug!(span, "non-associated item in check_assoc_item_is_const");
}
}
}
pub fn check_dereferencable(&self, span: Span, expected: Ty<'tcx>, inner: &hir::Pat) -> bool {
if let PatKind::Binding(..) = inner.node {
if let Some(mt) = self.shallow_resolve(expected).builtin_deref(true, ty::NoPreference) {
@ -554,167 +487,166 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
}
impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
pub fn check_pat_struct(&self, pat: &'gcx hir::Pat,
path: &hir::Path, fields: &'gcx [Spanned<hir::FieldPat>],
etc: bool, expected: Ty<'tcx>) {
let tcx = self.tcx;
let def = tcx.expect_def(pat.id);
let variant = match self.def_struct_variant(def, path.span) {
Some((_, variant)) => variant,
None => {
let name = pprust::path_to_string(path);
span_err!(tcx.sess, pat.span, E0163,
"`{}` does not name a struct or a struct variant", name);
self.write_error(pat.id);
for field in fields {
self.check_pat(&field.node.pat, tcx.types.err);
}
return;
fn check_pat_struct(&self,
pat: &'gcx hir::Pat,
path: &hir::Path,
fields: &'gcx [Spanned<hir::FieldPat>],
etc: bool,
expected: 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) {
variant_ty
} else {
self.write_error(pat.id);
for field in fields {
self.check_pat(&field.node.pat, self.tcx.types.err);
}
return;
};
let pat_ty = self.instantiate_type(def.def_id(), path);
let item_substs = match pat_ty.sty {
// Type check the path.
self.demand_eqtype(pat.span, expected, pat_ty);
// Type check subpatterns.
let substs = match pat_ty.sty {
ty::TyStruct(_, substs) | ty::TyEnum(_, substs) => substs,
_ => span_bug!(pat.span, "struct variant is not an ADT")
};
self.demand_eqtype(pat.span, expected, pat_ty);
self.check_struct_pat_fields(pat.span, fields, variant, &item_substs, etc);
self.write_ty(pat.id, pat_ty);
self.write_substs(pat.id, ty::ItemSubsts {
substs: item_substs
});
self.check_struct_pat_fields(pat.span, fields, variant, substs, etc);
}
fn check_pat_enum(&self,
fn check_pat_path(&self,
pat: &hir::Pat,
opt_self_ty: Option<Ty<'tcx>>,
path: &hir::Path,
subpats: &'gcx [P<hir::Pat>],
ddpos: Option<usize>,
expected: Ty<'tcx>,
is_tuple_struct_pat: bool)
expected: Ty<'tcx>)
{
// Typecheck the path.
let tcx = self.tcx;
let path_res = tcx.expect_resolution(pat.id);
if path_res.base_def == Def::Err {
self.set_tainted_by_errors();
let report_unexpected_def = || {
span_err!(tcx.sess, pat.span, E0533,
"`{}` does not name a unit variant, unit struct or a constant",
pprust::path_to_string(path));
self.write_error(pat.id);
for pat in subpats {
self.check_pat(&pat, tcx.types.err);
}
return;
}
let (opt_ty, segments, def) = match self.resolve_ty_and_def_ufcs(path_res,
None, path,
pat.span, pat.id) {
Some(resolution) => resolution,
// Error handling done inside resolve_ty_and_def_ufcs, so if
// resolution fails just return.
None => {return;}
};
// Items that were partially resolved before should have been resolved to
// associated constants (i.e. not methods).
if path_res.depth != 0 && !self.check_assoc_item_is_const(def, pat.span) {
self.write_error(pat.id);
return;
}
let enum_def = def.variant_def_ids()
.map_or_else(|| def.def_id(), |(enum_def, _)| enum_def);
let ctor_scheme = tcx.lookup_item_type(enum_def);
let ctor_predicates = tcx.lookup_predicates(enum_def);
let path_scheme = if ctor_scheme.ty.is_fn() {
let fn_ret = tcx.no_late_bound_regions(&ctor_scheme.ty.fn_ret()).unwrap();
ty::TypeScheme {
ty: fn_ret.unwrap(),
generics: ctor_scheme.generics,
}
} else {
ctor_scheme
};
self.instantiate_path(segments, path_scheme, &ctor_predicates,
opt_ty, def, pat.span, pat.id);
let report_bad_struct_kind = |is_warning| {
bad_struct_kind_err(tcx.sess, pat, path, is_warning);
if is_warning { return; }
self.write_error(pat.id);
for pat in subpats {
self.check_pat(&pat, tcx.types.err);
}
};
// If we didn't have a fully resolved path to start with, we had an
// associated const, and we should quit now, since the rest of this
// function uses checks specific to structs and enums.
if path_res.depth != 0 {
if is_tuple_struct_pat {
report_bad_struct_kind(false);
} else {
let pat_ty = self.node_ty(pat.id);
self.demand_suptype(pat.span, expected, pat_ty);
}
return;
}
let pat_ty = self.node_ty(pat.id);
self.demand_eqtype(pat.span, expected, pat_ty);
let real_path_ty = self.node_ty(pat.id);
let (kind_name, variant, expected_substs) = match real_path_ty.sty {
ty::TyEnum(enum_def, expected_substs) => {
let variant = enum_def.variant_of_def(def);
("variant", variant, expected_substs)
}
ty::TyStruct(struct_def, expected_substs) => {
let variant = struct_def.struct_variant();
("struct", variant, expected_substs)
}
_ => {
report_bad_struct_kind(false);
// Resolve the path and check the definition for errors.
let (def, opt_ty, segments) = self.resolve_ty_and_def_ufcs(opt_self_ty, path,
pat.id, pat.span);
match def {
Def::Err => {
self.set_tainted_by_errors();
self.write_error(pat.id);
return;
}
};
match (is_tuple_struct_pat, variant.kind()) {
(true, ty::VariantKind::Unit) if subpats.is_empty() && ddpos.is_some() => {
// Matching unit structs with tuple variant patterns (`UnitVariant(..)`)
// is allowed for backward compatibility.
report_bad_struct_kind(true);
Def::Method(..) => {
report_unexpected_def();
return;
}
(true, ty::VariantKind::Unit) |
(false, ty::VariantKind::Tuple) |
(_, ty::VariantKind::Struct) => {
report_bad_struct_kind(false);
return
Def::Variant(..) | Def::Struct(..) => {
let variant = tcx.expect_variant_def(def);
if variant.kind != VariantKind::Unit {
report_unexpected_def();
return;
}
}
_ => {}
Def::Const(..) | Def::AssociatedConst(..) => {} // OK
_ => bug!("unexpected pattern definition {:?}", def)
}
// Type check the path.
let scheme = tcx.lookup_item_type(def.def_id());
let predicates = tcx.lookup_predicates(def.def_id());
let pat_ty = self.instantiate_value_path(segments, scheme, &predicates,
opt_ty, def, pat.span, pat.id);
self.demand_suptype(pat.span, expected, pat_ty);
}
fn check_pat_tuple_struct(&self,
pat: &hir::Pat,
path: &hir::Path,
subpats: &'gcx [P<hir::Pat>],
ddpos: Option<usize>,
expected: Ty<'tcx>)
{
let tcx = self.tcx;
let on_error = || {
self.write_error(pat.id);
for pat in subpats {
self.check_pat(&pat, tcx.types.err);
}
};
let report_unexpected_def = |is_lint| {
let msg = format!("`{}` does not name a tuple variant or a tuple struct",
pprust::path_to_string(path));
if is_lint {
tcx.sess.add_lint(lint::builtin::MATCH_OF_UNIT_VARIANT_VIA_PAREN_DOTDOT,
pat.id, pat.span, msg);
} else {
span_err!(tcx.sess, pat.span, E0164, "{}", msg);
on_error();
}
};
// Resolve the path and check the definition for errors.
let (def, opt_ty, segments) = self.resolve_ty_and_def_ufcs(None, path, pat.id, pat.span);
let variant = match def {
Def::Err => {
self.set_tainted_by_errors();
on_error();
return;
}
Def::Const(..) | Def::AssociatedConst(..) | Def::Method(..) => {
report_unexpected_def(false);
return;
}
Def::Variant(..) | Def::Struct(..) => {
tcx.expect_variant_def(def)
}
_ => bug!("unexpected pattern definition {:?}", def)
};
if variant.kind == VariantKind::Unit && subpats.is_empty() && ddpos.is_some() {
// Matching unit structs with tuple variant patterns (`UnitVariant(..)`)
// is allowed for backward compatibility.
report_unexpected_def(true);
} else if variant.kind != VariantKind::Tuple {
report_unexpected_def(false);
return;
}
// Type check the path.
let scheme = tcx.lookup_item_type(def.def_id());
let scheme = if scheme.ty.is_fn() {
// Replace constructor type with constructed type for tuple struct patterns.
let fn_ret = tcx.no_late_bound_regions(&scheme.ty.fn_ret()).unwrap().unwrap();
ty::TypeScheme { ty: fn_ret, generics: scheme.generics }
} else {
// Leave the type as is for unit structs (backward compatibility).
scheme
};
let predicates = tcx.lookup_predicates(def.def_id());
let pat_ty = self.instantiate_value_path(segments, scheme, &predicates,
opt_ty, def, pat.span, pat.id);
self.demand_eqtype(pat.span, expected, pat_ty);
// Type check subpatterns.
if subpats.len() == variant.fields.len() ||
subpats.len() < variant.fields.len() && ddpos.is_some() {
let substs = match pat_ty.sty {
ty::TyStruct(_, substs) | ty::TyEnum(_, substs) => substs,
ref ty => bug!("unexpected pattern type {:?}", ty),
};
for (i, subpat) in subpats.iter().enumerate_and_adjust(variant.fields.len(), ddpos) {
let field_ty = self.field_ty(subpat.span, &variant.fields[i], expected_substs);
let field_ty = self.field_ty(subpat.span, &variant.fields[i], substs);
self.check_pat(&subpat, field_ty);
}
} else {
span_err!(tcx.sess, pat.span, E0023,
"this pattern has {} field{}, but the corresponding {} has {} field{}",
subpats.len(), if subpats.len() == 1 {""} else {"s"},
kind_name,
variant.fields.len(), if variant.fields.len() == 1 {""} else {"s"});
for pat in subpats {
self.check_pat(&pat, tcx.types.err);
}
"this pattern has {} field{s}, but the corresponding {} has {} field{s}",
subpats.len(), def.kind_name(), variant.fields.len(),
s = if variant.fields.len() == 1 {""} else {"s"});
on_error();
}
}

View File

@ -84,7 +84,7 @@ use astconv::{AstConv, ast_region_to_region, PathParamMode};
use dep_graph::DepNode;
use fmt_macros::{Parser, Piece, Position};
use middle::cstore::LOCAL_CRATE;
use hir::def::{self, Def};
use hir::def::{Def, PathResolution};
use hir::def_id::DefId;
use hir::pat_util;
use rustc::infer::{self, InferCtxt, InferOk, TypeOrigin, TypeTrace, type_variable};
@ -1621,64 +1621,32 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
///
/// Note that this function is only intended to be used with type-paths,
/// not with value-paths.
pub fn instantiate_type(&self,
did: DefId,
path: &hir::Path)
-> Ty<'tcx>
{
debug!("instantiate_type(did={:?}, path={:?})", did, path);
let type_scheme =
self.tcx.lookup_item_type(did);
let type_predicates =
self.tcx.lookup_predicates(did);
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 type_scheme = self.tcx.lookup_item_type(did);
let type_predicates = self.tcx.lookup_predicates(did);
let substs = AstConv::ast_path_substs_for_ty(self, self,
path.span,
PathParamMode::Optional,
&type_scheme.generics,
path.segments.last().unwrap());
debug!("instantiate_type: ty={:?} substs={:?}", &type_scheme.ty, &substs);
let bounds =
self.instantiate_bounds(path.span, &substs, &type_predicates);
self.add_obligations_for_parameters(
traits::ObligationCause::new(
path.span,
self.body_id,
traits::ItemObligation(did)),
&bounds);
let substs = self.tcx.mk_substs(substs);
debug!("instantiate_type_path: ty={:?} substs={:?}", &type_scheme.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);
self.instantiate_type_scheme(path.span, &substs, &type_scheme.ty)
}
/// Return the dict-like variant corresponding to a given `Def`.
pub fn def_struct_variant(&self,
def: Def,
_span: Span)
-> Option<(ty::AdtDef<'tcx>, ty::VariantDef<'tcx>)>
{
let (adt, variant) = match def {
Def::Variant(enum_id, variant_id) => {
let adt = self.tcx.lookup_adt_def(enum_id);
(adt, adt.variant_with_id(variant_id))
}
Def::Struct(did) | Def::TyAlias(did) => {
let typ = self.tcx.lookup_item_type(did);
if let ty::TyStruct(adt, _) = typ.ty.sty {
(adt, adt.struct_variant())
} else {
return None;
}
}
_ => return None
};
let var_kind = variant.kind();
if var_kind == ty::VariantKind::Struct {
Some((adt, variant))
} else if var_kind == ty::VariantKind::Unit {
Some((adt, variant))
} else {
None
}
let ty_substituted = self.instantiate_type_scheme(path.span, substs, &type_scheme.ty);
self.write_ty(node_id, ty_substituted);
self.write_substs(node_id, ty::ItemSubsts {
substs: substs
});
ty_substituted
}
pub fn write_nil(&self, node_id: ast::NodeId) {
@ -2998,7 +2966,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
while let Some((base_t, autoderefs)) = autoderef.next() {
let field = match base_t.sty {
ty::TyStruct(base_def, substs) => {
tuple_like = base_def.struct_variant().is_tuple_struct();
tuple_like = base_def.struct_variant().kind == ty::VariantKind::Tuple;
if !tuple_like { continue }
debug!("tuple struct named {:?}", base_t);
@ -3153,35 +3121,57 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
}
}
pub fn check_struct_path(&self,
path: &hir::Path,
node_id: ast::NodeId,
span: Span)
-> Option<(ty::VariantDef<'tcx>, Ty<'tcx>)> {
let def = self.finish_resolving_struct_path(path, node_id, span);
let variant = match def {
Def::Err => {
self.set_tainted_by_errors();
return None;
}
Def::Variant(..) | Def::Struct(..) => {
Some(self.tcx.expect_variant_def(def))
}
Def::TyAlias(did) | Def::AssociatedTy(_, did) => {
if let Some(&ty::TyStruct(adt, _)) = self.tcx.opt_lookup_item_type(did)
.map(|scheme| &scheme.ty.sty) {
Some(adt.struct_variant())
} else {
None
}
}
_ => None
};
if variant.is_none() || variant.unwrap().kind == ty::VariantKind::Tuple {
// Reject tuple structs for now, braced and unit structs are allowed.
span_err!(self.tcx.sess, span, E0071,
"`{}` does not name a struct or a struct variant",
pprust::path_to_string(path));
return None;
}
let ty = self.instantiate_type_path(def.def_id(), path, node_id);
Some((variant.unwrap(), ty))
}
fn check_expr_struct(&self,
expr: &hir::Expr,
path: &hir::Path,
fields: &'gcx [hir::Field],
base_expr: &'gcx Option<P<hir::Expr>>)
{
let tcx = self.tcx;
// Find the relevant variant
let def = tcx.expect_def(expr.id);
if def == Def::Err {
self.set_tainted_by_errors();
let (variant, expr_ty) = if let Some(variant_ty) = self.check_struct_path(path, expr.id,
expr.span) {
variant_ty
} else {
self.check_struct_fields_on_error(expr.id, fields, base_expr);
return;
}
let variant = match self.def_struct_variant(def, path.span) {
Some((_, variant)) => variant,
None => {
span_err!(self.tcx.sess, path.span, E0071,
"`{}` does not name a structure",
pprust::path_to_string(path));
self.check_struct_fields_on_error(expr.id, fields, base_expr);
return;
}
};
let expr_ty = self.instantiate_type(def.def_id(), path);
self.write_ty(expr.id, expr_ty);
self.check_expr_struct_fields(expr_ty, path.span, variant, fields,
base_expr.is_none());
if let &Some(ref base_expr) = base_expr {
@ -3192,13 +3182,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
expr.id,
adt.struct_variant().fields.iter().map(|f| {
self.normalize_associated_types_in(
expr.span, &f.ty(tcx, substs)
expr.span, &f.ty(self.tcx, substs)
)
}).collect()
);
}
_ => {
span_err!(tcx.sess, base_expr.span, E0436,
span_err!(self.tcx.sess, base_expr.span, E0436,
"functional record update syntax requires a struct");
}
}
@ -3349,24 +3339,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
};
self.write_ty(id, oprnd_t);
}
hir::ExprPath(ref maybe_qself, ref path) => {
let opt_self_ty = maybe_qself.as_ref().map(|qself| {
self.to_ty(&qself.ty)
});
let path_res = tcx.expect_resolution(id);
if let Some((opt_ty, segments, def)) =
self.resolve_ty_and_def_ufcs(path_res, opt_self_ty, path,
expr.span, expr.id) {
if def != Def::Err {
let (scheme, predicates) = self.type_scheme_and_predicates_for_def(expr.span,
def);
self.instantiate_path(segments, scheme, &predicates,
opt_ty, def, expr.span, id);
} else {
self.set_tainted_by_errors();
self.write_ty(id, self.tcx.types.err);
}
hir::ExprPath(ref opt_qself, ref path) => {
let opt_self_ty = opt_qself.as_ref().map(|qself| self.to_ty(&qself.ty));
let (def, opt_ty, segments) = self.resolve_ty_and_def_ufcs(opt_self_ty, path,
expr.id, expr.span);
if def != Def::Err {
let (scheme, predicates) = self.type_scheme_and_predicates_for_def(expr.span,
def);
self.instantiate_value_path(segments, scheme, &predicates,
opt_ty, def, expr.span, id);
} else {
self.set_tainted_by_errors();
self.write_error(id);
}
// We always require that the type provided as the value for
@ -3704,37 +3688,67 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
expected);
}
// 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
{
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
}
}
// Resolve associated value path into a base type and associated constant or method definition.
// The newly resolved definition is written into `def_map`.
pub fn resolve_ty_and_def_ufcs<'b>(&self,
path_res: def::PathResolution,
opt_self_ty: Option<Ty<'tcx>>,
path: &'b hir::Path,
span: Span,
node_id: ast::NodeId)
-> Option<(Option<Ty<'tcx>>, &'b [hir::PathSegment], Def)>
node_id: ast::NodeId,
span: Span)
-> (Def, Option<Ty<'tcx>>, &'b [hir::PathSegment])
{
// If fully resolved already, we don't have to do anything.
let path_res = self.tcx().expect_resolution(node_id);
if path_res.depth == 0 {
Some((opt_self_ty, &path.segments, path_res.base_def))
// If fully resolved already, we don't have to do anything.
(path_res.base_def, opt_self_ty, &path.segments)
} else {
let def = path_res.base_def;
// Try to resolve everything except for the last segment as a type.
let ty_segments = path.segments.split_last().unwrap().1;
let base_ty_end = path.segments.len() - path_res.depth;
let (ty, _def) = AstConv::finish_resolving_def_to_ty(self, self, span,
PathParamMode::Optional,
def,
path_res.base_def,
opt_self_ty,
node_id,
&ty_segments[..base_ty_end],
&ty_segments[base_ty_end..]);
// Resolve an associated constant or method on the previously resolved type.
let item_segment = path.segments.last().unwrap();
let item_name = item_segment.name;
let def = match self.resolve_ufcs(span, item_name, ty, node_id) {
Ok(def) => Some(def),
Ok(def) => def,
Err(error) => {
let def = match error {
method::MethodError::PrivateMatch(def) => Some(def),
_ => None,
method::MethodError::PrivateMatch(def) => def,
_ => Def::Err,
};
if item_name != keywords::Invalid.name() {
self.report_method_error(span, ty, item_name, None, error);
@ -3743,14 +3757,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
}
};
if let Some(def) = def {
// Write back the new resolution.
self.tcx().def_map.borrow_mut().insert(node_id, def::PathResolution::new(def));
Some((Some(ty), slice::ref_slice(item_segment), def))
} else {
self.write_error(node_id);
None
}
// Write back the new resolution.
self.tcx().def_map.borrow_mut().insert(node_id, PathResolution::new(def));
(def, Some(ty), slice::ref_slice(item_segment))
}
}
@ -3986,15 +3995,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
// Instantiates the given path, which must refer to an item with the given
// number of type parameters and type.
pub fn instantiate_path(&self,
segments: &[hir::PathSegment],
type_scheme: TypeScheme<'tcx>,
type_predicates: &ty::GenericPredicates<'tcx>,
opt_self_ty: Option<Ty<'tcx>>,
def: Def,
span: Span,
node_id: ast::NodeId) {
debug!("instantiate_path(path={:?}, def={:?}, node_id={}, type_scheme={:?})",
pub fn instantiate_value_path(&self,
segments: &[hir::PathSegment],
type_scheme: TypeScheme<'tcx>,
type_predicates: &ty::GenericPredicates<'tcx>,
opt_self_ty: Option<Ty<'tcx>>,
def: Def,
span: Span,
node_id: ast::NodeId)
-> Ty<'tcx> {
debug!("instantiate_value_path(path={:?}, def={:?}, node_id={}, type_scheme={:?})",
segments,
def,
node_id,
@ -4023,7 +4033,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
// actually pass through this function, but rather the
// `ast_ty_to_ty` function in `astconv`. However, in the case
// of struct patterns (and maybe literals) we do invoke
// `instantiate_path` to get the general type of an instance of
// `instantiate_value_path` to get the general type of an instance of
// a struct. (In these cases, there are actually no type
// parameters permitted at present, but perhaps we will allow
// them in the future.)
@ -4246,20 +4256,21 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
}
Err(_) => {
span_bug!(span,
"instantiate_path: (UFCS) {:?} was a subtype of {:?} but now is not?",
"instantiate_value_path: (UFCS) {:?} was a subtype of {:?} but now is not?",
self_ty,
impl_ty);
}
}
}
debug!("instantiate_path: type of {:?} is {:?}",
debug!("instantiate_value_path: type of {:?} is {:?}",
node_id,
ty_substituted);
self.write_ty(node_id, ty_substituted);
self.write_substs(node_id, ty::ItemSubsts {
substs: substs
});
ty_substituted
}
/// Finds the parameters that the user provided and adds them to `substs`. If too many

View File

@ -949,7 +949,7 @@ fn convert_variant_ctor<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
scheme: ty::TypeScheme<'tcx>,
predicates: ty::GenericPredicates<'tcx>) {
let tcx = ccx.tcx;
let ctor_ty = match variant.kind() {
let ctor_ty = match variant.kind {
VariantKind::Unit | VariantKind::Struct => scheme.ty,
VariantKind::Tuple => {
let inputs: Vec<_> =
@ -1040,15 +1040,17 @@ fn convert_struct_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
def: &hir::VariantData)
-> ty::AdtDefMaster<'tcx>
{
let did = ccx.tcx.map.local_def_id(it.id);
let ctor_id = if !def.is_struct() {
ccx.tcx.map.local_def_id(def.id())
} else {
did
};
ccx.tcx.intern_adt_def(did, ty::AdtKind::Struct,
vec![convert_struct_variant(ccx, ctor_id, it.name, ConstInt::Infer(0), def)])
// Use separate constructor id for unit/tuple structs and reuse did for braced structs.
let ctor_id = if !def.is_struct() { Some(ccx.tcx.map.local_def_id(def.id())) } else { None };
let variants = vec![convert_struct_variant(ccx, ctor_id.unwrap_or(did), it.name,
ConstInt::Infer(0), def)];
let adt = ccx.tcx.intern_adt_def(did, ty::AdtKind::Struct, variants);
if let Some(ctor_id) = ctor_id {
// Make adt definition available through constructor id as well.
ccx.tcx.insert_adt_def(ctor_id, adt);
}
adt
}
fn evaluate_disr_expr(ccx: &CrateCtxt, repr_ty: attr::IntType, e: &hir::Expr)

View File

@ -1895,33 +1895,6 @@ fn my_start(argc: isize, argv: *const *const u8) -> isize {
```
"##,
E0163: r##"
This error means that an attempt was made to match an enum variant as a
struct type when the variant isn't a struct type:
```compile_fail
enum Foo { B(u32) }
fn bar(foo: Foo) -> u32 {
match foo {
B{i} => i, // error E0163
}
}
```
Try using `()` instead:
```
enum Foo { B(u32) }
fn bar(foo: Foo) -> u32 {
match foo {
Foo::B(i) => i,
}
}
```
"##,
E0164: r##"
This error means that an attempt was made to match a struct type enum
variant as a non-struct type:
@ -3225,42 +3198,6 @@ impl Foo for Bar {
```
"##,
E0327: r##"
You cannot use associated items other than constant items as patterns. This
includes method items. Example of erroneous code:
```compile_fail
enum B {}
impl B {
fn bb() -> i32 { 0 }
}
fn main() {
match 0 {
B::bb => {} // error: associated items in match patterns must
// be constants
}
}
```
Please check that you're not using a method as a pattern. Example:
```
enum B {
ba,
bb
}
fn main() {
match B::ba {
B::bb => {} // ok!
_ => {}
}
}
```
"##,
E0329: r##"
An attempt was made to access an associated constant through either a generic
type parameter or `Self`. This is not supported yet. An example causing this
@ -4106,6 +4043,7 @@ register_diagnostics! {
// E0129,
// E0141,
// E0159, // use of trait `{}` as struct constructor
// E0163, // merged into E0071
E0167,
// E0168,
// E0173, // manual implementations of unboxed closure traits are experimental
@ -4162,4 +4100,5 @@ register_diagnostics! {
E0527, // expected {} elements, found {}
E0528, // expected at least {} elements, found {}
E0529, // slice pattern expects array or slice, not `{}`
E0533, // `{}` does not name a unit variant, unit struct or a constant
}

View File

@ -1904,7 +1904,7 @@ impl Clean<Item> for doctree::Variant {
impl<'tcx> Clean<Item> for ty::VariantDefData<'tcx, 'static> {
fn clean(&self, cx: &DocContext) -> Item {
let kind = match self.kind() {
let kind = match self.kind {
ty::VariantKind::Unit => CLikeVariant,
ty::VariantKind::Tuple => {
TupleVariant(
@ -2578,9 +2578,9 @@ fn name_from_pat(p: &hir::Pat) -> String {
match p.node {
PatKind::Wild => "_".to_string(),
PatKind::Binding(_, ref p, _) => p.node.to_string(),
PatKind::TupleStruct(ref p, _, _) | PatKind::Path(ref p) => path_to_string(p),
PatKind::QPath(..) => panic!("tried to get argument name from PatKind::QPath, \
which is not allowed in function arguments"),
PatKind::TupleStruct(ref p, _, _) | PatKind::Path(None, ref p) => path_to_string(p),
PatKind::Path(..) => panic!("tried to get argument name from qualified PatKind::Path, \
which is not allowed in function arguments"),
PatKind::Struct(ref name, ref fields, etc) => {
format!("{} {{ {}{} }}", path_to_string(name),
fields.iter().map(|&Spanned { node: ref fp, .. }|
@ -2653,7 +2653,7 @@ fn resolve_type(cx: &DocContext,
Def::SelfTy(..) if path.segments.len() == 1 => {
return Generic(keywords::SelfType.name().to_string());
}
Def::SelfTy(..) | Def::TyParam(..) => true,
Def::SelfTy(..) | Def::TyParam(..) | Def::AssociatedTy(..) => true,
_ => false,
};
let did = register_def(&*cx, def);

View File

@ -16,6 +16,5 @@ pub use use_from_trait_xc::Trait;
fn main() {
match () {
Trait { x: 42 } => () //~ ERROR expected variant, struct or type alias, found trait `Trait`
//~^ ERROR `Trait` does not name a struct or a struct variant
}
}

View File

@ -10,6 +10,7 @@
#![crate_name="lint_stability"]
#![crate_type = "lib"]
#![feature(staged_api)]
#![feature(associated_type_defaults)]
#![stable(feature = "lint_stability", since = "1.0.0")]
#[stable(feature = "test_feature", since = "1.0.0")]
@ -92,6 +93,15 @@ pub trait Trait {
fn trait_stable_text(&self) {}
}
#[stable(feature = "test_feature", since = "1.0.0")]
pub trait TraitWithAssociatedTypes {
#[unstable(feature = "test_feature", issue = "0")]
type TypeUnstable = u8;
#[stable(feature = "test_feature", since = "1.0.0")]
#[rustc_deprecated(since = "1.0.0", reason = "text")]
type TypeDeprecated = u8;
}
#[stable(feature = "test_feature", since = "1.0.0")]
impl Trait for MethodTester {}

View File

@ -31,12 +31,14 @@ fn main() {
Empty1 => () // Not an error, `Empty1` is interpreted as a new binding
}
match e3 {
E::Empty3 => () //~ ERROR `E::Empty3` does not name a tuple variant or a tuple struct
E::Empty3 => ()
//~^ ERROR `E::Empty3` does not name a unit variant, unit struct or a constant
}
match xe1 {
XEmpty1 => () // Not an error, `XEmpty1` is interpreted as a new binding
}
match xe3 {
XE::XEmpty3 => () //~ ERROR `XE::XEmpty3` does not name a tuple variant or a tuple struct
XE::XEmpty3 => ()
//~^ ERROR `XE::XEmpty3` does not name a unit variant, unit struct or a constant
}
}

View File

@ -16,7 +16,7 @@ pub struct GslResult {
impl GslResult {
pub fn new() -> GslResult {
Result { //~ ERROR: `Result` does not name a structure
Result { //~ ERROR: `Result` does not name a struct or a struct variant
val: 0f64,
err: 0f64
}

View File

@ -11,5 +11,5 @@
mod foo {}
fn main() {
let p = foo { x: () }; //~ ERROR `foo` does not name a structure
let p = foo { x: () }; //~ ERROR `foo` does not name a struct or a struct variant
}

View File

@ -15,6 +15,5 @@ enum Foo {
fn main() {
match Foo::Bar(1) {
Foo { i } => () //~ ERROR expected variant, struct or type alias, found enum `Foo`
//~^ ERROR `Foo` does not name a struct or a struct variant
}
}

View File

@ -11,5 +11,5 @@
mod MyMod {}
fn main() {
let myVar = MyMod { T: 0 }; //~ ERROR `MyMod` does not name a structure
let myVar = MyMod { T: 0 }; //~ ERROR `MyMod` does not name a struct or a struct variant
}

View File

@ -0,0 +1,35 @@
// 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.
#![feature(rustc_attrs)]
#![allow(warnings)]
struct CNFParser {
token: char,
}
impl CNFParser {
fn is_whitespace(c: char) -> bool {
c == ' ' || c == '\n'
}
fn consume_whitespace(&mut self) {
self.consume_while(&(CNFParser::is_whitespace))
}
fn consume_while(&mut self, p: &Fn(char) -> bool) {
while p(self.token) {
return
}
}
}
#[rustc_error]
fn main() {} //~ ERROR compilation successful

View File

@ -0,0 +1,21 @@
// 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.
enum Delicious {
Pie = 0x1,
Apple = 0x2,
ApplePie = Delicious::Apple as isize | Delicious::PIE as isize,
//~^ ERROR constant evaluation error: unresolved path in constant expression
}
const FOO: [u32; u8::MIN as usize] = [];
//~^ ERROR array length constant evaluation error: unresolved path in constant expression
fn main() {}

View File

@ -12,6 +12,5 @@ fn main() {
match 'a' {
char{ch} => true
//~^ ERROR expected variant, struct or type alias, found builtin type `char`
//~| ERROR `char` does not name a struct or a struct variant
};
}

View File

@ -11,12 +11,10 @@
mod A {}
fn main() {
let u = A { x: 1 }; //~ ERROR `A` does not name a structure
let v = u32 { x: 1 }; //~ ERROR `u32` does not name a structure
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
match () {
A { x: 1 } => {} //~ ERROR expected variant, struct or type alias, found module `A`
//~^ ERROR `A` does not name a struct or a struct variant
u32 { x: 1 } => {} //~ ERROR expected variant, struct or type alias, found builtin type `u32
//~^ ERROR `u32` does not name a struct or a struct variant
}
}

View File

@ -18,7 +18,7 @@ enum Enum {
fn main() {
let x = Foo(1);
Foo { ..x }; //~ ERROR `Foo` does not name a structure
Foo { ..x }; //~ ERROR `Foo` does not name a struct or a struct variant
let Foo { .. } = x; //~ ERROR `Foo` does not name a struct
let x = Bar;

View File

@ -18,7 +18,7 @@ struct S;
fn main() {
match Foo::Baz {
Foo::Bar => {}
//~^ ERROR `Foo::Bar` does not name a tuple variant or a tuple struct
//~^ ERROR `Foo::Bar` does not name a unit variant, unit struct or a constant
_ => {}
}

View File

@ -8,13 +8,15 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
enum Foo { B(u32) }
enum S {
A,
}
fn bar(foo: Foo) -> u32 {
match foo {
Foo::B { i } => i, //~ ERROR E0163
fn bug(l: S) {
match l {
S::B{ } => { },
//~^ ERROR ambiguous associated type; specify the type using the syntax `<S as Trait>::B`
}
}
fn main() {
}
fn main () {}

View File

@ -11,5 +11,5 @@
struct NonCopyable(());
fn main() {
let z = NonCopyable{ p: () }; //~ ERROR `NonCopyable` does not name a structure
let z = NonCopyable{ p: () }; //~ ERROR `NonCopyable` does not name a struct or a struct variant
}

View File

@ -10,7 +10,7 @@
struct T { i: i32 }
fn f<T>() {
let t = T { i: 0 }; //~ ERROR `T` does not name a structure
let t = T { i: 0 }; //~ ERROR `T` does not name a struct or a struct variant
}
mod Foo {

View File

@ -128,6 +128,11 @@ mod cross_crate {
<Foo>::trait_stable_text(&foo);
<Foo as Trait>::trait_stable_text(&foo);
struct S1<T: TraitWithAssociatedTypes>(T::TypeUnstable);
//~^ ERROR use of unstable library feature
struct S2<T: TraitWithAssociatedTypes>(T::TypeDeprecated);
//~^ ERROR use of deprecated item
let _ = DeprecatedStruct { //~ ERROR use of deprecated item
i: 0 //~ ERROR use of deprecated item
};

View File

@ -22,12 +22,13 @@ impl MyTrait for Foo {}
fn main() {
match 0u32 {
Foo::bar => {} //~ ERROR E0327
Foo::bar => {} //~ ERROR `Foo::bar` does not name a unit variant, unit struct or a constant
}
match 0u32 {
<Foo>::bar => {} //~ ERROR E0327
<Foo>::bar => {} //~ ERROR `bar` does not name a unit variant, unit struct or a constant
}
match 0u32 {
<Foo>::trait_bar => {} //~ ERROR E0327
<Foo>::trait_bar => {}
//~^ ERROR `trait_bar` does not name a unit variant, unit struct or a constant
}
}

View File

@ -27,7 +27,8 @@ impl S {
fn main() {
match 10 {
<S as Tr>::A::f::<u8> => {} //~ ERROR associated items in match patterns must be constants
<S as Tr>::A::f::<u8> => {}
//~^ ERROR `Tr::A::f<u8>` does not name a unit variant, unit struct or a constant
0 ... <S as Tr>::A::f::<u8> => {} //~ ERROR only char and numeric types are allowed in range
}
}

View File

@ -0,0 +1,37 @@
// 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>() {
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 main() {
match S {
S::A {} => {} //~ ERROR ambiguous associated type
}
}

View File

@ -12,5 +12,5 @@ trait TraitNotAStruct {}
fn main() {
TraitNotAStruct{ value: 0 };
//~^ ERROR: `TraitNotAStruct` does not name a structure [E0071]
//~^ ERROR: `TraitNotAStruct` does not name a struct or a struct variant [E0071]
}