diff --git a/src/main/kotlin/org/rust/lang/core/crate/Crate.kt b/src/main/kotlin/org/rust/lang/core/crate/Crate.kt index a53a728d23e..10d7efb9063 100644 --- a/src/main/kotlin/org/rust/lang/core/crate/Crate.kt +++ b/src/main/kotlin/org/rust/lang/core/crate/Crate.kt @@ -112,3 +112,6 @@ interface Crate : UserDataHolderEx { fun Crate.findDependency(normName: String): Crate? = dependencies.find { it.normName == normName }?.crate + +fun Crate.hasTransitiveDependencyOrSelf(other: Crate): Boolean = + other == this || other in flatDependencies diff --git a/src/main/kotlin/org/rust/lang/core/resolve/ImplLookup.kt b/src/main/kotlin/org/rust/lang/core/resolve/ImplLookup.kt index caf28f4dd99..00f01731d79 100644 --- a/src/main/kotlin/org/rust/lang/core/resolve/ImplLookup.kt +++ b/src/main/kotlin/org/rust/lang/core/resolve/ImplLookup.kt @@ -8,7 +8,8 @@ package org.rust.lang.core.resolve import com.intellij.openapi.project.Project import com.intellij.util.SmartList import gnu.trove.THashMap -import org.rust.cargo.project.model.CargoProject +import org.rust.lang.core.crate.Crate +import org.rust.lang.core.crate.hasTransitiveDependencyOrSelf import org.rust.lang.core.psi.* import org.rust.lang.core.psi.ext.* import org.rust.lang.core.resolve.SelectionCandidate.* @@ -20,7 +21,6 @@ import org.rust.lang.core.types.infer.* import org.rust.lang.core.types.infer.TypeInferenceMarks.WinnowParamCandidateLoses import org.rust.lang.core.types.infer.TypeInferenceMarks.WinnowParamCandidateWins import org.rust.lang.core.types.ty.* -import org.rust.lang.utils.CargoProjectCache import org.rust.openapiext.hitOnTrue import org.rust.openapiext.testAssert import org.rust.stdext.buildList @@ -180,7 +180,7 @@ data class ParamEnv(val callerBounds: List) { 1 -> return ParamEnv(rawBounds) } - val lookup = ImplLookup(decl.project, decl.cargoProject, decl.knownItems, ParamEnv(rawBounds)) + val lookup = ImplLookup(decl.project, decl.containingCrate, decl.knownItems, ParamEnv(rawBounds)) val ctx = lookup.ctx val bounds2 = rawBounds.map { val (bound, obligations) = ctx.normalizeAssociatedTypesIn(it) @@ -196,7 +196,7 @@ data class ParamEnv(val callerBounds: List) { class ImplLookup( private val project: Project, - cargoProject: CargoProject?, + private val containingCrate: Crate?, val items: KnownItems, private val paramEnv: ParamEnv = ParamEnv.EMPTY ) { @@ -305,7 +305,7 @@ class ImplLookup( } private fun findExplicitImplsWithoutAliases(selfTy: Ty, tyf: TyFingerprint, processor: RsProcessor): Boolean { - val impls = indexCache.findPotentialImpls(tyf) + val impls = findPotentialImpls(tyf) return impls.any { cachedImpl -> if (cachedImpl.isNegativeImpl) return@any false val (type, generics, constGenerics) = cachedImpl.typeAndGenerics ?: return@any false @@ -322,7 +322,7 @@ class ImplLookup( if (fingerprint != null) { val set = mutableSetOf(fingerprint) if (processor(fingerprint)) return true - val aliases = indexCache.findPotentialAliases(fingerprint) + val aliases = findPotentialAliases(fingerprint) val result = aliases.any { val name = it.name ?: return@any false val aliasFingerprint = TyFingerprint(name) @@ -337,6 +337,19 @@ class ImplLookup( return processor(TyFingerprint.TYPE_PARAMETER_OR_MACRO_FINGERPRINT) } + private fun findPotentialImpls(tyf: TyFingerprint): Sequence = + indexCache.findPotentialImpls(tyf) + .asSequence() + .filter { useImplsFromCrate(it.containingCrate) } + + private fun findPotentialAliases(tyf: TyFingerprint) = + indexCache.findPotentialAliases(tyf) + .asSequence() + .filter { useImplsFromCrate(it.containingCrate) } + + private fun useImplsFromCrate(crate: Crate?): Boolean = + containingCrate == null || crate != null && containingCrate.hasTransitiveDependencyOrSelf(crate) + private fun canCombineTypes( ty1: Ty, ty2: Ty, @@ -363,8 +376,8 @@ class ImplLookup( } /** return impls for a generic type `impl Trait for T {}` */ - private fun findBlanketImpls(): List { - return indexCache.findPotentialImpls(TyFingerprint.TYPE_PARAMETER_OR_MACRO_FINGERPRINT) + private fun findBlanketImpls(): Sequence { + return findPotentialImpls(TyFingerprint.TYPE_PARAMETER_OR_MACRO_FINGERPRINT) } /** @@ -747,7 +760,7 @@ class ImplLookup( } private fun assembleImplCandidatesWithoutAliases(ref: TraitRef, tyf: TyFingerprint, processor: RsProcessor): Boolean { - val impls = indexCache.findPotentialImpls(tyf) + val impls = findPotentialImpls(tyf) return impls.any { val candidate = it.trySelectCandidate(ref) candidate != null && processor(candidate) @@ -1268,14 +1281,8 @@ class ImplLookup( } else { ParamEnv.EMPTY } - return ImplLookup(psi.project, psi.cargoProject, psi.knownItems, paramEnv) + return ImplLookup(psi.project, psi.containingCrate, psi.knownItems, paramEnv) } - - private val cargoProjectGlobalFindImplsAndTraitsCache = - CargoProjectCache>("cargoProjectGlobalFindImplsAndTraitsCache") - - private val cargoProjectGlobalTraitSelectionCache = - CargoProjectCache>("cargoProjectGlobalTraitSelectionCache") } } diff --git a/src/main/kotlin/org/rust/lang/core/resolve/RsImplIndexAndTypeAliasCache.kt b/src/main/kotlin/org/rust/lang/core/resolve/RsImplIndexAndTypeAliasCache.kt index 4cc31fa45a0..760eff6c835 100644 --- a/src/main/kotlin/org/rust/lang/core/resolve/RsImplIndexAndTypeAliasCache.kt +++ b/src/main/kotlin/org/rust/lang/core/resolve/RsImplIndexAndTypeAliasCache.kt @@ -80,11 +80,11 @@ class RsImplIndexAndTypeAliasCache(private val project: Project) : Disposable { override fun dispose() {} companion object { - fun getInstance(project: Project): RsImplIndexAndTypeAliasCache = + fun getInstance(project: Project): RsImplIndexAndTypeAliasCache = project.service() @JvmStatic - private fun AtomicReference?>.getOrCreateMap(): ConcurrentMap { + private fun AtomicReference?>.getOrCreateMap(): ConcurrentMap { while (true) { get()?.let { return it } val map = ContainerUtil.createConcurrentSoftValueMap() diff --git a/src/main/kotlin/org/rust/lang/core/types/infer/TypeInference.kt b/src/main/kotlin/org/rust/lang/core/types/infer/TypeInference.kt index 80a6639c5b1..d1f9132cd66 100644 --- a/src/main/kotlin/org/rust/lang/core/types/infer/TypeInference.kt +++ b/src/main/kotlin/org/rust/lang/core/types/infer/TypeInference.kt @@ -35,7 +35,7 @@ import org.rust.stdext.RsResult.Ok fun inferTypesIn(element: RsInferenceContextOwner): RsInferenceResult { val items = element.knownItems val paramEnv = if (element is RsGenericDeclaration) ParamEnv.buildFor(element) else ParamEnv.EMPTY - val lookup = ImplLookup(element.project, element.cargoProject, items, paramEnv) + val lookup = ImplLookup(element.project, element.containingCrate, items, paramEnv) return recursionGuard(element, { lookup.ctx.infer(element) }, memoize = false) ?: error("Can not run nested type inference") } diff --git a/src/main/kotlin/org/rust/lang/utils/CargoProjectCache.kt b/src/main/kotlin/org/rust/lang/utils/CargoProjectCache.kt deleted file mode 100644 index 4654198b2d1..00000000000 --- a/src/main/kotlin/org/rust/lang/utils/CargoProjectCache.kt +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Use of this source code is governed by the MIT license that can be - * found in the LICENSE file. - */ - -package org.rust.lang.utils - -import com.intellij.openapi.util.Key -import com.intellij.psi.util.CachedValue -import com.intellij.psi.util.CachedValueProvider -import com.intellij.psi.util.CachedValuesManager -import com.intellij.util.containers.ContainerUtil -import org.rust.cargo.project.model.CargoProject -import org.rust.lang.core.psi.rustStructureModificationTracker -import org.rust.stdext.Cache -import java.util.concurrent.ConcurrentHashMap -import java.util.concurrent.ConcurrentMap - -/** - * Similar to [org.rust.openapiext.ProjectCache], but based on [CargoProject] - */ -class CargoProjectCache( - cacheName: String, - private val dependencyGetter: (CargoProject) -> Any = { it.project.rustStructureModificationTracker } -) { - init { - if (!registered.add(cacheName)) { - error(""" - CargoProjectCache `$cacheName` is already registered. - Make sure ProjectCache is static, that is, put it inside companion object. - """.trimIndent()) - } - } - - private val cacheKey: Key>> = Key.create(cacheName) - - fun getOrPut(project: CargoProject, key: T, defaultValue: () -> R): R { - val cache = getCacheInternal(project) - return cache.getOrPut(key) { defaultValue() } - } - - fun getCache(project: CargoProject): Cache = - Cache.fromConcurrentMap(getCacheInternal(project)) - - private fun getCacheInternal(project: CargoProject): ConcurrentMap { - return CachedValuesManager.getManager(project.project) - .getCachedValue(project, cacheKey, { - CachedValueProvider.Result.create( - ConcurrentHashMap(), - dependencyGetter(project) - ) - }, false) - } - - companion object { - private val registered = ContainerUtil.newConcurrentSet() - } -} diff --git a/src/test/kotlin/org/rust/lang/core/resolve/RsStubOnlyResolveTest.kt b/src/test/kotlin/org/rust/lang/core/resolve/RsStubOnlyResolveTest.kt index b7eeac2cac1..c30bc0f197c 100644 --- a/src/test/kotlin/org/rust/lang/core/resolve/RsStubOnlyResolveTest.kt +++ b/src/test/kotlin/org/rust/lang/core/resolve/RsStubOnlyResolveTest.kt @@ -892,4 +892,44 @@ class RsStubOnlyResolveTest : RsResolveTestBase() { pub fn func() {} } """) + + fun `test method is not resolved to independent crate 1`() = stubOnlyResolve(""" + //- lib.rs + pub struct Foo; + + fn foo() { + Foo.bar(); + } //^ unresolved + //- main.rs + use test_package::*; + + impl Foo { // Incoherent impl + fn bar(&self) {} + } + """) + + fun `test method is not resolved to independent crate 2`() = stubOnlyResolve(""" + //- bar.rs + pub struct Foo; + pub trait Bar { + fn bar(&self); + } + //- lib.rs + mod bar; + pub use bar::*; + + impl Bar for Foo { + fn bar(&self) {} + } + + fn foo() { + Foo.bar(); + } //^ lib.rs + //- main.rs + use test_package::*; + + impl Bar for Foo { // Incoherent impl + fn bar(&self) {} + } + """) } diff --git a/src/test/kotlin/org/rust/lang/core/type/RsGenericExpressionTypeInferenceTest.kt b/src/test/kotlin/org/rust/lang/core/type/RsGenericExpressionTypeInferenceTest.kt index b66713fdb07..b993552f099 100644 --- a/src/test/kotlin/org/rust/lang/core/type/RsGenericExpressionTypeInferenceTest.kt +++ b/src/test/kotlin/org/rust/lang/core/type/RsGenericExpressionTypeInferenceTest.kt @@ -2240,4 +2240,29 @@ class RsGenericExpressionTypeInferenceTest : RsTypificationTestBase() { a; } //^ X """) + + fun `test ignore impl in independent crate`() = stubOnlyTypeInfer(""" + //- lib.rs + pub struct Foo; + pub trait Bar { + type Item; + } + + impl Bar for Foo { + type Item = i32; + } + + fn infer(_: T) -> T::Item { todo!() } + + fn foo() { + let a = infer(Foo); + a; + } //^ i32 + //- main.rs + use test_package::*; + + impl Bar for Foo { // Incoherent impl + type Item = u8; + } + """) }