Skip to content

Commit

Permalink
PERF: introduce RsCachedImplItem
Browse files Browse the repository at this point in the history
  • Loading branch information
vlad20012 committed Jul 26, 2019
1 parent 7e7d940 commit a76cdf3
Show file tree
Hide file tree
Showing 6 changed files with 90 additions and 27 deletions.
Expand Up @@ -238,9 +238,8 @@ class AutoImportFix(element: RsElement) : LocalQuickFixOnPsiElement(element), Hi
val traits = sources.mapNotNull { source ->
val trait = when (source) {
is TraitImplSource.ExplicitImpl -> {
val impl = source.value
val traitRef = impl.traitRef ?: return null
traitRef.resolveToTrait() ?: return@mapNotNull null
if (source.isInherent) return null
source.implementedTrait?.element ?: return@mapNotNull null
}
is TraitImplSource.Derived -> source.value
is TraitImplSource.Collapsed -> source.value
Expand Down
41 changes: 27 additions & 14 deletions src/main/kotlin/org/rust/lang/core/resolve/ImplLookup.kt
Expand Up @@ -105,25 +105,38 @@ val HARDCODED_FROM_IMPLS_MAP: Map<TyPrimitive, List<TyPrimitive>> = run {
sealed class TraitImplSource {
abstract val value: RsTraitOrImpl

open val implementedTrait: BoundElement<RsTraitItem>? get() = value.implementedTrait
open val members: RsMembers? get() = value.members

val impl: RsImplItem?
get() = (this as? ExplicitImpl)?.value

/** An impl block, directly defined in the code */
data class ExplicitImpl(override val value: RsImplItem): TraitImplSource()
data class ExplicitImpl(private val cachedImpl: RsCachedImplItem) : TraitImplSource() {
override val value: RsImplItem get() = cachedImpl.impl
val isInherent: Boolean get() = cachedImpl.traitRef == null
override val implementedTrait: BoundElement<RsTraitItem>? get() = cachedImpl.implementedTrait
override val members: RsMembers? get() = cachedImpl.membres
}

/** T: Trait */
data class TraitBound(override val value: RsTraitItem): TraitImplSource()
data class TraitBound(override val value: RsTraitItem) : TraitImplSource()

/** Trait is implemented for item via ```#[derive]``` attribute. */
data class Derived(override val value: RsTraitItem): TraitImplSource()
data class Derived(override val value: RsTraitItem) : TraitImplSource()

/** dyn/impl Trait or a closure */
data class Object(override val value: RsTraitItem): TraitImplSource()
data class Object(override val value: RsTraitItem) : TraitImplSource()

/**
* Used only as a result of method pick. It means that method is resolved to multiple impls of the same trait
* (with different type parameter values), so we collapsed all impls to that trait. Specific impl
* will be selected during type inference.
*/
data class Collapsed(override val value: RsTraitItem): TraitImplSource()
data class Collapsed(override val value: RsTraitItem) : TraitImplSource()

/** A trait impl hardcoded in Intellij-Rust. Mostly it's something defined with a macro in stdlib */
data class Hardcoded(override val value: RsTraitItem): TraitImplSource()
data class Hardcoded(override val value: RsTraitItem) : TraitImplSource()
}

/**
Expand Down Expand Up @@ -207,7 +220,7 @@ class ImplLookup(
}

val ctx: RsInferenceContext by lazy(NONE) {
RsInferenceContext(this, items)
RsInferenceContext(project, this, items)
}

fun getEnvBoundTransitivelyFor(ty: Ty): Sequence<BoundElement<RsTraitItem>> {
Expand Down Expand Up @@ -348,11 +361,11 @@ class ImplLookup(
return impls
}

private fun findSimpleImpls(selfTy: Ty): Sequence<RsImplItem> {
private fun findSimpleImpls(selfTy: Ty): Sequence<RsCachedImplItem> {
return RsImplIndex.findPotentialImpls(project, selfTy).mapNotNull { impl ->
val subst = impl.generics.associate { it to ctx.typeVarForParam(it) }.toTypeSubst()
val subst = impl.impl.generics.associate { it to ctx.typeVarForParam(it) }.toTypeSubst()
// TODO: take into account the lifetimes (?)
val formalSelfTy = impl.typeReference?.type?.substitute(subst) ?: return@mapNotNull null
val formalSelfTy = impl.type?.substitute(subst) ?: return@mapNotNull null
impl.takeIf { ctx.canCombineTypes(formalSelfTy, selfTy) }
}
}
Expand Down Expand Up @@ -500,15 +513,15 @@ class ImplLookup(
.toList()
}

private fun Sequence<RsImplItem>.assembleImplCandidates(ref: TraitRef): Sequence<SelectionCandidate> =
private fun Sequence<RsCachedImplItem>.assembleImplCandidates(ref: TraitRef): Sequence<SelectionCandidate> =
mapNotNull { impl ->
val formalTraitRef = impl.implementedTrait ?: return@mapNotNull null
if (formalTraitRef.element != ref.trait.element) return@mapNotNull null
val formalSelfTy = impl.typeReference?.type ?: return@mapNotNull null
val formalSelfTy = impl.type ?: return@mapNotNull null
val (_, implTraitRef) =
prepareSubstAndTraitRefRaw(ctx, impl.generics, formalSelfTy, formalTraitRef, ref.selfTy)
prepareSubstAndTraitRefRaw(ctx, impl.impl.generics, formalSelfTy, formalTraitRef, ref.selfTy)
if (!ctx.probe { ctx.combineTraitRefs(implTraitRef, ref) }) return@mapNotNull null
SelectionCandidate.Impl(impl, formalSelfTy, formalTraitRef)
SelectionCandidate.Impl(impl.impl, formalSelfTy, formalTraitRef)
}

private fun assembleDerivedCandidates(ref: TraitRef): List<SelectionCandidate> {
Expand Down
8 changes: 4 additions & 4 deletions src/main/kotlin/org/rust/lang/core/resolve/NameResolution.kt
Expand Up @@ -528,7 +528,7 @@ private fun processTypeQualifiedPathResolveVariants(
fun(e: AssocItemScopeEntry): Boolean {
if (e.element !is RsTypeAlias) return processor(e)

val implementedTrait = e.source.value.implementedTrait
val implementedTrait = e.source.implementedTrait
?.foldTyTypeParameterWith { TyInfer.TyVar(it) }
?: return processor(e)

Expand Down Expand Up @@ -1129,12 +1129,12 @@ private fun processAssociatedItems(
* which are not implemented.
*/
fun processMembersWithDefaults(accessor: (RsMembers) -> List<RsAbstractable>): Boolean {
val directlyImplemented = traitOrImpl.value.members?.let { accessor(it) }.orEmpty()
val directlyImplemented = traitOrImpl.members?.let { accessor(it) }.orEmpty()
if (directlyImplemented.any { inherentProcessor(it) }) return true

if (traitOrImpl is TraitImplSource.ExplicitImpl) {
val direct = directlyImplemented.map { it.name }.toSet()
val membersFromTrait = traitOrImpl.value.implementedTrait?.element?.members ?: return false
val membersFromTrait = traitOrImpl.implementedTrait?.element?.members ?: return false
for (member in accessor(membersFromTrait)) {
if (member.name !in direct && inherentProcessor(member)) return true
}
Expand All @@ -1152,7 +1152,7 @@ private fun processAssociatedItems(
return false
}

val (inherent, traits) = lookup.findImplsAndTraits(type).partition { it is TraitImplSource.ExplicitImpl && it.value.traitRef == null }
val (inherent, traits) = lookup.findImplsAndTraits(type).partition { it is TraitImplSource.ExplicitImpl && it.isInherent }
if (inherent.any { processTraitOrImpl(it, true) }) return true
if (traits.any { processTraitOrImpl(it, false) }) return true
return false
Expand Down
42 changes: 42 additions & 0 deletions src/main/kotlin/org/rust/lang/core/resolve/RsCachedImplItem.kt
@@ -0,0 +1,42 @@
/*
* Use of this source code is governed by the MIT license that can be
* found in the LICENSE file.
*/

package org.rust.lang.core.resolve

import com.intellij.openapi.project.Project
import org.rust.lang.core.psi.RsImplItem
import org.rust.lang.core.psi.RsMembers
import org.rust.lang.core.psi.RsTraitItem
import org.rust.lang.core.psi.RsTraitRef
import org.rust.lang.core.psi.ext.RsMod
import org.rust.lang.core.psi.ext.resolveToBoundTrait
import org.rust.lang.core.resolve.ref.ResolveCacheDependency
import org.rust.lang.core.resolve.ref.RsResolveCache
import org.rust.lang.core.types.BoundElement
import org.rust.lang.core.types.ty.Ty
import org.rust.lang.core.types.type

class RsCachedImplItem(
val impl: RsImplItem,
val crateRoot: RsMod? = impl.crateRoot,
val traitRef: RsTraitRef? = impl.traitRef,
val membres: RsMembers? = impl.members
) {
val implementedTrait: BoundElement<RsTraitItem>? by lazy(LazyThreadSafetyMode.PUBLICATION) { traitRef?.resolveToBoundTrait() }
val type: Ty? by lazy(LazyThreadSafetyMode.PUBLICATION) { impl.typeReference?.type }

companion object {
fun resolve(project: Project, impl: RsImplItem): RsCachedImplItem {
return RsResolveCache.getInstance(project)
.resolveWithCaching(impl, ResolveCacheDependency.LOCAL_AND_RUST_STRUCTURE, Resolver)!!
}

private object Resolver : (RsImplItem) -> RsCachedImplItem {
override fun invoke(impl: RsImplItem): RsCachedImplItem {
return RsCachedImplItem(impl)
}
}
}
}
Expand Up @@ -15,6 +15,7 @@ import org.rust.ide.search.RsWithMacrosProjectScope
import org.rust.lang.core.macros.macroExpansionManager
import org.rust.lang.core.psi.RsImplItem
import org.rust.lang.core.psi.ext.typeParameters
import org.rust.lang.core.resolve.RsCachedImplItem
import org.rust.lang.core.stubs.RsFileStub
import org.rust.lang.core.stubs.RsImplItemStub
import org.rust.lang.core.types.TyFingerprint
Expand All @@ -31,7 +32,7 @@ class RsImplIndex : AbstractStubIndex<TyFingerprint, RsImplItem>() {
* Note this method may return false positives
* @see TyFingerprint
*/
fun findPotentialImpls(project: Project, target: Ty): Sequence<RsImplItem> {
fun findPotentialImpls(project: Project, target: Ty): Sequence<RsCachedImplItem> {
project.macroExpansionManager.ensureUpToDate()
val impls = run {
val fingerprint = TyFingerprint.create(target)
Expand All @@ -40,14 +41,18 @@ class RsImplIndex : AbstractStubIndex<TyFingerprint, RsImplItem>() {
}
val freeImpls = getElements(KEY, TyFingerprint.TYPE_PARAMETER_FINGERPRINT, project, RsWithMacrosProjectScope(project))
// filter dangling (not attached to some crate) rust files, e.g. tests, generated source
return (impls.asSequence() + freeImpls.asSequence()).filter { it.crateRoot != null }
return (impls.asSequence() + freeImpls.asSequence())
.map { RsCachedImplItem.resolve(project, it) }
.filter { it.crateRoot != null }
}

/** return impls for generic type `impl<T> Trait for T {}` */
fun findFreeImpls(project: Project): Sequence<RsImplItem> {
fun findFreeImpls(project: Project): Sequence<RsCachedImplItem> {
val freeImpls = getElements(KEY, TyFingerprint.TYPE_PARAMETER_FINGERPRINT, project, GlobalSearchScope.allScope(project))
// filter dangling (not attached to some crate) rust files, e.g. tests, generated source
return freeImpls.asSequence().filter { it.crateRoot != null }
return freeImpls.asSequence()
.map { RsCachedImplItem.resolve(project, it) }
.filter { it.crateRoot != null }
}

fun index(stub: RsImplItemStub, sink: IndexSink) {
Expand Down
Expand Up @@ -5,6 +5,7 @@

package org.rust.lang.core.types.infer

import com.intellij.openapi.project.Project
import com.intellij.openapi.util.Computable
import com.intellij.psi.util.CachedValueProvider
import com.intellij.psi.util.CachedValuesManager
Expand Down Expand Up @@ -115,6 +116,7 @@ class RsInferenceResult(
* A mutable object, which is filled while we walk function body top down.
*/
class RsInferenceContext(
val project: Project,
val lookup: ImplLookup,
val items: KnownItems
) : RsInferenceData {
Expand Down Expand Up @@ -245,13 +247,15 @@ class RsInferenceContext(
val fnName = (variant.element as? RsFunction)?.name
val impl = lookup.select(resolveTypeVarsIfPossible(traitRef)).ok()?.impl as? RsImplItem ?: continue
val fn = impl.members?.functionList?.find { it.name == fnName } ?: continue
resolvedPaths[path] = listOf(ResolvedPath.AssocItem(fn, TraitImplSource.ExplicitImpl(impl)))
val source = TraitImplSource.ExplicitImpl(RsCachedImplItem.resolve(project, impl))
resolvedPaths[path] = listOf(ResolvedPath.AssocItem(fn, source))
}
for ((call, traitRef) in methodRefinements) {
val variant = resolvedMethods[call]?.firstOrNull() ?: continue
val impl = lookup.select(resolveTypeVarsIfPossible(traitRef)).ok()?.impl as? RsImplItem ?: continue
val fn = impl.members?.functionList?.find { it.name == variant.name } ?: continue
resolvedMethods[call] = listOf(variant.copy(element = fn, source = TraitImplSource.ExplicitImpl(impl)))
val source = TraitImplSource.ExplicitImpl(RsCachedImplItem.resolve(project, impl))
resolvedMethods[call] = listOf(variant.copy(element = fn, source = source))
}
}

Expand Down

0 comments on commit a76cdf3

Please sign in to comment.