Skip to content

Commit 6f84a9c

Browse files
committed
GRAM: Support the new '..=' syntax for inclusive ranges
Inclusive ranges are currently a unstable feature of Rust. '..=' for ranges requires #![feature(inclusive_range_syntax)] '..=' for range patterns requires #![feature(dotdoteq_in_patterns)] The nightly version of Rust does not accept the previous syntax '...' for inclusive ranges anymore. (For range patterns the old syntax is still supported) It produces the following output: error: `...` syntax cannot be used in expressions help: Use `..` if you need an exclusive range (a < b) help: or `..=` if you need an inclusive range (a <= b) We still support the old '...' syntax for both ranges and range patterns. See the tracking issue rust-lang/rust/issues/28237 for '..=' inclusive ranges. (RFC 1192) Fixes intellij-rust#2335
1 parent 07a8475 commit 6f84a9c

File tree

10 files changed

+124
-9
lines changed

10 files changed

+124
-9
lines changed

src/main/grammars/RustLexer.flex

+1
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ OUTER_EOL_DOC = ({EOL_DOC_LINE}{EOL_WS})*{EOL_DOC_LINE}
153153
"." { return DOT; }
154154
".." { return DOTDOT; }
155155
"..." { return DOTDOTDOT; }
156+
"..=" { return DOTDOTEQ; }
156157
"=" { return EQ; }
157158
"!=" { return EXCLEQ; }
158159
"==" { return EQEQ; }

src/main/grammars/RustParser.bnf

+7-6
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
DOT = '.'
5959
DOTDOT = '..'
6060
DOTDOTDOT = '...'
61+
DOTDOTEQ = '..='
6162
FAT_ARROW = '=>'
6263
ARROW = '->'
6364
Q = '?'
@@ -401,7 +402,7 @@ Pat ::= PatWild
401402
| PatStruct
402403
| PatEnum
403404
| PatIdent
404-
| (PatConst !('..' | '...'))
405+
| (PatConst !('..' | '...' | '..='))
405406
| PatRange
406407
| PatUniq
407408

@@ -427,7 +428,7 @@ private Pat_with_recover ::= Pat (',' | &(')' | ']' | '..'))
427428
private PatField_with_recover ::= PatField (',' | & '}')
428429

429430
PatConst ::= PathExpr | LitExpr | &('-' LitExpr) UnaryExpr
430-
PatRange ::= PatConst ('..' | '...') PatConst { pin = 2 }
431+
PatRange ::= PatConst ('..' | '...' | '..=') PatConst { pin = 2 }
431432

432433
PatTup ::= '(' SeqPat ')'
433434
PatVec ::= '[' SeqPat ']'
@@ -847,7 +848,7 @@ Expr ::= RetExpr
847848
stubClass = "org.rust.lang.core.stubs.RsPlaceholderStub"
848849
}
849850

850-
private Expr_first ::= return | '|' | Path_first | '{' | '[' | '(' | '..' | '...' | true | false | box | QUOTE_IDENTIFIER
851+
private Expr_first ::= return | '|' | Path_first | '{' | '[' | '(' | '..' | '...' | '..=' | true | false | box | QUOTE_IDENTIFIER
851852
| '-' | '*' | '!' | '&' | move | LitExpr | while | if | for | continue | break | loop | match | unsafe
852853

853854
// https://github.com/rust-lang/rfcs/blob/master/text/0092-struct-grammar.md
@@ -1044,12 +1045,12 @@ ArrayExpr ::= OuterAttr* '[' ArrayInitializer ']' {
10441045
}
10451046
private ArrayInitializer ::= [ AnyExpr ( ';' AnyExpr | (',' AnyExpr)* ','? ) ]
10461047

