Skip to content

Commit f93aaf8

Browse files
authored
Auto merge of #34365 - petrochenkov:deferr, r=eddyb
Some more pattern cleanup and bugfixing The next part of #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 #34209 Closes #22933 (adds tests) r? @eddyb
2 parents d40c593 + d27e55c commit f93aaf8

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+646
-818
lines changed

src/libcore/ops.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1929,7 +1929,7 @@ pub trait FnMut<Args> : FnOnce<Args> {
19291929
#[fundamental] // so that regex can rely that `&str: !FnMut`
19301930
pub trait FnOnce<Args> {
19311931
/// The returned type after the call operator is used.
1932-
#[unstable(feature = "fn_traits", issue = "29625")]
1932+
#[stable(feature = "fn_once_output", since = "1.12.0")]
19331933
type Output;
19341934

19351935
/// This is called when the call operator is used.

src/librustc/cfg/construct.rs

-1
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,6 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
101101
match pat.node {
102102
PatKind::Binding(_, _, None) |
103103
PatKind::Path(..) |
104-
PatKind::QPath(..) |
105104
PatKind::Lit(..) |
106105
PatKind::Range(..) |
107106
PatKind::Wild => {

src/librustc/hir/def.rs

-9
Original file line numberDiff line numberDiff line change
@@ -137,15 +137,6 @@ impl Def {
137137
}
138138
}
139139

140-
pub fn variant_def_ids(&self) -> Option<(DefId, DefId)> {
141-
match *self {
142-
Def::Variant(enum_id, var_id) => {
143-
Some((enum_id, var_id))
144-
}
145-
_ => None
146-
}
147-
}
148-
149140
pub fn kind_name(&self) -> &'static str {
150141
match *self {
151142
Def::Fn(..) => "function",

src/librustc/hir/fold.rs

+5-6
Original file line numberDiff line numberDiff line change
@@ -930,12 +930,11 @@ pub fn noop_fold_pat<T: Folder>(p: P<Pat>, folder: &mut T) -> P<Pat> {
930930
PatKind::TupleStruct(folder.fold_path(pth),
931931
pats.move_map(|x| folder.fold_pat(x)), ddpos)
932932
}
933-
PatKind::Path(pth) => {
934-
PatKind::Path(folder.fold_path(pth))
935-
}
936-
PatKind::QPath(qself, pth) => {
937-
let qself = QSelf { ty: folder.fold_ty(qself.ty), ..qself };
938-
PatKind::QPath(qself, folder.fold_path(pth))
933+
PatKind::Path(opt_qself, pth) => {
934+
let opt_qself = opt_qself.map(|qself| {
935+
QSelf { ty: folder.fold_ty(qself.ty), position: qself.position }
936+
});
937+
PatKind::Path(opt_qself, folder.fold_path(pth))
939938
}
940939
PatKind::Struct(pth, fields, etc) => {
941940
let pth = folder.fold_path(pth);

src/librustc/hir/intravisit.rs

+4-5
Original file line numberDiff line numberDiff line change
@@ -460,11 +460,10 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat) {
460460
visitor.visit_path(path, pattern.id);
461461
walk_list!(visitor, visit_pat, children);
462462
}
463-
PatKind::Path(ref path) => {
464-
visitor.visit_path(path, pattern.id);
465-
}
466-
PatKind::QPath(ref qself, ref path) => {
467-
visitor.visit_ty(&qself.ty);
463+
PatKind::Path(ref opt_qself, ref path) => {
464+
if let Some(ref qself) = *opt_qself {
465+
visitor.visit_ty(&qself.ty);
466+
}
468467
visitor.visit_path(path, pattern.id)
469468
}
470469
PatKind::Struct(ref path, ref fields, _) => {

src/librustc/hir/lowering.rs

+8-11
Original file line numberDiff line numberDiff line change
@@ -862,7 +862,8 @@ impl<'a> LoweringContext<'a> {
862862
respan(pth1.span, pth1.node.name),
863863
sub.as_ref().map(|x| this.lower_pat(x)))
864864
}
865-
_ => hir::PatKind::Path(hir::Path::from_name(pth1.span, pth1.node.name))
865+
_ => hir::PatKind::Path(None, hir::Path::from_name(pth1.span,
866+
pth1.node.name))
866867
}
867868
})
868869
}
@@ -872,15 +873,11 @@ impl<'a> LoweringContext<'a> {
872873
pats.iter().map(|x| self.lower_pat(x)).collect(),
873874
ddpos)
874875
}
875-
PatKind::Path(None, ref pth) => {
876-
hir::PatKind::Path(self.lower_path(pth))
877-
}
878-
PatKind::Path(Some(ref qself), ref pth) => {
879-
let qself = hir::QSelf {
880-
ty: self.lower_ty(&qself.ty),
881-
position: qself.position,
882-
};
883-
hir::PatKind::QPath(qself, self.lower_path(pth))
876+
PatKind::Path(ref opt_qself, ref path) => {
877+
let opt_qself = opt_qself.as_ref().map(|qself| {
878+
hir::QSelf { ty: self.lower_ty(&qself.ty), position: qself.position }
879+
});
880+
hir::PatKind::Path(opt_qself, self.lower_path(path))
884881
}
885882
PatKind::Struct(ref pth, ref fields, etc) => {
886883
let pth = self.lower_path(pth);
@@ -1831,7 +1828,7 @@ impl<'a> LoweringContext<'a> {
18311828
-> P<hir::Pat> {
18321829
let def = self.resolver.resolve_generated_global_path(&path, true);
18331830
let pt = if subpats.is_empty() {
1834-
hir::PatKind::Path(path)
1831+
hir::PatKind::Path(None, path)
18351832
} else {
18361833
hir::PatKind::TupleStruct(path, subpats, None)
18371834
};

src/librustc/hir/mod.rs

+3-10
Original file line numberDiff line numberDiff line change
@@ -487,8 +487,7 @@ impl Pat {
487487
PatKind::Lit(_) |
488488
PatKind::Range(_, _) |
489489
PatKind::Binding(..) |
490-
PatKind::Path(..) |
491-
PatKind::QPath(_, _) => {
490+
PatKind::Path(..) => {
492491
true
493492
}
494493
}
@@ -538,15 +537,9 @@ pub enum PatKind {
538537
/// 0 <= position <= subpats.len()
539538
TupleStruct(Path, HirVec<P<Pat>>, Option<usize>),
540539

541-
/// A path pattern.
540+
/// A possibly qualified path pattern.
542541
/// Such pattern can be resolved to a unit struct/variant or a constant.
543-
Path(Path),
544-
545-
/// An associated const named using the qualified path `<T>::CONST` or
546-
/// `<T as Trait>::CONST`. Associated consts from inherent impls can be
547-
/// referred to as simply `T::CONST`, in which case they will end up as
548-
/// PatKind::Path, and the resolver will have to sort that out.
549-
QPath(QSelf, Path),
542+
Path(Option<QSelf>, Path),
550543

551544
/// A tuple pattern `(a, b)`.
552545
/// If the `..` pattern fragment is present, then `Option<usize>` denotes its position.

src/librustc/hir/pat_util.rs

+2-35
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,12 @@ use hir::def::*;
1212
use hir::def_id::DefId;
1313
use hir::{self, PatKind};
1414
use ty::TyCtxt;
15-
use util::nodemap::FnvHashMap;
1615
use syntax::ast;
1716
use syntax::codemap::Spanned;
1817
use syntax_pos::{Span, DUMMY_SP};
1918

2019
use std::iter::{Enumerate, ExactSizeIterator};
2120

22-
pub type PatIdMap = FnvHashMap<ast::Name, ast::NodeId>;
23-
2421
pub struct EnumerateAndAdjust<I> {
2522
enumerate: Enumerate<I>,
2623
gap_pos: usize,
@@ -56,7 +53,7 @@ impl<T: ExactSizeIterator> EnumerateAndAdjustIterator for T {
5653

5754
pub fn pat_is_refutable(dm: &DefMap, pat: &hir::Pat) -> bool {
5855
match pat.node {
59-
PatKind::Lit(_) | PatKind::Range(_, _) | PatKind::QPath(..) => true,
56+
PatKind::Lit(_) | PatKind::Range(_, _) | PatKind::Path(Some(..), _) => true,
6057
PatKind::TupleStruct(..) |
6158
PatKind::Path(..) |
6259
PatKind::Struct(..) => {
@@ -70,23 +67,9 @@ pub fn pat_is_refutable(dm: &DefMap, pat: &hir::Pat) -> bool {
7067
}
7168
}
7269

73-
pub fn pat_is_variant_or_struct(dm: &DefMap, pat: &hir::Pat) -> bool {
74-
match pat.node {
75-
PatKind::TupleStruct(..) |
76-
PatKind::Path(..) |
77-
PatKind::Struct(..) => {
78-
match dm.get(&pat.id).map(|d| d.full_def()) {
79-
Some(Def::Variant(..)) | Some(Def::Struct(..)) | Some(Def::TyAlias(..)) => true,
80-
_ => false
81-
}
82-
}
83-
_ => false
84-
}
85-
}
86-
8770
pub fn pat_is_const(dm: &DefMap, pat: &hir::Pat) -> bool {
8871
match pat.node {
89-
PatKind::Path(..) | PatKind::QPath(..) => {
72+
PatKind::Path(..) => {
9073
match dm.get(&pat.id).map(|d| d.full_def()) {
9174
Some(Def::Const(..)) | Some(Def::AssociatedConst(..)) => true,
9275
_ => false
@@ -96,22 +79,6 @@ pub fn pat_is_const(dm: &DefMap, pat: &hir::Pat) -> bool {
9679
}
9780
}
9881

99-
// Same as above, except that partially-resolved defs cause `false` to be
100-
// returned instead of a panic.
101-
pub fn pat_is_resolved_const(dm: &DefMap, pat: &hir::Pat) -> bool {
102-
match pat.node {
103-
PatKind::Path(..) | PatKind::QPath(..) => {
104-
match dm.get(&pat.id)
105-
.and_then(|d| if d.depth == 0 { Some(d.base_def) }
106-
else { None } ) {
107-
Some(Def::Const(..)) | Some(Def::AssociatedConst(..)) => true,
108-
_ => false
109-
}
110-
}
111-
_ => false
112-
}
113-
}
114-
11582
/// Call `f` on every "binding" in a pattern, e.g., on `a` in
11683
/// `match foo() { Some(a) => (), None => () }`
11784
pub fn pat_bindings<F>(pat: &hir::Pat, mut f: F)

src/librustc/hir/print.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1750,10 +1750,10 @@ impl<'a> State<'a> {
17501750
}
17511751
try!(self.pclose());
17521752
}
1753-
PatKind::Path(ref path) => {
1753+
PatKind::Path(None, ref path) => {
17541754
self.print_path(path, true, 0)?;
17551755
}
1756-
PatKind::QPath(ref qself, ref path) => {
1756+
PatKind::Path(Some(ref qself), ref path) => {
17571757
self.print_qpath(path, qself, false)?;
17581758
}
17591759
PatKind::Struct(ref path, ref fields, etc) => {

src/librustc/middle/expr_use_visitor.rs

+39-99
Original file line numberDiff line numberDiff line change
@@ -945,52 +945,41 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
945945
/// The core driver for walking a pattern; `match_mode` must be
946946
/// established up front, e.g. via `determine_pat_move_mode` (see
947947
/// also `walk_irrefutable_pat` for patterns that stand alone).
948-
fn walk_pat(&mut self,
949-
cmt_discr: mc::cmt<'tcx>,
950-
pat: &hir::Pat,
951-
match_mode: MatchMode) {
952-
debug!("walk_pat cmt_discr={:?} pat={:?}", cmt_discr,
953-
pat);
948+
fn walk_pat(&mut self, cmt_discr: mc::cmt<'tcx>, pat: &hir::Pat, match_mode: MatchMode) {
949+
debug!("walk_pat cmt_discr={:?} pat={:?}", cmt_discr, pat);
954950

955951
let tcx = &self.tcx();
956952
let mc = &self.mc;
957953
let infcx = self.mc.infcx;
958954
let delegate = &mut self.delegate;
959955
return_if_err!(mc.cat_pattern(cmt_discr.clone(), pat, |mc, cmt_pat, pat| {
960-
match pat.node {
961-
PatKind::Binding(bmode, _, _) => {
962-
debug!("binding cmt_pat={:?} pat={:?} match_mode={:?}",
963-
cmt_pat,
964-
pat,
965-
match_mode);
966-
967-
// pat_ty: the type of the binding being produced.
968-
let pat_ty = return_if_err!(infcx.node_ty(pat.id));
969-
970-
// Each match binding is effectively an assignment to the
971-
// binding being produced.
972-
if let Ok(binding_cmt) = mc.cat_def(pat.id, pat.span, pat_ty,
973-
tcx.expect_def(pat.id)) {
974-
delegate.mutate(pat.id, pat.span, binding_cmt, MutateMode::Init);
975-
}
956+
if let PatKind::Binding(bmode, _, _) = pat.node {
957+
debug!("binding cmt_pat={:?} pat={:?} match_mode={:?}", cmt_pat, pat, match_mode);
976958

977-
// It is also a borrow or copy/move of the value being matched.
978-
match bmode {
979-
hir::BindByRef(m) => {
980-
if let ty::TyRef(&r, _) = pat_ty.sty {
981-
let bk = ty::BorrowKind::from_mutbl(m);
982-
delegate.borrow(pat.id, pat.span, cmt_pat,
983-
r, bk, RefBinding);
984-
}
985-
}
986-
hir::BindByValue(..) => {
987-
let mode = copy_or_move(infcx, &cmt_pat, PatBindingMove);
988-
debug!("walk_pat binding consuming pat");
989-
delegate.consume_pat(pat, cmt_pat, mode);
959+
// pat_ty: the type of the binding being produced.
960+
let pat_ty = return_if_err!(infcx.node_ty(pat.id));
961+
962+
// Each match binding is effectively an assignment to the
963+
// binding being produced.
964+
if let Ok(binding_cmt) = mc.cat_def(pat.id, pat.span, pat_ty,
965+
tcx.expect_def(pat.id)) {
966+
delegate.mutate(pat.id, pat.span, binding_cmt, MutateMode::Init);
967+
}
968+
969+
// It is also a borrow or copy/move of the value being matched.
970+
match bmode {
971+
hir::BindByRef(m) => {
972+
if let ty::TyRef(&r, _) = pat_ty.sty {
973+
let bk = ty::BorrowKind::from_mutbl(m);
974+
delegate.borrow(pat.id, pat.span, cmt_pat, r, bk, RefBinding);
990975
}
991976
}
977+
hir::BindByValue(..) => {
978+
let mode = copy_or_move(infcx, &cmt_pat, PatBindingMove);
979+
debug!("walk_pat binding consuming pat");
980+
delegate.consume_pat(pat, cmt_pat, mode);
981+
}
992982
}
993-
_ => {}
994983
}
995984
}));
996985

@@ -999,72 +988,23 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
999988
// to the above loop's visit of than the bindings that form
1000989
// the leaves of the pattern tree structure.
1001990
return_if_err!(mc.cat_pattern(cmt_discr, pat, |mc, cmt_pat, pat| {
1002-
match pat.node {
1003-
PatKind::Struct(..) | PatKind::TupleStruct(..) |
1004-
PatKind::Path(..) | PatKind::QPath(..) => {
1005-
match tcx.expect_def(pat.id) {
1006-
Def::Variant(enum_did, variant_did) => {
1007-
let downcast_cmt =
1008-
if tcx.lookup_adt_def(enum_did).is_univariant() {
1009-
cmt_pat
1010-
} else {
1011-
let cmt_pat_ty = cmt_pat.ty;
1012-
mc.cat_downcast(pat, cmt_pat, cmt_pat_ty, variant_did)
1013-
};
1014-
1015-
debug!("variant downcast_cmt={:?} pat={:?}",
1016-
downcast_cmt,
1017-
pat);
1018-
1019-
delegate.matched_pat(pat, downcast_cmt, match_mode);
1020-
}
1021-
1022-
Def::Struct(..) | Def::TyAlias(..) => {
1023-
// A struct (in either the value or type
1024-
// namespace; we encounter the former on
1025-
// e.g. patterns for unit structs).
1026-
1027-
debug!("struct cmt_pat={:?} pat={:?}",
1028-
cmt_pat,
1029-
pat);
1030-
1031-
delegate.matched_pat(pat, cmt_pat, match_mode);
1032-
}
1033-
1034-
Def::Const(..) | Def::AssociatedConst(..) => {
1035-
// This is a leaf (i.e. identifier binding
1036-
// or constant value to match); thus no
1037-
// `matched_pat` call.
1038-
}
991+
match tcx.expect_def_or_none(pat.id) {
992+
Some(Def::Variant(enum_did, variant_did)) => {
993+
let downcast_cmt = if tcx.lookup_adt_def(enum_did).is_univariant() {
994+
cmt_pat
995+
} else {
996+
let cmt_pat_ty = cmt_pat.ty;
997+
mc.cat_downcast(pat, cmt_pat, cmt_pat_ty, variant_did)
998+
};
1039999

1040-
def => {
1041-
// An enum type should never be in a pattern.
1042-
// Remaining cases are e.g. Def::Fn, to
1043-
// which identifiers within patterns
1044-
// should not resolve. However, we do
1045-
// encouter this when using the
1046-
// expr-use-visitor during typeck. So just
1047-
// ignore it, an error should have been
1048-
// reported.
1049-
1050-
if !tcx.sess.has_errors() {
1051-
span_bug!(pat.span,
1052-
"Pattern has unexpected def: {:?} and type {:?}",
1053-
def,
1054-
cmt_pat.ty);
1055-
}
1056-
}
1057-
}
1000+
debug!("variant downcast_cmt={:?} pat={:?}", downcast_cmt, pat);
1001+
delegate.matched_pat(pat, downcast_cmt, match_mode);
10581002
}
1059-
1060-
PatKind::Wild | PatKind::Tuple(..) | PatKind::Box(..) |
1061-
PatKind::Ref(..) | PatKind::Lit(..) | PatKind::Range(..) |
1062-
PatKind::Vec(..) | PatKind::Binding(..) => {
1063-
// Each of these cases does not
1064-
// correspond to an enum variant or struct, so we
1065-
// do not do any `matched_pat` calls for these
1066-
// cases either.
1003+
Some(Def::Struct(..)) | Some(Def::TyAlias(..)) | Some(Def::AssociatedTy(..)) => {
1004+
debug!("struct cmt_pat={:?} pat={:?}", cmt_pat, pat);
1005+
delegate.matched_pat(pat, cmt_pat, match_mode);
10671006
}
1007+
_ => {}
10681008
}
10691009
}));
10701010
}

0 commit comments

Comments
 (0)