Skip to content

Commit fbf2626

Browse files
committed
Match AST changes around .. in patterns
`TupleStructP`, `TupleP`, `SliceP`, all used to accept `..` in them. The parsing rules were awful, and the fields were confusing. Now, `..` is its own pattern (although semantically it doesn't make sense outside of the cases I just listed). Also, a `ParenP` was added. I have not fixed `Resolve` yet to take advantage of this.
1 parent 9b0547d commit fbf2626

File tree

7 files changed

+126
-167
lines changed

7 files changed

+126
-167
lines changed

src/Language/Rust/Parser/Internal.y

+12-36
Original file line numberDiff line numberDiff line change
@@ -770,7 +770,7 @@ arg_general :: { Arg Span }
770770
| '&' ident ':' ty { Arg (Just (RefP (IdentP (ByValue Immutable) (unspan $2) Nothing (spanOf $2)) Immutable ($1 # $2))) $4 ($1 # $4) }
771771
| '&&' '_' ':' ty { Arg (Just (RefP (RefP (WildP (spanOf $2)) Immutable (nudge 1 0 ($1 # $2))) Immutable ($1 # $2))) $4 ($1 # $4) }
772772
| '&&' ident ':' ty { Arg (Just (RefP (RefP (IdentP (ByValue Immutable) (unspan $2) Nothing (spanOf $2)) Immutable (nudge 1 0 ($1 # $2))) Immutable ($1 # $2))) $4 ($1 # $4) }
773-
773+
774774
-- Self argument (only allowed in trait function signatures)
775775
arg_self_general :: { Arg Span }
776776
: mut self { SelfValue Mutable ($1 # $>) }
@@ -812,6 +812,7 @@ lambda_arg :: { Arg Span }
812812
pat :: { Pat Span }
813813
: ntPat { $1 }
814814
| '_' { WildP (spanOf $1) }
815+
| '..' { RestP (spanOf $1) }
815816
| '&' mut pat { RefP $3 Mutable ($1 # $3) }
816817
| '&' pat { RefP $2 Immutable ($1 # $2) }
817818
| '&&' mut pat { RefP (RefP $3 Mutable (nudge 1 0 ($1 # $3))) Immutable ($1 # $3) }
@@ -832,51 +833,26 @@ pat :: { Pat Span }
832833
| lit_or_path '..=' lit_or_path { RangeP $1 $3 ($1 # $>) }
833834
| expr_path '{' '..' '}' { StructP $1 [] True ($1 # $>) }
834835
| expr_path '{' pat_fields '}' { let (fs,b) = $3 in StructP $1 fs b ($1 # $>) }
835-
| expr_path '(' pat_tup ')' { let (ps,m,_) = $3 in TupleStructP $1 ps m ($1 # $>) }
836+
| expr_path '(' sep_byT(pat,',') ')' { TupleStructP $1 $3 ($1 # $>) }
836837
| expr_mac { MacP $1 (spanOf $1) }
837-
| '[' pat_slice ']' { let (b,s,a) = $2 in SliceP b s a ($1 # $3) }
838-
| '(' pat_tup ')' {%
839-
case $2 of
840-
([p], Nothing, False) -> parseError (CloseDelim Paren)
841-
(ps,m,t) -> pure (TupleP ps m ($1 # $3))
838+
| '[' sep_byT(pat,',') ']' { SliceP $2 ($1 # $>) }
839+
| '(' ')' { TupleP [] ($1 # $>) }
840+
| '(' sep_by1(pat,',') ',' ')' { TupleP (toList $2) ($1 # $>) }
841+
| '(' sep_by1(pat,',') ')' {
842+
case toList $2 of
843+
l @ [RestP _] -> TupleP l ($1 # $>) -- (..) is a tuple pattern
844+
[p] -> ParenP p ($1 # $>) -- (<pat>) is parenthesis around a pattern
845+
l -> TupleP l ($1 # $>) -- (<pat1>, <pat2>) is a tuple pattern
842846
}
843847

844-
845-
-- The first element is the spans, the second the position of '..', and the third if there is a
846-
-- trailing comma
847-
pat_tup :: { ([Pat Span], Maybe Int, Bool) }
848-
: sep_by1(pat,',') ',' '..' ',' sep_by1(pat,',') { (toList ($1 <> $5), Just (length $1), False) }
849-
| sep_by1(pat,',') ',' '..' ',' sep_by1(pat,',') ',' { (toList ($1 <> $5), Just (length $1), True) }
850-
| sep_by1(pat,',') ',' '..' { (toList $1, Just (length $1), False) }
851-
| sep_by1(pat,',') { (toList $1, Nothing, False) }
852-
| sep_by1(pat,',') ',' { (toList $1, Nothing, True) }
853-
| '..' ',' sep_by1(pat,',') { (toList $3, Just 0, False) }
854-
| '..' ',' sep_by1(pat,',') ',' { (toList $3, Just 0, True) }
855-
| '..' { ([], Just 0, False) }
856-
| {- empty -} { ([], Nothing, False) }
857-
858-
-- The first element is the patterns at the beginning of the slice, the second the optional binding
859-
-- for the middle slice ('Nothing' if there is no '..' and 'Just (WildP mempty) is there is one, but
860-
-- unlabelled), and the third is the patterns at the end of the slice.
861-
pat_slice :: { ([Pat Span], Maybe (Pat Span), [Pat Span]) }
862-
: sep_by1(pat,',') ',' '..' ',' sep_by1T(pat,',') { (toList $1, Just (WildP mempty), toList $5) }
863-
| sep_by1(pat,',') ',' '..' { (toList $1, Just (WildP mempty), []) }
864-
| sep_by1(pat,',') '..' ',' sep_by1T(pat,',') { let (xs, x) = unsnoc $1 in (toList xs, Just x, toList $4) }
865-
| sep_by1(pat,',') '..' { let (xs, x) = unsnoc $1 in (toList xs, Just x, []) }
866-
| sep_by1T(pat,',') { (toList $1, Nothing, []) }
867-
| '..' ',' sep_by1T(pat,',') { ([], Just (WildP mempty), toList $3) }
868-
| '..' { ([], Just (WildP mempty), []) }
869-
| {- empty -} { ([], Nothing, []) }
870-
871-
872848
-- Endpoints of range patterns
873849
lit_or_path :: { Expr Span }
874850
: expr_path { PathExpr [] Nothing $1 (spanOf $1) }
875851
| expr_qual_path { PathExpr [] (Just (fst (unspan $1))) (snd (unspan $1)) (spanOf $1) }
876852
| '-' lit_expr { Unary [] Neg $2 ($1 # $2) }
877853
| lit_expr { $1 }
878854

879-
-- Used in patterns for tuple and expression patterns
855+
-- Used in patterns for expression patterns
880856
pat_fields :: { ([FieldPat Span], Bool) }
881857
: sep_byT(pat_field,',') { ($1, False) }
882858
| sep_by1(pat_field,',') ',' '..' { (toList $1, True) }

src/Language/Rust/Pretty/Internal.hs

+18-29
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ Portability : portable
99
1010
The pretty printing facilities in this file are re-exported to 'Language.Rust.Pretty' via the
1111
'Pretty' and 'PrettyAnnotated' classes. There may be invariants in this module that are not properly
12-
documented.
12+
documented.
1313
-}
1414
{-# OPTIONS_GHC -Wall -fno-warn-name-shadowing #-}
1515
{-# OPTIONS_HADDOCK hide, not-home #-}
@@ -23,32 +23,32 @@ module Language.Rust.Pretty.Internal (
2323

2424
-- ** Top level
2525
printSourceFile,
26-
26+
2727
-- ** General
2828
printMutability,
2929
printUnsafety,
3030
printFnArgsAndRet,
3131
printIdent,
32-
32+
3333
-- ** Paths
3434
printPath,
35-
35+
3636
-- ** Attributes
3737
printAttr,
38-
38+
3939
-- ** Literals
4040
printLit,
4141
printLitSuffix,
4242
printLitTok,
43-
43+
4444
-- ** Expressions
4545
printExpr,
4646
printAbi,
4747
printUnOp,
4848
printBinOp,
4949
printField,
5050
printRangeLimits,
51-
51+
5252
-- ** Types and lifetimes
5353
printType,
5454
printGenerics,
@@ -60,15 +60,15 @@ module Language.Rust.Pretty.Internal (
6060
printWherePredicate,
6161
printPolyTraitRef,
6262
printTraitRef,
63-
63+
6464
-- ** Patterns
6565
printPat,
6666
printBindingMode,
6767
printFieldPat,
68-
68+
6969
-- ** Statements
7070
printStmt,
71-
71+
7272
-- ** Items
7373
printItem,
7474
printForeignItem,
@@ -79,7 +79,7 @@ module Language.Rust.Pretty.Internal (
7979
printVariant,
8080
printUseTree,
8181
printVis,
82-
82+
8383
-- ** Blocks
8484
printBlock,
8585

@@ -868,34 +868,23 @@ printFullMutability Immutable = "const"
868868
-- | Print a pattern (@print_pat@)
869869
printPat :: Pat a -> Doc a
870870
printPat (WildP x) = annotate x "_"
871+
printPat (RestP x) = annotate x ".."
871872
printPat (IdentP bm p s x) = annotate x (printBindingMode bm <+> printIdent p <+> perhaps (\p' -> "@" <+> printPat p') s)
872873
printPat (StructP p fs False x) = annotate x (printPath p True <+> block Brace True "," mempty (printFieldPat `map` fs))
873874
printPat (StructP p fs True x) = annotate x (printPath p True <+> block Brace True mempty mempty ([ printFieldPat f <> "," | f <- fs ] ++ [ ".." ]))
874-
printPat (TupleStructP p es Nothing x) = annotate x (printPath p True <> "(" <> commas es printPat <> ")")
875-
printPat (TupleStructP p es (Just d) x) = let (before,after) = splitAt d es
876-
in annotate x (printPath p True <> "(" <> commas before printPat <> when (d /= 0) ","
877-
<+> ".." <> when (d /= length es) ("," <+> commas after printPat) <> ")")
875+
printPat (TupleStructP p es x) = annotate x (printPath p True <> "(" <> commas es printPat <> ")")
878876
printPat (PathP Nothing path x) = annotate x (printPath path True)
879877
printPat (PathP (Just qself) path x) = annotate x (printQPath path qself True)
880-
printPat (TupleP [elt] Nothing x) = annotate x ("(" <> printPat elt <> ",)")
881-
printPat (TupleP elts Nothing x) = annotate x ("(" <> commas elts printPat <> ")")
882-
printPat (TupleP elts (Just ddpos) _) = let (before,after) = splitAt ddpos elts
883-
in "(" <> commas before printPat <> unless (null before) ","
884-
<+> ".." <> unless (null after) ("," <+> commas after printPat) <> ")"
878+
printPat (TupleP [RestP y] x) = annotate x ("(" <> annotate y ".." <> ")")
879+
printPat (TupleP [elt] x) = annotate x ("(" <> printPat elt <> ",)")
880+
printPat (TupleP elts x) = annotate x ("(" <> commas elts printPat <> ")")
885881
printPat (BoxP inner x) = annotate x ("box" <+> printPat inner)
886882
printPat (RefP inner mutbl x) = annotate x ("&" <> printMutability mutbl <+> printPat inner)
887883
printPat (LitP expr x) = annotate x (printExpr expr)
888884
printPat (RangeP lo hi x) = annotate x (printExpr lo <+> "..=" <+> printExpr hi)
889-
printPat (SliceP pb Nothing pa x) = annotate x ("[" <> commas (pb ++ pa) printPat <> "]")
890-
printPat (SliceP pb (Just ps) pa x) = annotate x ("[" <> commas pb printPat <> ps' <+> commas pa printPat <> "]")
891-
where ps' = hcat [ unless (null pb) ","
892-
, space
893-
, case ps of WildP{} -> mempty
894-
_ -> printPat ps
895-
, ".."
896-
, unless (null pa) ","
897-
]
885+
printPat (SliceP ps x) = annotate x ("[" <> commas ps printPat <> "]")
898886
printPat (MacP m x) = annotate x (printMac Paren m)
887+
printPat (ParenP p x) = annotate x ("(" <> printPat p <> ")")
899888

900889
-- | Print a field pattern
901890
printFieldPat :: FieldPat a -> Doc a

src/Language/Rust/Pretty/Resolve.hs

+9-14
Original file line numberDiff line numberDiff line change
@@ -573,23 +573,20 @@ instance (Typeable a, Monoid a) => Resolve (LifetimeDef a) where resolveM = reso
573573
--------------
574574
-- Patterns --
575575
--------------
576+
-- TODO: consider disallowind `..` not in the allowed contexts
577+
-- TODO: use parenP
576578

577579
-- | A pattern can be invalid of
578580
--
579-
-- * the index of the '...' in the tuple/tuple-struct is out of range
580581
-- * the index of the qself path is out of range
581582
-- * any underlying component is invalid
582583
--
583584
resolvePat :: (Typeable a, Monoid a) => Pat a -> ResolveM (Pat a)
584585
-- TupleStruct
585-
resolvePat t@(TupleStructP p fs im x) = scope t $ do
586+
resolvePat t@(TupleStructP p fs x) = scope t $ do
586587
p' <- resolvePath ExprPath p
587588
fs' <- traverse resolvePat fs
588-
im' <- case im of
589-
Nothing -> pure Nothing
590-
Just i | 0 <= i && i <= length fs -> pure (Just i)
591-
_ -> err im "index of ... in tuple struct pattern is outside of field range"
592-
pure (TupleStructP p' fs' im' x)
589+
pure (TupleStructP p' fs' x)
593590
-- PathP
594591
resolvePat p@(PathP Nothing a x) = scope p (PathP Nothing <$> resolvePath ExprPath a <*> pure x)
595592
resolvePat p@(PathP q@(Just (QSelf _ i)) p'@(Path g s x) x')
@@ -601,13 +598,9 @@ resolvePat p@(PathP q@(Just (QSelf _ i)) p'@(Path g s x) x')
601598
q' <- traverse resolveQSelf q
602599
pure (PathP q' (Path g (tyPSegs <> exprPSegs) x) x')
603600
-- TupleP
604-
resolvePat p@(TupleP ps i x) = scope p $ do
601+
resolvePat p@(TupleP ps x) = scope p $ do
605602
ps' <- traverse resolvePat ps
606-
i' <- case i of
607-
Nothing -> pure Nothing
608-
Just j | 0 <= j && j <= length ps -> pure i
609-
| otherwise -> err i "index of ... in tuple pattern is outside of range"
610-
pure (TupleP ps' i' x)
603+
pure (TupleP ps' x)
611604

612605
-- Everything else...
613606
resolvePat p@(LitP e x) = scope p (LitP <$> resolveExpr LitExpr e <*> pure x)
@@ -617,7 +610,9 @@ resolvePat p@(IdentP m i p' x) = scope p (IdentP m <$> resolveIdent i <*> traver
617610
resolvePat p@(StructP p' fs b x) = scope p (StructP <$> resolvePath ExprPath p' <*> traverse resolveFieldPat fs <*> pure b <*> pure x)
618611
resolvePat p@(BoxP p' x) = scope p (BoxP <$> resolvePat p' <*> pure x)
619612
resolvePat p@(RefP p' m x) = scope p (RefP <$> resolvePat p' <*> pure m <*> pure x)
620-
resolvePat p@(SliceP b m a x) = scope p (SliceP <$> traverse resolvePat b <*> traverse resolvePat m <*> traverse resolvePat a <*> pure x)
613+
resolvePat p@(SliceP ps x) = scope p (SliceP <$> traverse resolvePat ps <*> pure x)
614+
resolvePat p@(RestP x) = scope p (pure (RestP x))
615+
resolvePat p@(ParenP p' x) = scope p (ParenP <$> resolvePat p' <*> pure x)
621616
resolvePat p@(MacP m x) = scope p (MacP <$> resolveMac ExprPath m <*> pure x)
622617

623618
instance (Typeable a, Monoid a) => Resolve (Pat a) where resolveM = resolvePat

src/Language/Rust/Syntax/AST.hs

+17-15
Original file line numberDiff line numberDiff line change
@@ -777,14 +777,12 @@ data Pat a
777777
| IdentP BindingMode Ident (Maybe (Pat a)) a
778778
-- | struct pattern. The 'Bool' signals the presence of a @..@. (example: @Variant { x, y, .. }@)
779779
| StructP (Path a) [FieldPat a] Bool a
780-
-- | tuple struct pattern. If the @..@ pattern is present, the 'Maybe Int' denotes its position.
781-
-- (example: @Variant(x, y, .., z)@)
782-
| TupleStructP (Path a) [Pat a] (Maybe Int) a
780+
-- | tuple struct pattern (example: @Variant(x, y, z)@)
781+
| TupleStructP (Path a) [Pat a] a
783782
-- | path pattern (example @A::B::C@)
784783
| PathP (Maybe (QSelf a)) (Path a) a
785-
-- | tuple pattern. If the @..@ pattern is present, the 'Maybe Int' denotes its position.
786-
-- (example: @(a, b)@)
787-
| TupleP [Pat a] (Maybe Int) a
784+
-- | tuple pattern (example: @(a, b)@)
785+
| TupleP [Pat a] a
788786
-- | box pattern (example: @box _@)
789787
| BoxP (Pat a) a
790788
-- | reference pattern (example: @&mut (a, b)@)
@@ -793,9 +791,13 @@ data Pat a
793791
| LitP (Expr a) a
794792
-- | range pattern (example: @1...2@)
795793
| RangeP (Expr a) (Expr a) a
796-
-- | slice pattern where, as per [this RFC](https://github.com/P1start/rfcs/blob/array-pattern-changes/text/0000-array-pattern-changes.md),
797-
-- the pattern is split into the patterns before/after the @..@ and the pattern at the @..@. (example: @[a, b, ..i, y, z]@)
798-
| SliceP [Pat a] (Maybe (Pat a)) [Pat a] a
794+
-- | slice pattern (example: @[a, b, .., y, z]@)
795+
| SliceP [Pat a] a
796+
-- | A rest pattern @..@. Syntactically it is valid anywhere, but semantically it only has meaning
797+
-- immediately inside a 'SliceP', a 'TupleP', or a 'TupleStructP' (example @[a, .., b]@)
798+
| RestP a
799+
-- | A paren
800+
| ParenP (Pat a) a
799801
-- | generated from a call to a macro (example: @LinkedList!(1,2,3)@)
800802
| MacP (Mac a) a
801803
deriving (Eq, Ord, Functor, Show, Typeable, Data, Generic, Generic1, NFData)
@@ -804,14 +806,16 @@ instance Located a => Located (Pat a) where
804806
spanOf (WildP s) = spanOf s
805807
spanOf (IdentP _ _ _ s) = spanOf s
806808
spanOf (StructP _ _ _ s) = spanOf s
807-
spanOf (TupleStructP _ _ _ s) = spanOf s
809+
spanOf (TupleStructP _ _ s) = spanOf s
808810
spanOf (PathP _ _ s) = spanOf s
809-
spanOf (TupleP _ _ s) = spanOf s
811+
spanOf (TupleP _ s) = spanOf s
810812
spanOf (BoxP _ s) = spanOf s
811813
spanOf (RefP _ _ s) = spanOf s
812814
spanOf (LitP _ s) = spanOf s
813815
spanOf (RangeP _ _ s) = spanOf s
814-
spanOf (SliceP _ _ _ s) = spanOf s
816+
spanOf (SliceP _ s) = spanOf s
817+
spanOf (RestP s) = spanOf s
818+
spanOf (ParenP _ s) = spanOf s
815819
spanOf (MacP _ s) = spanOf s
816820

817821
-- | Everything in Rust is namespaced using nested modules. A 'Path' represents a path into nested
@@ -1021,9 +1025,7 @@ data Ty a
10211025
| PathTy (Maybe (QSelf a)) (Path a) a
10221026
-- | trait object type (example: @Bound1 + Bound2 + Bound3@)
10231027
| TraitObject (NonEmpty (TyParamBound a)) a
1024-
-- | impl trait type (see the
1025-
-- [RFC](https://github.com/rust-lang/rfcs/blob/master/text/1522-conservative-impl-trait.md))
1026-
-- (example: @impl Bound1 + Bound2 + Bound3@).
1028+
-- | impl trait type (example: @impl Bound1 + Bound2 + Bound3@).
10271029
| ImplTrait (NonEmpty (TyParamBound a)) a
10281030
-- | no-op; kept solely so that we can pretty print faithfully
10291031
| ParenTy (Ty a) a

test/rustc-tests/Diff.hs

+6-8
Original file line numberDiff line numberDiff line change
@@ -466,9 +466,11 @@ instance Show a => Diffable (Pat a) where
466466
let val' = val ! "node"
467467
case (val', p') of
468468
("Wild", WildP _) -> pure ()
469+
("Rest", RestP _) -> pure ()
469470
(Data.Aeson.Object{}, _) ->
470471
case (val' ! "variant", p') of
471472
("Box", BoxP p _) -> p === (val' ! "fields" ! 0)
473+
("Paren", ParenP p _) -> p === (val' ! "fields" ! 0)
472474
("Lit", LitP e _) -> e === (val' ! "fields" ! 0)
473475
("Mac", MacP m _) -> m === (val' ! "fields" ! 0)
474476
("Ident", IdentP bm i m _) -> do
@@ -482,20 +484,16 @@ instance Show a => Diffable (Pat a) where
482484
p === (val' ! "fields" ! 0)
483485
fp === (val' ! "fields" ! 1)
484486
d === (val' ! "fields" ! 2)
485-
("TupleStruct", TupleStructP p fp mi _) -> do
487+
("TupleStruct", TupleStructP p fp _) -> do
486488
p === (val' ! "fields" ! 0)
487489
fp === (val' ! "fields" ! 1)
488-
mi === (val' ! "fields" ! 2)
489-
("Tuple", TupleP fp mi _) -> do
490+
("Tuple", TupleP fp _) -> do
490491
fp === (val' ! "fields" ! 0)
491-
mi === (val' ! "fields" ! 1)
492492
("Range", RangeP e1 e2 _) -> do
493493
e1 === (val' ! "fields" ! 0)
494494
e2 === (val' ! "fields" ! 1)
495-
("Slice", SliceP b m a _) -> do
496-
b === (val' ! "fields" ! 0)
497-
m === (val' ! "fields" ! 1)
498-
a === (val' ! "fields" ! 2)
495+
("Slice", SliceP a _) -> do
496+
a === (val' ! "fields" ! 0)
499497
("Path", PathP q p _) -> do
500498
q === (val' ! "fields" ! 0)
501499
p === (val' ! "fields" ! 1)

0 commit comments

Comments
 (0)