Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GRAM: parse of generic parameters for assoc types / type aliases and assoc type bindings #8542

Merged
merged 1 commit into from
Apr 29, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
21 changes: 11 additions & 10 deletions src/main/grammars/RustParser.bnf
Original file line number Diff line number Diff line change
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
mchernyavsky marked this conversation as resolved.
Show resolved Hide resolved
}

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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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.

Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
@@ -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>;
}