Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
int
Rust
提交
c9aff92e
R
Rust
项目概览
int
/
Rust
接近 1 年 前同步成功
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
R
Rust
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
c9aff92e
编写于
2月 24, 2018
作者:
V
Vadim Petrochenkov
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Support parentheses in patterns under feature gate
Improve recovery for trailing comma after `..`
上级
0ff9872b
变更
12
隐藏空白更改
内联
并排
Showing
12 changed file
with
166 addition
and
107 deletion
+166
-107
src/librustc/hir/lowering.rs
src/librustc/hir/lowering.rs
+78
-76
src/librustc_lint/builtin.rs
src/librustc_lint/builtin.rs
+1
-0
src/libsyntax/ast.rs
src/libsyntax/ast.rs
+3
-1
src/libsyntax/feature_gate.rs
src/libsyntax/feature_gate.rs
+7
-0
src/libsyntax/fold.rs
src/libsyntax/fold.rs
+1
-0
src/libsyntax/parse/parser.rs
src/libsyntax/parse/parser.rs
+40
-26
src/libsyntax/print/pprust.rs
src/libsyntax/print/pprust.rs
+5
-0
src/libsyntax/visit.rs
src/libsyntax/visit.rs
+2
-1
src/test/parse-fail/pat-tuple-2.rs
src/test/parse-fail/pat-tuple-2.rs
+1
-1
src/test/run-pass/pat-tuple-7.rs
src/test/run-pass/pat-tuple-7.rs
+2
-2
src/test/ui/feature-gate-pattern_parentheses.rs
src/test/ui/feature-gate-pattern_parentheses.rs
+15
-0
src/test/ui/feature-gate-pattern_parentheses.stderr
src/test/ui/feature-gate-pattern_parentheses.stderr
+11
-0
未找到文件。
src/librustc/hir/lowering.rs
浏览文件 @
c9aff92e
...
...
@@ -2465,86 +2465,88 @@ fn lower_binop(&mut self, b: BinOp) -> hir::BinOp {
}
fn
lower_pat
(
&
mut
self
,
p
:
&
Pat
)
->
P
<
hir
::
Pat
>
{
let
LoweredNodeId
{
node_id
,
hir_id
}
=
self
.lower_node_id
(
p
.id
);
let
node
=
match
p
.node
{
PatKind
::
Wild
=>
hir
::
PatKind
::
Wild
,
PatKind
::
Ident
(
ref
binding_mode
,
pth1
,
ref
sub
)
=>
{
match
self
.resolver
.get_resolution
(
p
.id
)
.map
(|
d
|
d
.base_def
())
{
// `None` can occur in body-less function signatures
def
@
None
|
def
@
Some
(
Def
::
Local
(
_
))
=>
{
let
canonical_id
=
match
def
{
Some
(
Def
::
Local
(
id
))
=>
id
,
_
=>
p
.id
};
hir
::
PatKind
::
Binding
(
self
.lower_binding_mode
(
binding_mode
),
canonical_id
,
respan
(
pth1
.span
,
pth1
.node.name
),
sub
.as_ref
()
.map
(|
x
|
self
.lower_pat
(
x
)))
}
Some
(
def
)
=>
{
hir
::
PatKind
::
Path
(
hir
::
QPath
::
Resolved
(
None
,
P
(
hir
::
Path
{
span
:
pth1
.span
,
def
,
segments
:
hir_vec!
[
hir
::
PathSegment
::
from_name
(
pth1
.node.name
)
],
})))
}
}
}
PatKind
::
Lit
(
ref
e
)
=>
hir
::
PatKind
::
Lit
(
P
(
self
.lower_expr
(
e
))),
PatKind
::
TupleStruct
(
ref
path
,
ref
pats
,
ddpos
)
=>
{
let
qpath
=
self
.lower_qpath
(
p
.id
,
&
None
,
path
,
ParamMode
::
Optional
,
ImplTraitContext
::
Disallowed
);
hir
::
PatKind
::
TupleStruct
(
qpath
,
pats
.iter
()
.map
(|
x
|
self
.lower_pat
(
x
))
.collect
(),
ddpos
)
}
PatKind
::
Path
(
ref
qself
,
ref
path
)
=>
{
hir
::
PatKind
::
Path
(
self
.lower_qpath
(
p
.id
,
qself
,
path
,
ParamMode
::
Optional
,
ImplTraitContext
::
Disallowed
))
}
PatKind
::
Struct
(
ref
path
,
ref
fields
,
etc
)
=>
{
let
qpath
=
self
.lower_qpath
(
p
.id
,
&
None
,
path
,
ParamMode
::
Optional
,
ImplTraitContext
::
Disallowed
);
let
fs
=
fields
.iter
()
.map
(|
f
|
{
Spanned
{
span
:
f
.span
,
node
:
hir
::
FieldPat
{
name
:
self
.lower_ident
(
f
.node.ident
),
pat
:
self
.lower_pat
(
&
f
.node.pat
),
is_shorthand
:
f
.node.is_shorthand
,
},
}
})
.collect
();
hir
::
PatKind
::
Struct
(
qpath
,
fs
,
etc
)
}
PatKind
::
Tuple
(
ref
elts
,
ddpos
)
=>
{
hir
::
PatKind
::
Tuple
(
elts
.iter
()
.map
(|
x
|
self
.lower_pat
(
x
))
.collect
(),
ddpos
)
}
PatKind
::
Box
(
ref
inner
)
=>
hir
::
PatKind
::
Box
(
self
.lower_pat
(
inner
)),
PatKind
::
Ref
(
ref
inner
,
mutbl
)
=>
{
hir
::
PatKind
::
Ref
(
self
.lower_pat
(
inner
),
self
.lower_mutability
(
mutbl
))
}
PatKind
::
Range
(
ref
e1
,
ref
e2
,
ref
end
)
=>
{
hir
::
PatKind
::
Range
(
P
(
self
.lower_expr
(
e1
)),
P
(
self
.lower_expr
(
e2
)),
self
.lower_range_end
(
end
))
}
PatKind
::
Slice
(
ref
before
,
ref
slice
,
ref
after
)
=>
{
hir
::
PatKind
::
Slice
(
before
.iter
()
.map
(|
x
|
self
.lower_pat
(
x
))
.collect
(),
slice
.as_ref
()
.map
(|
x
|
self
.lower_pat
(
x
)),
after
.iter
()
.map
(|
x
|
self
.lower_pat
(
x
))
.collect
())
}
PatKind
::
Paren
(
ref
inner
)
=>
return
self
.lower_pat
(
inner
),
PatKind
::
Mac
(
_
)
=>
panic!
(
"Shouldn't exist here"
),
};
let
LoweredNodeId
{
node_id
,
hir_id
}
=
self
.lower_node_id
(
p
.id
);
P
(
hir
::
Pat
{
id
:
node_id
,
hir_id
,
node
:
match
p
.node
{
PatKind
::
Wild
=>
hir
::
PatKind
::
Wild
,
PatKind
::
Ident
(
ref
binding_mode
,
pth1
,
ref
sub
)
=>
{
match
self
.resolver
.get_resolution
(
p
.id
)
.map
(|
d
|
d
.base_def
())
{
// `None` can occur in body-less function signatures
def
@
None
|
def
@
Some
(
Def
::
Local
(
_
))
=>
{
let
canonical_id
=
match
def
{
Some
(
Def
::
Local
(
id
))
=>
id
,
_
=>
p
.id
};
hir
::
PatKind
::
Binding
(
self
.lower_binding_mode
(
binding_mode
),
canonical_id
,
respan
(
pth1
.span
,
pth1
.node.name
),
sub
.as_ref
()
.map
(|
x
|
self
.lower_pat
(
x
)))
}
Some
(
def
)
=>
{
hir
::
PatKind
::
Path
(
hir
::
QPath
::
Resolved
(
None
,
P
(
hir
::
Path
{
span
:
pth1
.span
,
def
,
segments
:
hir_vec!
[
hir
::
PathSegment
::
from_name
(
pth1
.node.name
)
],
})))
}
}
}
PatKind
::
Lit
(
ref
e
)
=>
hir
::
PatKind
::
Lit
(
P
(
self
.lower_expr
(
e
))),
PatKind
::
TupleStruct
(
ref
path
,
ref
pats
,
ddpos
)
=>
{
let
qpath
=
self
.lower_qpath
(
p
.id
,
&
None
,
path
,
ParamMode
::
Optional
,
ImplTraitContext
::
Disallowed
);
hir
::
PatKind
::
TupleStruct
(
qpath
,
pats
.iter
()
.map
(|
x
|
self
.lower_pat
(
x
))
.collect
(),
ddpos
)
}
PatKind
::
Path
(
ref
qself
,
ref
path
)
=>
{
hir
::
PatKind
::
Path
(
self
.lower_qpath
(
p
.id
,
qself
,
path
,
ParamMode
::
Optional
,
ImplTraitContext
::
Disallowed
))
}
PatKind
::
Struct
(
ref
path
,
ref
fields
,
etc
)
=>
{
let
qpath
=
self
.lower_qpath
(
p
.id
,
&
None
,
path
,
ParamMode
::
Optional
,
ImplTraitContext
::
Disallowed
);
let
fs
=
fields
.iter
()
.map
(|
f
|
{
Spanned
{
span
:
f
.span
,
node
:
hir
::
FieldPat
{
name
:
self
.lower_ident
(
f
.node.ident
),
pat
:
self
.lower_pat
(
&
f
.node.pat
),
is_shorthand
:
f
.node.is_shorthand
,
},
}
})
.collect
();
hir
::
PatKind
::
Struct
(
qpath
,
fs
,
etc
)
}
PatKind
::
Tuple
(
ref
elts
,
ddpos
)
=>
{
hir
::
PatKind
::
Tuple
(
elts
.iter
()
.map
(|
x
|
self
.lower_pat
(
x
))
.collect
(),
ddpos
)
}
PatKind
::
Box
(
ref
inner
)
=>
hir
::
PatKind
::
Box
(
self
.lower_pat
(
inner
)),
PatKind
::
Ref
(
ref
inner
,
mutbl
)
=>
{
hir
::
PatKind
::
Ref
(
self
.lower_pat
(
inner
),
self
.lower_mutability
(
mutbl
))
}
PatKind
::
Range
(
ref
e1
,
ref
e2
,
ref
end
)
=>
{
hir
::
PatKind
::
Range
(
P
(
self
.lower_expr
(
e1
)),
P
(
self
.lower_expr
(
e2
)),
self
.lower_range_end
(
end
))
}
PatKind
::
Slice
(
ref
before
,
ref
slice
,
ref
after
)
=>
{
hir
::
PatKind
::
Slice
(
before
.iter
()
.map
(|
x
|
self
.lower_pat
(
x
))
.collect
(),
slice
.as_ref
()
.map
(|
x
|
self
.lower_pat
(
x
)),
after
.iter
()
.map
(|
x
|
self
.lower_pat
(
x
))
.collect
())
}
PatKind
::
Mac
(
_
)
=>
panic!
(
"Shouldn't exist here"
),
},
node
,
span
:
p
.span
,
})
}
...
...
src/librustc_lint/builtin.rs
浏览文件 @
c9aff92e
...
...
@@ -737,6 +737,7 @@ fn check_pat(&mut self, cx: &EarlyContext, pat: &ast::Pat) {
PatKind
::
TupleStruct
(
..
)
|
PatKind
::
Ref
(
..
)
|
PatKind
::
Box
(
..
)
|
PatKind
::
Paren
(
..
)
|
PatKind
::
Slice
(
..
)
=>
(),
// Extract the expressions and check them
...
...
src/libsyntax/ast.rs
浏览文件 @
c9aff92e
...
...
@@ -562,7 +562,7 @@ pub fn walk<F>(&self, it: &mut F) -> bool
PatKind
::
TupleStruct
(
_
,
ref
s
,
_
)
|
PatKind
::
Tuple
(
ref
s
,
_
)
=>
{
s
.iter
()
.all
(|
p
|
p
.walk
(
it
))
}
PatKind
::
Box
(
ref
s
)
|
PatKind
::
Ref
(
ref
s
,
_
)
=>
{
PatKind
::
Box
(
ref
s
)
|
PatKind
::
Ref
(
ref
s
,
_
)
|
PatKind
::
Paren
(
ref
s
)
=>
{
s
.walk
(
it
)
}
PatKind
::
Slice
(
ref
before
,
ref
slice
,
ref
after
)
=>
{
...
...
@@ -656,6 +656,8 @@ pub enum PatKind {
/// `[a, b, ..i, y, z]` is represented as:
/// `PatKind::Slice(box [a, b], Some(i), box [y, z])`
Slice
(
Vec
<
P
<
Pat
>>
,
Option
<
P
<
Pat
>>
,
Vec
<
P
<
Pat
>>
),
/// Parentheses in patters used for grouping, i.e. `(PAT)`.
Paren
(
P
<
Pat
>
),
/// A macro pattern; pre-expansion
Mac
(
Mac
),
}
...
...
src/libsyntax/feature_gate.rs
浏览文件 @
c9aff92e
...
...
@@ -449,6 +449,9 @@ pub fn new() -> Features {
// Multiple patterns with `|` in `if let` and `while let`
(
active
,
if_while_or_patterns
,
"1.26.0"
,
Some
(
48215
)),
// Parentheses in patterns
(
active
,
pattern_parentheses
,
"1.26.0"
,
None
),
);
declare_features!
(
...
...
@@ -1663,6 +1666,10 @@ fn visit_pat(&mut self, pattern: &'a ast::Pat) {
gate_feature_post!
(
&
self
,
dotdoteq_in_patterns
,
pattern
.span
,
"`..=` syntax in patterns is experimental"
);
}
PatKind
::
Paren
(
..
)
=>
{
gate_feature_post!
(
&
self
,
pattern_parentheses
,
pattern
.span
,
"parentheses in patterns are unstable"
);
}
_
=>
{}
}
visit
::
walk_pat
(
self
,
pattern
)
...
...
src/libsyntax/fold.rs
浏览文件 @
c9aff92e
...
...
@@ -1148,6 +1148,7 @@ pub fn noop_fold_pat<T: Folder>(p: P<Pat>, folder: &mut T) -> P<Pat> {
slice
.map
(|
x
|
folder
.fold_pat
(
x
)),
after
.move_map
(|
x
|
folder
.fold_pat
(
x
)))
}
PatKind
::
Paren
(
inner
)
=>
PatKind
::
Paren
(
folder
.fold_pat
(
inner
)),
PatKind
::
Mac
(
mac
)
=>
PatKind
::
Mac
(
folder
.fold_mac
(
mac
))
},
span
:
folder
.new_span
(
span
)
...
...
src/libsyntax/parse/parser.rs
浏览文件 @
c9aff92e
...
...
@@ -3484,33 +3484,47 @@ fn parse_pats(&mut self) -> PResult<'a, Vec<P<Pat>>> {
};
}
fn
parse_pat_tuple_elements
(
&
mut
self
,
unary_needs_comma
:
bool
)
->
PResult
<
'a
,
(
Vec
<
P
<
Pat
>>
,
Option
<
usize
>
)
>
{
let
mut
fields
=
vec!
[];
let
mut
ddpos
=
None
;
// Parses a parenthesized list of patterns like
// `()`, `(p)`, `(p,)`, `(p, q)`, or `(p, .., q)`. Returns:
// - a vector of the patterns that were parsed
// - an option indicating the index of the `..` element
// - a boolean indicating whether a trailing comma was present.
// Trailing commas are significant because (p) and (p,) are different patterns.
fn
parse_parenthesized_pat_list
(
&
mut
self
)
->
PResult
<
'a
,
(
Vec
<
P
<
Pat
>>
,
Option
<
usize
>
,
bool
)
>
{
self
.expect
(
&
token
::
OpenDelim
(
token
::
Paren
))
?
;
while
!
self
.check
(
&
token
::
CloseDelim
(
token
::
Paren
))
{
if
ddpos
.is_none
()
&&
self
.eat
(
&
token
::
DotDot
)
{
ddpos
=
Some
(
fields
.len
());
if
self
.eat
(
&
token
::
Comma
)
{
// `..` needs to be followed by `)` or `, pat`, `..,)` is disallowed.
fields
.push
(
self
.parse_pat
()
?
);
let
mut
fields
=
Vec
::
new
();
let
mut
ddpos
=
None
;
let
mut
trailing_comma
=
false
;
loop
{
if
self
.eat
(
&
token
::
DotDot
)
{
if
ddpos
.is_none
()
{
ddpos
=
Some
(
fields
.len
());
}
else
{
// Emit a friendly error, ignore `..` and continue parsing
self
.span_err
(
self
.prev_span
,
"`..` can only be used once per tuple or tuple struct pattern"
);
}
}
else
if
ddpos
.is_some
()
&&
self
.eat
(
&
token
::
DotDot
)
{
// Emit a friendly error, ignore `..` and continue parsing
self
.span_err
(
self
.prev_span
,
"`..` can only be used once per
\
tuple or tuple struct pattern"
);
}
else
{
}
else
if
!
self
.check
(
&
token
::
CloseDelim
(
token
::
Paren
))
{
fields
.push
(
self
.parse_pat
()
?
);
}
else
{
break
}
if
!
self
.check
(
&
token
::
CloseDelim
(
token
::
Paren
))
||
(
unary_needs_comma
&&
fields
.len
()
==
1
&&
ddpos
.is_none
())
{
self
.expect
(
&
token
::
Comma
)
?
;
trailing_comma
=
self
.eat
(
&
token
::
Comma
);
if
!
trailing_comma
{
break
}
}
Ok
((
fields
,
ddpos
))
if
ddpos
==
Some
(
fields
.len
())
&&
trailing_comma
{
// `..` needs to be followed by `)` or `, pat`, `..,)` is disallowed.
self
.span_err
(
self
.prev_span
,
"trailing comma is not permitted after `..`"
);
}
self
.expect
(
&
token
::
CloseDelim
(
token
::
Paren
))
?
;
Ok
((
fields
,
ddpos
,
trailing_comma
))
}
fn
parse_pat_vec_elements
(
...
...
@@ -3714,10 +3728,12 @@ pub fn parse_pat(&mut self) -> PResult<'a, P<Pat>> {
}
token
::
OpenDelim
(
token
::
Paren
)
=>
{
// Parse (pat,pat,pat,...) as tuple pattern
self
.bump
();
let
(
fields
,
ddpos
)
=
self
.parse_pat_tuple_elements
(
true
)
?
;
self
.expect
(
&
token
::
CloseDelim
(
token
::
Paren
))
?
;
pat
=
PatKind
::
Tuple
(
fields
,
ddpos
);
let
(
fields
,
ddpos
,
trailing_comma
)
=
self
.parse_parenthesized_pat_list
()
?
;
pat
=
if
fields
.len
()
==
1
&&
ddpos
.is_none
()
&&
!
trailing_comma
{
PatKind
::
Paren
(
fields
.into_iter
()
.nth
(
0
)
.unwrap
())
}
else
{
PatKind
::
Tuple
(
fields
,
ddpos
)
};
}
token
::
OpenDelim
(
token
::
Bracket
)
=>
{
// Parse [pat,pat,...] as slice pattern
...
...
@@ -3807,9 +3823,7 @@ pub fn parse_pat(&mut self) -> PResult<'a, P<Pat>> {
return
Err
(
self
.fatal
(
"unexpected `(` after qualified path"
));
}
// Parse tuple struct or enum pattern
self
.bump
();
let
(
fields
,
ddpos
)
=
self
.parse_pat_tuple_elements
(
false
)
?
;
self
.expect
(
&
token
::
CloseDelim
(
token
::
Paren
))
?
;
let
(
fields
,
ddpos
,
_
)
=
self
.parse_parenthesized_pat_list
()
?
;
pat
=
PatKind
::
TupleStruct
(
path
,
fields
,
ddpos
)
}
_
=>
pat
=
PatKind
::
Path
(
qself
,
path
),
...
...
src/libsyntax/print/pprust.rs
浏览文件 @
c9aff92e
...
...
@@ -2659,6 +2659,11 @@ pub fn print_pat(&mut self, pat: &ast::Pat) -> io::Result<()> {
|
s
,
p
|
s
.print_pat
(
p
))
?
;
self
.s
.word
(
"]"
)
?
;
}
PatKind
::
Paren
(
ref
inner
)
=>
{
self
.popen
()
?
;
self
.print_pat
(
inner
)
?
;
self
.pclose
()
?
;
}
PatKind
::
Mac
(
ref
m
)
=>
self
.print_mac
(
m
,
token
::
Paren
)
?
,
}
self
.ann
.post
(
self
,
NodePat
(
pat
))
...
...
src/libsyntax/visit.rs
浏览文件 @
c9aff92e
...
...
@@ -425,7 +425,8 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) {
walk_list!
(
visitor
,
visit_pat
,
tuple_elements
);
}
PatKind
::
Box
(
ref
subpattern
)
|
PatKind
::
Ref
(
ref
subpattern
,
_
)
=>
{
PatKind
::
Ref
(
ref
subpattern
,
_
)
|
PatKind
::
Paren
(
ref
subpattern
)
=>
{
visitor
.visit_pat
(
subpattern
)
}
PatKind
::
Ident
(
_
,
ref
pth1
,
ref
optional_subpattern
)
=>
{
...
...
src/test/parse-fail/pat-tuple-2.rs
浏览文件 @
c9aff92e
...
...
@@ -12,6 +12,6 @@
fn
main
()
{
match
0
{
(
pat
,
..
,)
=>
{}
//~ ERROR
expected pattern, found `)
`
(
pat
,
..
,)
=>
{}
//~ ERROR
trailing comma is not permitted after `..
`
}
}
src/test/
parse-fail/pat-tuple-6
.rs
→
src/test/
run-pass/pat-tuple-7
.rs
浏览文件 @
c9aff92e
...
...
@@ -8,10 +8,10 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags: -Z parse-only
#![feature(pattern_parentheses)]
fn
main
()
{
match
0
{
(
pat
)
=>
{}
//~ ERROR expected one of `,` or `@`, found `)`
(
pat
)
=>
assert_eq!
(
pat
,
0
)
}
}
src/test/ui/feature-gate-pattern_parentheses.rs
0 → 100644
浏览文件 @
c9aff92e
// Copyright 2017 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.
fn
main
()
{
match
0
{
(
pat
)
=>
{}
//~ ERROR parentheses in patterns are unstable
}
}
src/test/ui/feature-gate-pattern_parentheses.stderr
0 → 100644
浏览文件 @
c9aff92e
error[E0658]: parentheses in patterns are unstable
--> $DIR/feature-gate-pattern_parentheses.rs:13:9
|
LL | (pat) => {} //~ ERROR parentheses in patterns are unstable
| ^^^^^
|
= help: add #![feature(pattern_parentheses)] to the crate attributes to enable
error: aborting due to previous error
If you want more information on this error, try using "rustc --explain E0658"
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录