Skip to content

Commit a4d8531

Browse files
committed
(GRAM): untagged unions
closes #781
1 parent 33079ef commit a4d8531

File tree

9 files changed

+127
-5
lines changed

9 files changed

+127
-5
lines changed

src/main/kotlin/org/rust/lang/core/RustFileElementType.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,5 @@ import org.rust.lang.RustLanguage
55
import org.rust.lang.core.stubs.RustFileStub
66

77
object RustFileElementType : IStubFileElementType<RustFileStub>(RustLanguage) {
8-
override fun getStubVersion(): Int = 14
8+
override fun getStubVersion(): Int = 15
99
}

src/main/kotlin/org/rust/lang/core/grammar/rust.bnf

+12
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,7 @@ private item ::= static_item
283283
| mod_item
284284
| foreign_mod_item
285285
| struct_item
286+
| union_item
286287
| enum_item
287288
| view_item
288289
| macro_item
@@ -566,6 +567,17 @@ struct_item ::= attrs_and_vis STRUCT IDENTIFIER generic_params? (tuple_fields? w
566567
elementTypeFactory = "org.rust.lang.core.stubs.ElementFactoryKt.factory"
567568
}
568569

570+
// RFC 1444
571+
union_item ::= attrs_and_vis "union" IDENTIFIER generic_params? where_clause? block_fields {
572+
hooks = [ leftBinder = "DOC_COMMENT_BINDER" ]
573+
implements = [ "org.rust.lang.core.psi.RustItemElement"
574+
"org.rust.lang.core.psi.RustPathNamedElement"
575+
"org.rust.lang.core.psi.RustGenericDeclaration" ]
576+
mixin = "org.rust.lang.core.psi.impl.mixin.RustUnionItemImplMixin"
577+
stubClass = "org.rust.lang.core.stubs.elements.RustUnionItemElementStub"
578+
elementTypeFactory = "org.rust.lang.core.stubs.ElementFactoryKt.factory"
579+
}
580+
569581
enum_item ::= attrs_and_vis ENUM IDENTIFIER generic_params? where_clause? enum_body {
570582
hooks = [ leftBinder = "DOC_COMMENT_BINDER" ]
571583
implements = [ "org.rust.lang.core.resolve.scope.RustResolveScope"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package org.rust.lang.core.psi.impl.mixin
2+
3+
import com.intellij.lang.ASTNode
4+
import com.intellij.psi.stubs.IStubElementType
5+
import org.rust.ide.icons.RustIcons
6+
import org.rust.lang.core.psi.RustUnionItemElement
7+
import org.rust.lang.core.psi.iconWithVisibility
8+
import org.rust.lang.core.psi.impl.RustPsiImplUtil
9+
import org.rust.lang.core.psi.impl.RustStubbedNamedElementImpl
10+
import org.rust.lang.core.stubs.elements.RustUnionItemElementStub
11+
import org.rust.lang.core.symbols.RustPath
12+
import javax.swing.Icon
13+
14+
abstract class RustUnionItemImplMixin : RustStubbedNamedElementImpl<RustUnionItemElementStub>, RustUnionItemElement {
15+
16+
constructor(node: ASTNode) : super(node)
17+
18+
constructor(stub: RustUnionItemElementStub, nodeType: IStubElementType<*, *>) : super(stub, nodeType)
19+
20+
override fun getIcon(flags: Int): Icon =
21+
iconWithVisibility(flags, RustIcons.STRUCT)
22+
23+
override val isPublic: Boolean get() = RustPsiImplUtil.isPublic(this)
24+
25+
override val canonicalCratePath: RustPath? get() = RustPsiImplUtil.canonicalCratePath(this)
26+
}

src/main/kotlin/org/rust/lang/core/stubs/ElementFactory.kt

+2-3
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,9 @@ fun factory(name: String): RustStubElementType<*, *> = when (name) {
1717
"TRAIT_METHOD_MEMBER" -> RustTraitMethodMemberStubElementType
1818
"TYPE_ITEM" -> RustTypeItemStubElementType
1919
"USE_ITEM" -> RustUseItemStubElementType
20+
"UNION_ITEM" -> RustUnionItemStubElementType
2021
"FOREIGN_MOD_ITEM" -> RustForeignModItemStubElementType
2122
"EXTERN_CRATE_ITEM" -> RustExternCrateItemStubElementType
2223

23-
else -> {
24-
throw IllegalArgumentException("Unknown element $name")
25-
}
24+
else -> error("Unknown element $name")
2625
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package org.rust.lang.core.stubs.elements
2+
3+
4+
import com.intellij.psi.stubs.*
5+
import org.rust.lang.core.psi.RustUnionItemElement
6+
import org.rust.lang.core.psi.impl.RustUnionItemElementImpl
7+
import org.rust.lang.core.stubs.RustNamedElementStub
8+
import org.rust.lang.core.stubs.RustNamedStubElementType
9+
import org.rust.lang.core.stubs.index.RustGotoClassIndex
10+
11+
object RustUnionItemStubElementType : RustNamedStubElementType<RustUnionItemElementStub, RustUnionItemElement>("UNION_ITEM") {
12+
override fun createStub(psi: RustUnionItemElement, parentStub: StubElement<*>?): RustUnionItemElementStub =
13+
RustUnionItemElementStub(parentStub, this, psi.name, psi.isPublic)
14+
15+
override fun createPsi(stub: RustUnionItemElementStub): RustUnionItemElement =
16+
RustUnionItemElementImpl(stub, this)
17+
18+
override fun deserialize(dataStream: StubInputStream, parentStub: StubElement<*>?): RustUnionItemElementStub =
19+
RustUnionItemElementStub(parentStub, this, dataStream.readNameAsString(), dataStream.readBoolean())
20+
21+
override fun serialize(stub: RustUnionItemElementStub, dataStream: StubOutputStream) = with(dataStream) {
22+
writeName(stub.name)
23+
writeBoolean(stub.isPublic)
24+
}
25+
26+
override fun indexStub(stub: RustUnionItemElementStub, sink: IndexSink) {
27+
super.indexStub(stub, sink)
28+
stub.name?.let { sink.occurrence(RustGotoClassIndex.KEY, it) }
29+
}
30+
31+
}
32+
33+
34+
class RustUnionItemElementStub(
35+
parent: StubElement<*>?,
36+
elementType: IStubElementType<*, *>,
37+
name: String?,
38+
isPublic: Boolean
39+
) : RustNamedElementStub<RustUnionItemElement>(parent, elementType, name ?: "", isPublic)

src/test/kotlin/org/rust/lang/core/parser/RustCompleteParsingTestCase.kt

+1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ class RustCompleteParsingTestCase : RustParsingTestCaseBase("complete") {
3636
fun testAssociatedTypes() = doTest(true)
3737
fun testLastBlockIsExpression() = doTest(true)
3838
fun testLabels() = doTest(true)
39+
fun testUnion() = doTest(true)
3940

4041
fun testIssue320() = doTest(true)
4142

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#[repr(C)]
2+
union U {
3+
i: i32,
4+
f: f32,
5+
}
6+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
FILE
2+
RustUnionItemElementImpl(UNION_ITEM)
3+
RustOuterAttrElementImpl(OUTER_ATTR)
4+
PsiElement(#)('#')
5+
PsiElement([)('[')
6+
RustMetaItemElementImpl(META_ITEM)
7+
PsiElement(<IDENTIFIER>)('repr')
8+
PsiElement(()('(')
9+
RustMetaItemElementImpl(META_ITEM)
10+
PsiElement(<IDENTIFIER>)('C')
11+
PsiElement())(')')
12+
PsiElement(])(']')
13+
PsiWhiteSpace('\n')
14+
PsiElement(<IDENTIFIER>)('union')
15+
PsiWhiteSpace(' ')
16+
PsiElement(<IDENTIFIER>)('U')
17+
PsiWhiteSpace(' ')
18+
RustBlockFieldsElementImpl(BLOCK_FIELDS)
19+
PsiElement({)('{')
20+
PsiWhiteSpace('\n ')
21+
RustFieldDeclElementImpl(FIELD_DECL)
22+
PsiElement(<IDENTIFIER>)('i')
23+
PsiElement(:)(':')
24+
PsiWhiteSpace(' ')
25+
RustPathTypeElementImpl(PATH_TYPE)
26+
RustPathElementImpl(PATH)
27+
PsiElement(<IDENTIFIER>)('i32')
28+
PsiElement(,)(',')
29+
PsiWhiteSpace('\n ')
30+
RustFieldDeclElementImpl(FIELD_DECL)
31+
PsiElement(<IDENTIFIER>)('f')
32+
PsiElement(:)(':')
33+
PsiWhiteSpace(' ')
34+
RustPathTypeElementImpl(PATH_TYPE)
35+
RustPathElementImpl(PATH)
36+
PsiElement(<IDENTIFIER>)('f32')
37+
PsiElement(,)(',')
38+
PsiWhiteSpace('\n')
39+
PsiElement(})('}')

src/test/resources/org/rust/lang/core/parser/fixtures/partial/fn.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ FILE
8484
RustBlockElementImpl(BLOCK)
8585
PsiElement({)('{')
8686
PsiWhiteSpace('\n ')
87-
PsiErrorElement:<expr>, const, enum, extern, fn, impl, mod, static, struct, trait, type or use expected, got '+'
87+
PsiErrorElement:<expr>, const, enum, extern, fn, impl, mod, static, struct, trait, type, union or use expected, got '+'
8888
PsiElement(+)('+')
8989
PsiWhiteSpace('\n')
9090
PsiElement(})('}')

0 commit comments

Comments
 (0)