Skip to content

Commit

Permalink
GRAM: Support the new '..=' syntax for inclusive ranges
Browse files Browse the repository at this point in the history
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
  • Loading branch information
kumbayo committed Mar 11, 2018
1 parent 07a8475 commit 6f84a9c
Show file tree
Hide file tree
Showing 10 changed files with 124 additions and 9 deletions.
1 change: 1 addition & 0 deletions src/main/grammars/RustLexer.flex
Expand Up @@ -153,6 +153,7 @@ OUTER_EOL_DOC = ({EOL_DOC_LINE}{EOL_WS})*{EOL_DOC_LINE}
"." { return DOT; }
".." { return DOTDOT; }
"..." { return DOTDOTDOT; }
"..=" { return DOTDOTEQ; }
"=" { return EQ; }
"!=" { return EXCLEQ; }
"==" { return EQEQ; }
Expand Down
13 changes: 7 additions & 6 deletions src/main/grammars/RustParser.bnf
Expand Up @@ -58,6 +58,7 @@
DOT = '.'
DOTDOT = '..'
DOTDOTDOT = '...'
DOTDOTEQ = '..='
FAT_ARROW = '=>'
ARROW = '->'
Q = '?'
Expand Down Expand Up @@ -401,7 +402,7 @@ Pat ::= PatWild
| PatStruct
| PatEnum
| PatIdent
| (PatConst !('..' | '...'))
| (PatConst !('..' | '...' | '..='))
| PatRange
| PatUniq

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

PatConst ::= PathExpr | LitExpr | &('-' LitExpr) UnaryExpr
PatRange ::= PatConst ('..' | '...') PatConst { pin = 2 }
PatRange ::= PatConst ('..' | '...' | '..=') PatConst { pin = 2 }

PatTup ::= '(' SeqPat ')'
PatVec ::= '[' SeqPat ']'
Expand Down Expand Up @@ -847,7 +848,7 @@ Expr ::= RetExpr
stubClass = "org.rust.lang.core.stubs.RsPlaceholderStub"
}

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

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

