Skip to content

Commit

Permalink
TY&RES: ignore impls from non-dependency crates
Browse files Browse the repository at this point in the history
  • Loading branch information
vlad20012 committed Sep 1, 2022
1 parent cb8a701 commit f055165
Show file tree
Hide file tree
Showing 7 changed files with 94 additions and 77 deletions.
3 changes: 3 additions & 0 deletions src/main/kotlin/org/rust/lang/core/crate/Crate.kt
Expand Up @@ -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
39 changes: 23 additions & 16 deletions src/main/kotlin/org/rust/lang/core/resolve/ImplLookup.kt
Expand Up @@ -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.*
Expand All @@ -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
Expand Down Expand Up @@ -180,7 +180,7 @@ data class ParamEnv(val callerBounds: List<TraitRef>) {
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)
Expand All @@ -196,7 +196,7 @@ data class ParamEnv(val callerBounds: List<TraitRef>) {

class ImplLookup(
private val project: Project,
cargoProject: CargoProject?,
private val containingCrate: Crate?,
val items: KnownItems,
private val paramEnv: ParamEnv = ParamEnv.EMPTY
) {
Expand Down Expand Up @@ -305,7 +305,7 @@ class ImplLookup(
}

private fun findExplicitImplsWithoutAliases(selfTy: Ty, tyf: TyFingerprint, processor: RsProcessor<RsCachedImplItem>): 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
Expand All @@ -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)
Expand All @@ -337,6 +337,19 @@ class ImplLookup(
return processor(TyFingerprint.TYPE_PARAMETER_OR_MACRO_FINGERPRINT)
}

private fun findPotentialImpls(tyf: TyFingerprint): Sequence<RsCachedImplItem> =
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,
Expand All @@ -363,8 +376,8 @@ class ImplLookup(
}

/** return impls for a generic type `impl<T> Trait for T {}` */
private fun findBlanketImpls(): List<RsCachedImplItem> {
return indexCache.findPotentialImpls(TyFingerprint.TYPE_PARAMETER_OR_MACRO_FINGERPRINT)
private fun findBlanketImpls(): Sequence<RsCachedImplItem> {
return findPotentialImpls(TyFingerprint.TYPE_PARAMETER_OR_MACRO_FINGERPRINT)
}

/**
Expand Down Expand Up @@ -747,7 +760,7 @@ class ImplLookup(
}

private fun assembleImplCandidatesWithoutAliases(ref: TraitRef, tyf: TyFingerprint, processor: RsProcessor<SelectionCandidate>): Boolean {
val impls = indexCache.findPotentialImpls(tyf)
val impls = findPotentialImpls(tyf)
return impls.any {
val candidate = it.trySelectCandidate(ref)
candidate != null && processor(candidate)
Expand Down Expand Up @@ -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<Ty, List<TraitImplSource>>("cargoProjectGlobalFindImplsAndTraitsCache")

private val cargoProjectGlobalTraitSelectionCache =
CargoProjectCache<TraitRef, SelectionResult<SelectionCandidate>>("cargoProjectGlobalTraitSelectionCache")
}
}

Expand Down
Expand Up @@ -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 <T: Any> AtomicReference<ConcurrentMap<TyFingerprint, T>?>.getOrCreateMap(): ConcurrentMap<TyFingerprint, T> {
private fun <T : Any> AtomicReference<ConcurrentMap<TyFingerprint, T>?>.getOrCreateMap(): ConcurrentMap<TyFingerprint, T> {
while (true) {
get()?.let { return it }
val map = ContainerUtil.createConcurrentSoftValueMap<TyFingerprint, T>()
Expand Down
Expand Up @@ -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")
}
Expand Down
58 changes: 0 additions & 58 deletions src/main/kotlin/org/rust/lang/utils/CargoProjectCache.kt

This file was deleted.

Expand Up @@ -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) {}
}
""")
}
Expand Up @@ -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: Bar>(_: 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;
}
""")
}

0 comments on commit f055165

Please sign in to comment.