1047-
fake RangeExpr ::= Expr? ('..' | '...') Expr? {
1048+
fake RangeExpr ::= Expr? ('..' | '...' | '..=') Expr? {
10481049
elementTypeFactory = "org.rust.lang.core.stubs.StubImplementationsKt.factory"
10491050
}
10501051

1051-
FullRangeExpr ::= Expr ( '..' (<<checkBraceAllowed>> Expr)? | '...' (<<checkBraceAllowed>> Expr) ) { elementType = RangeExpr }
1052-
OpenRangeExpr ::= ( '..' (<<checkBraceAllowed>> Expr)? | '...' (<<checkBraceAllowed>> Expr) ) { elementType = RangeExpr }
1052+
FullRangeExpr ::= Expr ( '..' (<<checkBraceAllowed>> Expr)? | '...' (<<checkBraceAllowed>> Expr) | '..=' (<<checkBraceAllowed>> Expr) ) { elementType = RangeExpr }
1053+
OpenRangeExpr ::= ( '..' (<<checkBraceAllowed>> Expr)? | '...' (<<checkBraceAllowed>> Expr) | '..=' (<<checkBraceAllowed>> Expr) ) { elementType = RangeExpr }
10531054

10541055
IndexExpr ::= Expr IndexArg {
10551056
elementTypeFactory = "org.rust.lang.core.stubs.StubImplementationsKt.factory"

src/main/kotlin/org/rust/ide/formatter/impl/utils.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import com.intellij.psi.tree.TokenSet.create as ts
2323

2424
val SPECIAL_MACRO_ARGS = ts(FORMAT_MACRO_ARGUMENT, LOG_MACRO_ARGUMENT, TRY_MACRO_ARGUMENT, VEC_MACRO_ARGUMENT, ASSERT_MACRO_ARGUMENT)
2525

26-
val NO_SPACE_AROUND_OPS = ts(COLONCOLON, DOT, DOTDOT, DOTDOTDOT)
26+
val NO_SPACE_AROUND_OPS = ts(COLONCOLON, DOT, DOTDOT, DOTDOTDOT, DOTDOTEQ)
2727
val SPACE_AROUND_OPS = TokenSet.andNot(RS_OPERATORS, NO_SPACE_AROUND_OPS)
2828
val UNARY_OPS = ts(MINUS, MUL, EXCL, AND, ANDAND)
2929

src/main/kotlin/org/rust/lang/core/psi/RsTokenType.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ val RS_KEYWORDS = tokenSetOf(
4040
)
4141

4242
val RS_OPERATORS = tokenSetOf(
43-
AND, ANDEQ, ARROW, FAT_ARROW, SHA, COLON, COLONCOLON, COMMA, DIV, DIVEQ, DOT, DOTDOT, DOTDOTDOT, EQ, EQEQ, EXCL,
43+
AND, ANDEQ, ARROW, FAT_ARROW, SHA, COLON, COLONCOLON, COMMA, DIV, DIVEQ, DOT, DOTDOT, DOTDOTDOT, DOTDOTEQ, EQ, EQEQ, EXCL,
4444
EXCLEQ, GT, LT, MINUS, MINUSEQ, MUL, MULEQ, OR, OREQ, PLUS, PLUSEQ, REM, REMEQ, SEMICOLON, XOR, XOREQ, Q, AT,
4545
DOLLAR, GTGTEQ, GTGT, GTEQ, LTLTEQ, LTLT, LTEQ, OROR, ANDAND
4646
)

src/main/kotlin/org/rust/lang/core/types/infer/TypeInference.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -1248,7 +1248,7 @@ private class RsFnInferenceContext(
12481248
private fun inferRangeType(expr: RsRangeExpr): Ty {
12491249
val el = expr.exprList
12501250
val dot2 = expr.dotdot
1251-
val dot3 = expr.dotdotdot
1251+
val dot3 = expr.dotdotdot ?: expr.dotdoteq
12521252

12531253
val (rangeName, indexType) = when {
12541254
dot2 != null && el.size == 0 -> "RangeFull" to null

src/test/kotlin/org/rust/ide/formatter/RsFormatterTest.kt

+30
Original file line numberDiff line numberDiff line change
@@ -309,11 +309,41 @@ class RsFormatterTest : RsFormatterTestBase() {
309309
fn main() {
310310
if let - 10 .. - 1 = - 8 {}
311311
if let - 10 ... - 1 = - 8 {}
312+
if let - 10 ..= - 1 = - 8 {}
312313
}
313314
""", """
314315
fn main() {
315316
if let -10..-1 = -8 {}
316317
if let -10...-1 = -8 {}
318+
if let -10..=-1 = -8 {}
319+
}
320+
""")
321+
322+
fun `test ranges`() = doTextTest("""
323+
fn main() {
324+
let r = .. ;
325+
let r = .. 1;
326+
let r = 0 .. ;
327+
let r = 0 .. 1;
328+
329+
let r = ... 1;
330+
let r = 0 ... 1;
331+
332+
let r = ..= 1;
333+
let r = 0 ..= 1;
334+
}
335+
""", """
336+
fn main() {
337+
let r = ..;
338+
let r = ..1;
339+
let r = 0..;
340+
let r = 0..1;
341+
342+
let r = ...1;
343+
let r = 0...1;
344+
345+
let r = ..=1;
346+
let r = 0..=1;
317347
}
318348
""")
319349

src/test/kotlin/org/rust/lang/core/type/RsNumericLiteralTypeInferenceTest.kt

+10
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,16 @@ class RsNumericLiteralTypeInferenceTest : RsTypificationTestBase() {
424424
}
425425
""")
426426

427+
fun `test unify match pattern inclusive range new syntax`() = testExpr("""
428+
fn main() {
429+
match 0u8 {
430+
0..=1 => {},
431+
//^ u8
432+
_ => {},
433+
};
434+
}
435+
""")
436+
427437
fun `test unify match pattern exclusive range`() = testExpr("""
428438
fn main() {
429439
match 0u8 {

src/test/kotlin/org/rust/lang/core/type/RsStdlibExpressionTypeInferenceTest.kt

+18
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,15 @@ class RsStdlibExpressionTypeInferenceTest : RsTypificationTestBase() {
7474
}
7575
""")
7676

77+
fun `test RangeToInclusive new syntax`() = stubOnlyTypeInfer("""
78+
//- main.rs
79+
fn main() {
80+
let x = ..=42u16;
81+
x
82+
//^ RangeToInclusive<u16>
83+
}
84+
""")
85+
7786
fun `test RangeInclusive 1`() = stubOnlyTypeInfer("""
7887
//- main.rs
7988
fn main() {
@@ -92,6 +101,15 @@ class RsStdlibExpressionTypeInferenceTest : RsTypificationTestBase() {
92101
}
93102
""")
94103

104+
fun `test RangeInclusive new syntax`() = stubOnlyTypeInfer("""
105+
//- main.rs
106+
fn main() {
107+
let x = 0..=42u16;
108+
x
109+
//^ RangeInclusive<u16>
110+
}
111+
""")
112+
95113
fun `test vec!`() = stubOnlyTypeInfer("""
96114
//- main.rs
97115
fn main() {

src/test/resources/org/rust/lang/core/parser/fixtures/complete/ranges.rs

+3
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ fn main() {
77
r = 1...10;
88
r = 1 ... 10;
99
r = ... 10;
10+
r = 1..=10;
11+
r = 1 ..= 10;
12+
r = ..= 10;
1013

1114
for i in 0.. {
1215
2

src/test/resources/org/rust/lang/core/parser/fixtures/complete/ranges.txt

+52
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,58 @@ FILE
148148
RsLitExprImpl(LIT_EXPR)
149149
PsiElement(INTEGER_LITERAL)('10')
150150
PsiElement(;)(';')
151+
PsiWhiteSpace('\n ')
152+
RsExprStmtImpl(EXPR_STMT)
153+
RsBinaryExprImpl(BINARY_EXPR)
154+
RsPathExprImpl(PATH_EXPR)
155+
RsPathImpl(PATH)
156+
PsiElement(identifier)('r')
157+
PsiWhiteSpace(' ')
158+
RsBinaryOpImpl(BINARY_OP)
159+
PsiElement(=)('=')
160+
PsiWhiteSpace(' ')
161+
RsRangeExprImpl(RANGE_EXPR)
162+
RsLitExprImpl(LIT_EXPR)
163+
PsiElement(INTEGER_LITERAL)('1')
164+
PsiElement(..=)('..=')
165+
RsLitExprImpl(LIT_EXPR)
166+
PsiElement(INTEGER_LITERAL)('10')
167+
PsiElement(;)(';')
168+
PsiWhiteSpace('\n ')
169+
RsExprStmtImpl(EXPR_STMT)
170+
RsBinaryExprImpl(BINARY_EXPR)
171+
RsPathExprImpl(PATH_EXPR)
172+
RsPathImpl(PATH)
173+
PsiElement(identifier)('r')
174+
PsiWhiteSpace(' ')
175+
RsBinaryOpImpl(BINARY_OP)
176+
PsiElement(=)('=')
177+
PsiWhiteSpace(' ')
178+
RsRangeExprImpl(RANGE_EXPR)
179+
RsLitExprImpl(LIT_EXPR)
180+
PsiElement(INTEGER_LITERAL)('1')
181+
PsiWhiteSpace(' ')
182+
PsiElement(..=)('..=')
183+
PsiWhiteSpace(' ')
184+
RsLitExprImpl(LIT_EXPR)
185+
PsiElement(INTEGER_LITERAL)('10')
186+
PsiElement(;)(';')
187+
PsiWhiteSpace('\n ')
188+
RsExprStmtImpl(EXPR_STMT)
189+
RsBinaryExprImpl(BINARY_EXPR)
190+
RsPathExprImpl(PATH_EXPR)
191+
RsPathImpl(PATH)
192+
PsiElement(identifier)('r')
193+
PsiWhiteSpace(' ')
194+
RsBinaryOpImpl(BINARY_OP)
195+
PsiElement(=)('=')
196+
PsiWhiteSpace(' ')
197+
RsRangeExprImpl(RANGE_EXPR)
198+
PsiElement(..=)('..=')
199+
PsiWhiteSpace(' ')
200+
RsLitExprImpl(LIT_EXPR)
201+
PsiElement(INTEGER_LITERAL)('10')
202+
PsiElement(;)(';')
151203
PsiWhiteSpace('\n\n ')
152204
RsForExprImpl(FOR_EXPR)
153205
PsiElement(for)('for')

0 commit comments

Comments
 (0)