fake RangeExpr ::= Expr? ('..' | '...') Expr? {
fake RangeExpr ::= Expr? ('..' | '...' | '..=') Expr? {
elementTypeFactory = "org.rust.lang.core.stubs.StubImplementationsKt.factory"
}

FullRangeExpr ::= Expr ( '..' (<<checkBraceAllowed>> Expr)? | '...' (<<checkBraceAllowed>> Expr) ) { elementType = RangeExpr }
OpenRangeExpr ::= ( '..' (<<checkBraceAllowed>> Expr)? | '...' (<<checkBraceAllowed>> Expr) ) { elementType = RangeExpr }
FullRangeExpr ::= Expr ( '..' (<<checkBraceAllowed>> Expr)? | '...' (<<checkBraceAllowed>> Expr) | '..=' (<<checkBraceAllowed>> Expr) ) { elementType = RangeExpr }
OpenRangeExpr ::= ( '..' (<<checkBraceAllowed>> Expr)? | '...' (<<checkBraceAllowed>> Expr) | '..=' (<<checkBraceAllowed>> Expr) ) { elementType = RangeExpr }

IndexExpr ::= Expr IndexArg {
elementTypeFactory = "org.rust.lang.core.stubs.StubImplementationsKt.factory"
Expand Down
2 changes: 1 addition & 1 deletion src/main/kotlin/org/rust/ide/formatter/impl/utils.kt
Expand Up @@ -23,7 +23,7 @@ import com.intellij.psi.tree.TokenSet.create as ts

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

val NO_SPACE_AROUND_OPS = ts(COLONCOLON, DOT, DOTDOT, DOTDOTDOT)
val NO_SPACE_AROUND_OPS = ts(COLONCOLON, DOT, DOTDOT, DOTDOTDOT, DOTDOTEQ)
val SPACE_AROUND_OPS = TokenSet.andNot(RS_OPERATORS, NO_SPACE_AROUND_OPS)
val UNARY_OPS = ts(MINUS, MUL, EXCL, AND, ANDAND)

Expand Down
2 changes: 1 addition & 1 deletion src/main/kotlin/org/rust/lang/core/psi/RsTokenType.kt
Expand Up @@ -40,7 +40,7 @@ val RS_KEYWORDS = tokenSetOf(
)

val RS_OPERATORS = tokenSetOf(
AND, ANDEQ, ARROW, FAT_ARROW, SHA, COLON, COLONCOLON, COMMA, DIV, DIVEQ, DOT, DOTDOT, DOTDOTDOT, EQ, EQEQ, EXCL,
AND, ANDEQ, ARROW, FAT_ARROW, SHA, COLON, COLONCOLON, COMMA, DIV, DIVEQ, DOT, DOTDOT, DOTDOTDOT, DOTDOTEQ, EQ, EQEQ, EXCL,
EXCLEQ, GT, LT, MINUS, MINUSEQ, MUL, MULEQ, OR, OREQ, PLUS, PLUSEQ, REM, REMEQ, SEMICOLON, XOR, XOREQ, Q, AT,
DOLLAR, GTGTEQ, GTGT, GTEQ, LTLTEQ, LTLT, LTEQ, OROR, ANDAND
)
Expand Down
Expand Up @@ -1248,7 +1248,7 @@ private class RsFnInferenceContext(
private fun inferRangeType(expr: RsRangeExpr): Ty {
val el = expr.exprList
val dot2 = expr.dotdot
val dot3 = expr.dotdotdot
val dot3 = expr.dotdotdot ?: expr.dotdoteq

val (rangeName, indexType) = when {
dot2 != null && el.size == 0 -> "RangeFull" to null
Expand Down
30 changes: 30 additions & 0 deletions src/test/kotlin/org/rust/ide/formatter/RsFormatterTest.kt
Expand Up @@ -309,11 +309,41 @@ class RsFormatterTest : RsFormatterTestBase() {
fn main() {
if let - 10 .. - 1 = - 8 {}
if let - 10 ... - 1 = - 8 {}
if let - 10 ..= - 1 = - 8 {}
}
""", """
fn main() {
if let -10..-1 = -8 {}
if let -10...-1 = -8 {}
if let -10..=-1 = -8 {}
}
""")

fun `test ranges`() = doTextTest("""
fn main() {
let r = .. ;
let r = .. 1;
let r = 0 .. ;
let r = 0 .. 1;
let r = ... 1;
let r = 0 ... 1;
let r = ..= 1;
let r = 0 ..= 1;
}
""", """
fn main() {
let r = ..;
let r = ..1;
let r = 0..;
let r = 0..1;
let r = ...1;
let r = 0...1;
let r = ..=1;
let r = 0..=1;
}
""")

Expand Down
Expand Up @@ -424,6 +424,16 @@ class RsNumericLiteralTypeInferenceTest : RsTypificationTestBase() {
}
""")

fun `test unify match pattern inclusive range new syntax`() = testExpr("""
fn main() {
match 0u8 {
0..=1 => {},
//^ u8
_ => {},
};
}
""")

fun `test unify match pattern exclusive range`() = testExpr("""
fn main() {
match 0u8 {
Expand Down
Expand Up @@ -74,6 +74,15 @@ class RsStdlibExpressionTypeInferenceTest : RsTypificationTestBase() {
}
""")

fun `test RangeToInclusive new syntax`() = stubOnlyTypeInfer("""
//- main.rs
fn main() {
let x = ..=42u16;
x
//^ RangeToInclusive<u16>
}
""")

fun `test RangeInclusive 1`() = stubOnlyTypeInfer("""
//- main.rs
fn main() {
Expand All @@ -92,6 +101,15 @@ class RsStdlibExpressionTypeInferenceTest : RsTypificationTestBase() {
}
""")

fun `test RangeInclusive new syntax`() = stubOnlyTypeInfer("""
//- main.rs
fn main() {
let x = 0..=42u16;
x
//^ RangeInclusive<u16>
}
""")

fun `test vec!`() = stubOnlyTypeInfer("""
//- main.rs
fn main() {
Expand Down
Expand Up @@ -7,6 +7,9 @@ fn main() {
r = 1...10;
r = 1 ... 10;
r = ... 10;
r = 1..=10;
r = 1 ..= 10;
r = ..= 10;

for i in 0.. {
2
Expand Down
Expand Up @@ -148,6 +148,58 @@ FILE
RsLitExprImpl(LIT_EXPR)
PsiElement(INTEGER_LITERAL)('10')
PsiElement(;)(';')
PsiWhiteSpace('\n ')
RsExprStmtImpl(EXPR_STMT)
RsBinaryExprImpl(BINARY_EXPR)
RsPathExprImpl(PATH_EXPR)
RsPathImpl(PATH)
PsiElement(identifier)('r')
PsiWhiteSpace(' ')
RsBinaryOpImpl(BINARY_OP)
PsiElement(=)('=')
PsiWhiteSpace(' ')
RsRangeExprImpl(RANGE_EXPR)
RsLitExprImpl(LIT_EXPR)
PsiElement(INTEGER_LITERAL)('1')
PsiElement(..=)('..=')
RsLitExprImpl(LIT_EXPR)
PsiElement(INTEGER_LITERAL)('10')
PsiElement(;)(';')
PsiWhiteSpace('\n ')
RsExprStmtImpl(EXPR_STMT)
RsBinaryExprImpl(BINARY_EXPR)
RsPathExprImpl(PATH_EXPR)
RsPathImpl(PATH)
PsiElement(identifier)('r')
PsiWhiteSpace(' ')
RsBinaryOpImpl(BINARY_OP)
PsiElement(=)('=')
PsiWhiteSpace(' ')
RsRangeExprImpl(RANGE_EXPR)
RsLitExprImpl(LIT_EXPR)
PsiElement(INTEGER_LITERAL)('1')
PsiWhiteSpace(' ')
PsiElement(..=)('..=')
PsiWhiteSpace(' ')
RsLitExprImpl(LIT_EXPR)
PsiElement(INTEGER_LITERAL)('10')
PsiElement(;)(';')
PsiWhiteSpace('\n ')
RsExprStmtImpl(EXPR_STMT)
RsBinaryExprImpl(BINARY_EXPR)
RsPathExprImpl(PATH_EXPR)
RsPathImpl(PATH)
PsiElement(identifier)('r')
PsiWhiteSpace(' ')
RsBinaryOpImpl(BINARY_OP)
PsiElement(=)('=')
PsiWhiteSpace(' ')
RsRangeExprImpl(RANGE_EXPR)
PsiElement(..=)('..=')
PsiWhiteSpace(' ')
RsLitExprImpl(LIT_EXPR)
PsiElement(INTEGER_LITERAL)('10')
PsiElement(;)(';')
PsiWhiteSpace('\n\n ')
RsForExprImpl(FOR_EXPR)
PsiElement(for)('for')
Expand Down

0 comments on commit 6f84a9c

Please sign in to comment.