Skip to content

Commit

Permalink
Merge #8542
Browse files Browse the repository at this point in the history
8542: GRAM: Fix parsing of generic parameters for assoc types / type aliases and assoc type bindings r=vlad20012 a=mchernyavsky

Relates to #6633.

changelog: Fix parsing of generic parameters for assoc types / type aliases and assoc type bindings


Co-authored-by: mhernyavsky <chernyavsky.mikhail@gmail.com>
  • Loading branch information
bors[bot] and mhernyavsky committed Apr 29, 2022
2 parents 6ab14f3 + fe082f1 commit 484384d
Show file tree
Hide file tree
Showing 20 changed files with 593 additions and 105 deletions.
21 changes: 11 additions & 10 deletions src/main/grammars/RustParser.bnf
Expand Up @@ -229,15 +229,18 @@ TypeArgumentList ::= TypeArgumentListImpl {
ColonTypeArgumentList ::= &'::' TypeArgumentListImpl { elementType = TypeArgumentList }

private TypeArgumentListImpl ::= '::'? '<' !'=' <<list_element AnyTypeArgument>>* '>' { pin = 3 }
private AnyTypeArgument ::= AssocTypeBinding | TypeReference | Lifetime | RestrictedConstExpr
private AnyTypeArgument ::= <<typeReferenceOrAssocTypeBinding TypePathGenericArgsNoTypeQual AssocTypeBinding_upper TypeReference TraitType_upper>>
| Lifetime
| RestrictedConstExpr
| never (AssocTypeBinding | TypeReference)

AssocTypeBinding ::= identifier (AssocTypeBindingType | AssocTypeBindingBound) {
implements = [ "org.rust.lang.core.psi.ext.RsMandatoryReferenceElement" ]
mixin = "org.rust.lang.core.psi.ext.RsAssocTypeBindingMixin"
stubClass = "org.rust.lang.core.stubs.RsAssocTypeBindingStub"
AssocTypeBinding ::= TypePathGenericArgsNoTypeQual (AssocTypeBindingType | AssocTypeBindingBound) {
extends = "org.rust.lang.core.psi.ext.RsStubbedElementImpl<?>"
stubClass = "org.rust.lang.core.stubs.RsPlaceholderStub"
elementTypeFactory = "org.rust.lang.core.stubs.StubImplementationsKt.factory"
}

private AssocTypeBinding_upper ::= AssocTypeBindingType | AssocTypeBindingBound
private AssocTypeBindingType ::= '=' TypeReference { pin = 1 }
private AssocTypeBindingBound ::= ':' TypeBounds { pin = 1 }

Expand Down Expand Up @@ -941,7 +944,7 @@ ScalarTypeReference ::= ArrayType
ArrayType ::= '[' TypeReference [';' AnyExpr] ']' {
pin = 1
implements = [ "org.rust.lang.core.psi.ext.RsInferenceContextOwner" ]
elementTypeFactory = "org.rust.lang.core.stubs.StubImplementationsKt.factory"
elementTypeFactory = "org.rust.lang.core.stubs.StubImplementationsKt.factory"i
}

private RefLikeStart ::= ( '&' Lifetime? mut? | '*' [ const | mut ] )
Expand Down Expand Up @@ -1008,9 +1011,7 @@ private ImplicitTraitTypeInner ::= Polybound ('+' Polybound)+

private TraitType_upper ::= ('+' Polybound)+

upper TypeAlias ::= TYPE_KW identifier
[ TypeParameterList WhereClause? | WhereClause | TypeParamBounds ]
[ '=' TypeReference ] ';' {
upper TypeAlias ::= TYPE_KW identifier TypeParameterList? TypeParamBounds? WhereClause? [ '=' TypeReference ] ';' {
pin = 'identifier'
name = ""
implements = [ "org.rust.lang.core.psi.ext.RsQualifiedNamedElement"
Expand Down Expand Up @@ -1138,7 +1139,7 @@ AddBinExpr ::= Expr <<isIncompleteBlockExpr>> AddBinOp <<setStmtMode 'Stmt
MulBinExpr ::= Expr <<isIncompleteBlockExpr>> MulBinOp <<setStmtMode 'StmtMode.OFF'>> Expr <<resetFlags>>

CompBinOp ::= '==' | '!=' { name = "operator" }
RelCompBinOp ::= lteq | gteq | !ltlt '<' | !gtgt <<checkGtAllowed>> '>' { name = "operator" }
RelCompBinOp ::= lteq | <<checkGtAllowed>> gteq | !ltlt '<' | !gtgt <<checkGtAllowed>> '>' { name = "operator" }
BitShiftBinOp ::= ltlt | <<checkGtAllowed>> gtgt { name = "operator" }
AddBinOp ::= '+' | '-' { name = "operator" }
MulBinOp ::= '*' | '/' | '%' { name = "operator" }
Expand Down
Expand Up @@ -419,7 +419,7 @@ private fun PsiElement.generateDocumentation(buffer: StringBuilder, prefix: Stri
when (this) {
is RsPath -> generatePathDocumentation(this, buffer)
is RsAssocTypeBinding -> {
buffer += identifier.text
path.generateDocumentation(buffer)
typeReference?.generateDocumentation(buffer, " = ")
}
is RsTraitRef -> path.generateDocumentation(buffer)
Expand Down
2 changes: 1 addition & 1 deletion src/main/kotlin/org/rust/ide/presentation/RsPsiRenderer.kt
Expand Up @@ -457,7 +457,7 @@ open class RsPsiRenderer(
}
}
assocTypeBindings.joinToWithBuffer(sb, ", ") { sb ->
sb.append(referenceName)
appendPath(sb, this.path)
sb.append("=")
typeReference?.let { appendTypeReference(sb, 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 + 37
const val PARSER_VERSION: Int = LEXER_VERSION + 38
}
}
50 changes: 50 additions & 0 deletions src/main/kotlin/org/rust/lang/core/parser/RustParserUtil.kt
Expand Up @@ -429,6 +429,56 @@ object RustParserUtil : GeneratedParserUtilBase() {
return result
}

@Suppress("DuplicatedCode")
@JvmStatic
fun typeReferenceOrAssocTypeBinding(
b: PsiBuilder,
level: Int,
pathP: Parser,
assocTypeBindingUpperP: Parser,
typeReferenceP: Parser,
traitTypeUpperP: Parser,
): Boolean {
if (b.tokenType == DYN || b.tokenType == IDENTIFIER && b.tokenText == "dyn" && b.lookAhead(1) != EXCL) {
return typeReferenceP.parse(b, level)
}

val typeOrAssoc = enter_section_(b)
val polybound = enter_section_(b)
val bound = enter_section_(b)
val traitRef = enter_section_(b)

if (!pathP.parse(b, level) || nextTokenIsFast(b, EXCL)) {
exit_section_(b, traitRef, null, false)
exit_section_(b, bound, null, false)
exit_section_(b, polybound, null, false)
exit_section_(b, typeOrAssoc, null, false)
return typeReferenceP.parse(b, level)
}

if (nextTokenIsFast(b, PLUS) ) {
exit_section_(b, traitRef, TRAIT_REF, true)
exit_section_(b, bound, BOUND, true)
exit_section_(b, polybound, POLYBOUND, true)
val result = traitTypeUpperP.parse(b, level)
exit_section_(b, typeOrAssoc, TRAIT_TYPE, result)
return result
}

exit_section_(b, traitRef, null, true)
exit_section_(b, bound, null, true)
exit_section_(b, polybound, null, true)

if (!nextTokenIsFast(b, EQ) && !nextTokenIsFast(b, COLON)) {
exit_section_(b, typeOrAssoc, BASE_TYPE, true)
return true
}

val result = assocTypeBindingUpperP.parse(b, level)
exit_section_(b, typeOrAssoc, ASSOC_TYPE_BINDING, result)
return result
}

private val SPECIAL_MACRO_PARSERS: Map<String, (PsiBuilder, Int) -> Boolean>
private val SPECIAL_EXPR_MACROS: Set<String>

Expand Down
20 changes: 0 additions & 20 deletions src/main/kotlin/org/rust/lang/core/psi/ext/RsAssocTypeBinding.kt
Expand Up @@ -5,30 +5,10 @@

package org.rust.lang.core.psi.ext

import com.intellij.lang.ASTNode
import com.intellij.psi.PsiElement
import com.intellij.psi.stubs.IStubElementType
import org.rust.lang.core.psi.RsAssocTypeBinding
import org.rust.lang.core.psi.RsPath
import org.rust.lang.core.resolve.ref.RsAssocTypeBindingReferenceImpl
import org.rust.lang.core.resolve.ref.RsReference
import org.rust.lang.core.stubs.RsAssocTypeBindingStub

// Current grammar allows to write assoc type bindings in method calls, e.g.
// `a.foo::<Item = i32>()`, so it's nullable
val RsAssocTypeBinding.parentPath: RsPath?
get() = ancestorStrict()

abstract class RsAssocTypeBindingMixin : RsStubbedElementImpl<RsAssocTypeBindingStub>,
RsAssocTypeBinding {

constructor(node: ASTNode) : super(node)

constructor(stub: RsAssocTypeBindingStub, nodeType: IStubElementType<*, *>) : super(stub, nodeType)

override fun getReference(): RsReference = RsAssocTypeBindingReferenceImpl(this)

override val referenceNameElement: PsiElement get() = identifier

override val referenceName: String get() = greenStub?.referenceName ?: super.referenceName
}
2 changes: 2 additions & 0 deletions src/main/kotlin/org/rust/lang/core/psi/ext/RsMethodOrPath.kt
Expand Up @@ -5,13 +5,15 @@

package org.rust.lang.core.psi.ext

import org.rust.lang.core.psi.RsAssocTypeBinding
import org.rust.lang.core.psi.RsLifetime
import org.rust.lang.core.psi.RsTypeArgumentList
import org.rust.lang.core.psi.RsTypeReference

val RsMethodOrPath.lifetimeArguments: List<RsLifetime> get() = typeArgumentList?.lifetimeArguments.orEmpty()
val RsMethodOrPath.typeArguments: List<RsTypeReference> get() = typeArgumentList?.typeArguments.orEmpty()
val RsMethodOrPath.constArguments: List<RsElement> get() = typeArgumentList?.constArguments.orEmpty()
val RsMethodOrPath.assocTypeBindings: List<RsAssocTypeBinding> get() = typeArgumentList?.assocTypeBindingList.orEmpty()

fun RsMethodOrPath.getGenericArguments(
includeLifetimes: Boolean = true,
Expand Down
3 changes: 3 additions & 0 deletions src/main/kotlin/org/rust/lang/core/resolve/NameResolution.kt
Expand Up @@ -324,6 +324,9 @@ fun processPathResolveVariants(lookup: ImplLookup?, path: RsPath, isCompletion:
if (parent is RsMacroCall) {
error("Tried to use `processPathResolveVariants` for macro path. See `RsMacroPathReferenceImpl`")
}
if (parent is RsAssocTypeBinding) {
return processAssocTypeVariants(parent, processor)
}
val qualifier = path.qualifier
val typeQual = path.typeQual
val ns = path.allowedNamespaces(isCompletion)
Expand Down

This file was deleted.

Expand Up @@ -38,6 +38,11 @@ class RsPathReferenceImpl(

if (target is RsAbstractable) {
val owner = target.owner

if (target is RsTypeAlias && owner.isImplOrTrait && path.parent is RsAssocTypeBinding) {
return super.isReferenceTo(target)
}

if (owner.isImplOrTrait && (path.parent is RsUseSpeck || path.path == null && path.typeQual == null)) {
return false
}
Expand Down Expand Up @@ -417,7 +422,7 @@ private fun pathTypeParameters(path: RsPath): RsPsiPathParameters? {
}

private fun resolveAssocTypeBinding(trait: RsTraitItem, binding: RsAssocTypeBinding): RsTypeAlias? =
collectResolveVariants(binding.referenceName) { processAssocTypeVariants(trait, it) }
collectResolveVariants(binding.path.referenceName) { processAssocTypeVariants(trait, it) }
.singleOrNull() as? RsTypeAlias?

/** Resolves a reference through type aliases */
Expand Down
27 changes: 1 addition & 26 deletions src/main/kotlin/org/rust/lang/core/stubs/StubImplementations.kt
Expand Up @@ -272,7 +272,7 @@ fun factory(name: String): RsStubElementType<*, *> = when (name) {
"LIFETIME_PARAMETER" -> RsLifetimeParameterStub.Type
"FOR_LIFETIMES" -> RsPlaceholderStub.Type("FOR_LIFETIMES", ::RsForLifetimesImpl)
"TYPE_ARGUMENT_LIST" -> RsPlaceholderStub.Type("TYPE_ARGUMENT_LIST", ::RsTypeArgumentListImpl)
"ASSOC_TYPE_BINDING" -> RsAssocTypeBindingStub.Type
"ASSOC_TYPE_BINDING" -> RsPlaceholderStub.Type("ASSOC_TYPE_BINDING", ::RsAssocTypeBindingImpl)

"TYPE_PARAM_BOUNDS" -> RsPlaceholderStub.Type("TYPE_PARAM_BOUNDS", ::RsTypeParamBoundsImpl)
"POLYBOUND" -> RsPolyboundStub.Type
Expand Down Expand Up @@ -2155,31 +2155,6 @@ private fun RsStubLiteralKind?.serialize(dataStream: StubOutputStream) {
}
}

class RsAssocTypeBindingStub(
parent: StubElement<*>?, elementType: IStubElementType<*, *>,
val referenceName: String
) : StubBase<RsAssocTypeBinding>(parent, elementType) {

object Type : RsStubElementType<RsAssocTypeBindingStub, RsAssocTypeBinding>("ASSOC_TYPE_BINDING") {
override fun deserialize(dataStream: StubInputStream, parentStub: StubElement<*>?) =
RsAssocTypeBindingStub(
parentStub, this,
dataStream.readNameAsString()!!
)

override fun serialize(stub: RsAssocTypeBindingStub, dataStream: StubOutputStream) =
with(dataStream) {
writeName(stub.referenceName)
}

override fun createPsi(stub: RsAssocTypeBindingStub): RsAssocTypeBinding =
RsAssocTypeBindingImpl(stub, this)

override fun createStub(psi: RsAssocTypeBinding, parentStub: StubElement<*>?) =
RsAssocTypeBindingStub(parentStub, this, psi.referenceName)
}
}

class RsPolyboundStub(
parent: StubElement<*>?, elementType: IStubElementType<*, *>,
val hasQ: Boolean,
Expand Down
Expand Up @@ -1028,9 +1028,9 @@ private fun List<RsPolybound>?.toPredicates(selfTy: Ty): Sequence<PsiPredicate>
val traitRef = bound.bound.traitRef ?: return@flatMap emptySequence<PsiPredicate>()
val boundTrait = traitRef.resolveToBoundTrait() ?: return@flatMap emptySequence<PsiPredicate>()

val assocTypeBounds = traitRef.path.typeArgumentList?.assocTypeBindingList.orEmpty().asSequence()
val assocTypeBounds = traitRef.path.assocTypeBindings.asSequence()
.flatMap nestedFlatMap@{
val assoc = it.reference.resolve() as? RsTypeAlias
val assoc = it.path.reference?.resolve() as? RsTypeAlias
?: return@nestedFlatMap emptySequence<PsiPredicate>()
val projectionTy = TyProjection.valueOf(selfTy, assoc)
val typeRef = it.typeReference
Expand Down
@@ -1,10 +1,13 @@
trait T {
type B;
type A = Self;
type A;
type B = Self;
type C<U>;
type D<U> = E<U>;
}

struct S;

impl T for S {
type B = T;
type A = T;
type C<U> = T<U>;
}

0 comments on commit 484384d

Please sign in to comment.