diff --git a/src/main/kotlin/org/rust/lang/core/psi/ext/RsAbstractable.kt b/src/main/kotlin/org/rust/lang/core/psi/ext/RsAbstractable.kt index aee1ef8574c..2c1b5a832e8 100644 --- a/src/main/kotlin/org/rust/lang/core/psi/ext/RsAbstractable.kt +++ b/src/main/kotlin/org/rust/lang/core/psi/ext/RsAbstractable.kt @@ -43,17 +43,17 @@ inline fun RsAbstractable.getOwner(getAncestor: PsiElement.() -> PsiElement?): R // Resolve a const, fn or type in a impl block to the corresponding item in the trait block val RsAbstractable.superItem: RsAbstractable? get() { - val rustImplItem = ancestorStrict() ?: return null - val superTrait = rustImplItem.traitRef?.resolveToTrait() ?: return null + val impl = (owner as? RsAbstractableOwner.Impl)?.impl ?: return null + val superTrait = impl.traitRef?.resolveToTrait() ?: return null return superTrait.findCorrespondingElement(this) } fun RsTraitOrImpl.findCorrespondingElement(element: RsAbstractable): RsAbstractable? { - val members = members ?: return null + val members = expandedMembers return when (element) { - is RsConstant -> members.constantList.find { it.name == element.name } - is RsFunction -> members.functionList.find { it.name == element.name } - is RsTypeAlias -> members.typeAliasList.find { it.name == element.name } + is RsConstant -> members.constants.find { it.name == element.name } + is RsFunction -> members.functions.find { it.name == element.name } + is RsTypeAlias -> members.types.find { it.name == element.name } else -> error("unreachable") } } diff --git a/src/main/kotlin/org/rust/lang/core/resolve/ref/RsPathReferenceImpl.kt b/src/main/kotlin/org/rust/lang/core/resolve/ref/RsPathReferenceImpl.kt index 3ad34729fa5..e7ed914dc65 100644 --- a/src/main/kotlin/org/rust/lang/core/resolve/ref/RsPathReferenceImpl.kt +++ b/src/main/kotlin/org/rust/lang/core/resolve/ref/RsPathReferenceImpl.kt @@ -30,18 +30,46 @@ class RsPathReferenceImpl( override val RsPath.referenceAnchor: PsiElement get() = referenceNameElement - override fun isReferenceTo(element: PsiElement): Boolean { - if (element is RsFieldDecl) return false + override fun isReferenceTo(target: PsiElement): Boolean { + if (target is RsFieldDecl) return false val path = this.element - if (element is RsNamedElement && !path.allowedNamespaces().intersects(element.namespaces)) return false + if (target is RsNamedElement && !path.allowedNamespaces().intersects(target.namespaces)) return false - val isMember = element is RsAbstractable && element.owner.isImplOrTrait - if (isMember && (path.parent is RsUseSpeck || path.path == null && path.typeQual == null)) { - return false + if (target is RsAbstractable) { + val owner = target.owner + if (owner.isImplOrTrait && (path.parent is RsUseSpeck || path.path == null && path.typeQual == null)) { + return false + } + + // If `path.parent` is expression, then `path.reference.resolve()` will invoke type inference for the + // function containing `path`, which can be very heavy. Trying to avoid it + if (target !is RsTypeAlias && path.parent is RsPathExpr) { + val resolvedRaw = resolvePathRaw(path) + val mgr = target.manager + when (owner) { + RsAbstractableOwner.Free, RsAbstractableOwner.Foreign -> + return resolvedRaw.any { mgr.areElementsEquivalent(it.element, target) } + is RsAbstractableOwner.Impl -> if (owner.isInherent) { + return resolvedRaw.any { mgr.areElementsEquivalent(it.element, target) } + } else { + val superItem = target.superItem ?: return false + if (resolvedRaw.size == 1 && mgr.areElementsEquivalent(resolvedRaw.single().element, target)) return true + val canBeReferenceTo = resolvedRaw.any { + mgr.areElementsEquivalent(it.element, target) || + mgr.areElementsEquivalent(it.element, superItem) + } + if (!canBeReferenceTo) return false + } + is RsAbstractableOwner.Trait -> { + val canBeReferenceTo = resolvedRaw.any { mgr.areElementsEquivalent(it.element, target) } + if (!canBeReferenceTo) return false + } + } + } } - val target = resolve() - return element.manager.areElementsEquivalent(target, element) + val resolved = resolve() + return target.manager.areElementsEquivalent(resolved, target) } override fun advancedResolve(): BoundElement? = @@ -74,7 +102,7 @@ class RsPathReferenceImpl( } } -fun resolvePathRaw(path: RsPath, lookup: ImplLookup): List { +fun resolvePathRaw(path: RsPath, lookup: ImplLookup? = null): List { return collectResolveVariantsAsScopeEntries(path.referenceName) { processPathResolveVariants(lookup, path, false, it) }