Skip to content

Commit

Permalink
GRAM&ANN: Annotate if let guard syntax as experimental
Browse files Browse the repository at this point in the history
  • Loading branch information
mchernyavsky committed Sep 12, 2021
1 parent 0f40620 commit 99feb54
Show file tree
Hide file tree
Showing 6 changed files with 47 additions and 7 deletions.
2 changes: 1 addition & 1 deletion src/main/grammars/RustParser.bnf
Expand Up @@ -1246,7 +1246,7 @@ MatchArm ::= OuterAttr* TopPat MatchArmGuard? '=>' StmtModeExpr (',' | (&'}' | <
pin = 2
implements = [ "org.rust.lang.core.psi.ext.RsOuterAttributeOwner" ]
}
MatchArmGuard ::= if AnyExpr
MatchArmGuard ::= if (AnyExpr | IfLetCondition)

private MatchArm_with_recover ::= !'}' MatchArm {
pin = 1
Expand Down
7 changes: 7 additions & 0 deletions src/main/kotlin/org/rust/ide/annotator/RsErrorAnnotator.kt
Expand Up @@ -68,6 +68,7 @@ class RsErrorAnnotator : AnnotatorBase(), HighlightRangeExtension {
override fun visitImplItem(o: RsImplItem) = checkImpl(rsHolder, o)
override fun visitLabel(o: RsLabel) = checkLabel(rsHolder, o)
override fun visitLifetime(o: RsLifetime) = checkLifetime(rsHolder, o)
override fun visitMatchArmGuard(o: RsMatchArmGuard) = checkMatchArmGuard(rsHolder, o)
override fun visitModDeclItem(o: RsModDeclItem) = checkModDecl(rsHolder, o)
override fun visitModItem(o: RsModItem) = checkDuplicates(rsHolder, o)
override fun visitUseSpeck(o: RsUseSpeck) = checkUseSpeck(rsHolder, o)
Expand Down Expand Up @@ -690,6 +691,12 @@ class RsErrorAnnotator : AnnotatorBase(), HighlightRangeExtension {
}
}

private fun checkMatchArmGuard(holder: RsAnnotationHolder, guard: RsMatchArmGuard) {
if (guard.let != null) {
IF_LET_GUARD.check(holder, guard, "if let guard")
}
}

private fun checkModDecl(holder: RsAnnotationHolder, modDecl: RsModDeclItem) {
checkDuplicates(holder, modDecl)
val pathAttribute = modDecl.pathAttribute
Expand Down
Expand Up @@ -12,29 +12,32 @@ import org.rust.lang.core.psi.RsExpr
import org.rust.lang.core.psi.RsIfExpr
import org.rust.lang.core.psi.RsMatchArmGuard
import org.rust.lang.core.psi.RsPsiFactory
import org.rust.lang.core.psi.ext.parentMatchArm
import org.rust.lang.core.psi.ext.ancestorStrict
import org.rust.lang.core.psi.ext.parentMatchArm

class MoveGuardToMatchArmIntention : RsElementBaseIntentionAction<MoveGuardToMatchArmIntention.Context>() {
override fun getText(): String = "Move guard inside the match arm"
override fun getFamilyName(): String = text

data class Context(
val guard: RsMatchArmGuard,
val guardExpr: RsExpr,
val armBody: RsExpr
)

override fun findApplicableContext(project: Project, editor: Editor, element: PsiElement): Context? {
val guard = element.ancestorStrict<RsMatchArmGuard>() ?: return null
if (guard.let != null) return null // TODO: support `if let guard`
val guardExpr = guard.expr ?: return null
val armBody = guard.parentMatchArm.expr ?: return null
return Context(guard, armBody)
return Context(guard, guardExpr, armBody)
}

override fun invoke(project: Project, editor: Editor, ctx: Context) {
val (guard, oldBody) = ctx
val (guard, guardExpr, oldBody) = ctx
val caretOffsetInGuard = editor.caretModel.offset - guard.textOffset
val psiFactory = RsPsiFactory(project)
var newBody = psiFactory.createIfExpression(guard.expr, oldBody)
var newBody = psiFactory.createIfExpression(guardExpr, oldBody)
newBody = oldBody.replace(newBody) as RsIfExpr
guard.delete()
editor.caretModel.moveToOffset(newBody.textOffset + caretOffsetInGuard)
Expand Down
5 changes: 4 additions & 1 deletion src/main/kotlin/org/rust/lang/core/dfa/ExprUseWalker.kt
Expand Up @@ -446,7 +446,10 @@ class ExprUseWalker(private val delegate: Delegate, private val mc: MemoryCatego

private fun walkArm(discriminantCmt: Cmt, arm: RsMatchArm, mode: MatchMode) {
arm.patList.forEach { walkPat(discriminantCmt, it, mode) }
arm.matchArmGuard?.let { consumeExpr(it.expr) }
val guard = arm.matchArmGuard
if (guard?.let == null) { // TODO: support `if let guard`
guard?.expr?.let { consumeExpr(it) }
}
arm.expr?.let { consumeExpr(it) }
}

Expand Down
Expand Up @@ -104,6 +104,6 @@ class RustParserDefinition : ParserDefinition {
/**
* Should be increased after any change of parser rules
*/
const val PARSER_VERSION: Int = LEXER_VERSION + 31
const val PARSER_VERSION: Int = LEXER_VERSION + 32
}
}
27 changes: 27 additions & 0 deletions src/test/kotlin/org/rust/ide/annotator/RsErrorAnnotatorTest.kt
Expand Up @@ -3000,6 +3000,33 @@ class RsErrorAnnotatorTest : RsAnnotatorTestBase(RsErrorAnnotator::class) {
}
""")

@MockRustcVersion("1.47.0")
fun `test if let guard E0658 1`() = checkErrors("""
fn main() {
fn main() {
let xs = vec![0i32];
match xs.len() {
1 <error descr="if let guard is experimental [E0658]">if let Some(x) = xs.iter().next()</error> => {}
_ => unreachable!(),
}
}
}
""")

@MockRustcVersion("1.47.0-nightly")
fun `test if let guard E0658 2`() = checkErrors("""
#![feature(if_let_guard)]
fn main() {
fn main() {
let xs = vec![0i32];
match xs.len() {
1 if let Some(x) = xs.iter().next() => {}
_ => unreachable!(),
}
}
}
""")

@MockRustcVersion("1.0.0-nightly")
fun `test stable attr on invalid owner E0132`() = checkErrors("""
#![feature(start)]
Expand Down

0 comments on commit 99feb54

Please sign in to comment.