Skip to content

Commit 8370cc4

Browse files
committed
TY: Improve autocompletion for primitive types
In Rust primitive types are only allowed a single impl block that must be annotated with lang attribute We do not enforce this yet an accept user defined impl blocks. See rust-lang/rust#23104 and the error code E0390. The primitive type bool does not have an impl block / lang attribute. TODO: * Clean up a lot * Combine the 2 find methods * Missing primitive types: slice, const_ptr, mut_ptr * Autocompletions on u8, i8, ... do not work as they are implemented by a macro * What fingerprint/string should we use for primitive types (to avoid overlap with user defined types) * Incomplete tests
1 parent f9d0145 commit 8370cc4

File tree

4 files changed

+88
-5
lines changed

4 files changed

+88
-5
lines changed

src/main/kotlin/org/rust/lang/core/resolve/ResolveEngine.kt

+2-1
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,8 @@ private fun lexicalDeclarations(
305305
sequenceOf(
306306
itemDeclarations(scope, true, context),
307307
injectedCrates(scope),
308-
preludeSymbols(scope.module, context)
308+
preludeSymbols(scope.module, context),
309+
emptySequence()//TODO inject primitive types somewhere around here maybe???
309310
).flatten()
310311

311312
is RsModItem ->

src/main/kotlin/org/rust/lang/core/resolve/indexes/RsImplIndex.kt

+20-1
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,11 @@ import org.rust.lang.core.psi.RsStructOrEnumItemElement
1313
import org.rust.lang.core.psi.impl.mixin.isAssocFn
1414
import org.rust.lang.core.stubs.RsFileStub
1515
import org.rust.lang.core.stubs.RsImplItemStub
16-
import org.rust.lang.core.types.types.RustStructOrEnumTypeBase
1716
import org.rust.lang.core.types.RustType
1817
import org.rust.lang.core.types.RustTypeFingerprint
1918
import org.rust.lang.core.types.type
19+
import org.rust.lang.core.types.types.RustPrimitiveType
20+
import org.rust.lang.core.types.types.RustStructOrEnumTypeBase
2021

2122

2223
object RsImplIndex {
@@ -32,6 +33,8 @@ object RsImplIndex {
3233
fun findImplsFor(target: RustType, project: Project): Sequence<RsImplItem> {
3334
val inherentImpls = if (target is RustStructOrEnumTypeBase)
3435
InherentImpls.find(target.item)
36+
else if (target is RustPrimitiveType)
37+
InherentImpls.find(target, project);
3538
else
3639
emptySequence()
3740

@@ -98,6 +101,22 @@ object RsImplIndex {
98101
}
99102
}
100103

104+
fun find(target: RustPrimitiveType, project: Project): Sequence<RsImplItem> {
105+
val fingerprint = RustTypeFingerprint.create(target)
106+
?: return emptySequence()
107+
108+
return StubIndex.getElements(
109+
InherentImpls.KEY,
110+
fingerprint,
111+
project,
112+
GlobalSearchScope.allScope(project),
113+
RsImplItem::class.java
114+
).asSequence().filter { impl ->
115+
val ty = impl.typeReference?.type
116+
ty is RustPrimitiveType && ty == target
117+
}
118+
}
119+
101120
fun index(stub: RsImplItemStub, sink: IndexSink) {
102121
val type = stub.psi.typeReference ?: return
103122
val key = RustTypeFingerprint.create(type)

src/main/kotlin/org/rust/lang/core/types/RustTypeFingerprint.kt

+2-3
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,7 @@ package org.rust.lang.core.types
33
import org.rust.lang.core.psi.RsBaseType
44
import org.rust.lang.core.psi.RsRefLikeType
55
import org.rust.lang.core.psi.RsTypeReference
6-
import org.rust.lang.core.types.types.RustEnumType
7-
import org.rust.lang.core.types.types.RustReferenceType
8-
import org.rust.lang.core.types.types.RustStructType
6+
import org.rust.lang.core.types.types.*
97
import java.io.DataInput
108
import java.io.DataOutput
119

@@ -23,6 +21,7 @@ data class RustTypeFingerprint private constructor(
2321
is RustStructType -> type.item.name?.let(::RustTypeFingerprint)
2422
is RustEnumType -> type.item.name?.let(::RustTypeFingerprint)
2523
is RustReferenceType -> create(type.referenced)
24+
is RustPrimitiveType -> type.toString().let(::RustTypeFingerprint)
2625
else -> null
2726
}
2827
}

src/test/kotlin/org/rust/lang/core/resolve/RsStdlibResolveTest.kt

+64
Original file line numberDiff line numberDiff line change
@@ -136,4 +136,68 @@ class RsStdlibResolveTest : RsResolveTestBase() {
136136
fn main() { use self::m::Some; }
137137
//^ unresolved
138138
""")
139+
140+
fun testChar() = stubOnlyResolve("""
141+
//- main.rs
142+
fn main() { 'Z'.is_lowercase(); }
143+
//^ ...libstd_unicode/char.rs
144+
""")
145+
146+
fun testCharUFCS() = expect<IllegalStateException> { stubOnlyResolve ("""
147+
//- main.rs
148+
fn main() { char.is_lowercase('Z'); }
149+
//^ ...libstd_unicode/char.rs
150+
""")
151+
}
152+
153+
fun testStr() = stubOnlyResolve("""
154+
//- main.rs
155+
fn main() { "Z".to_uppercase(); }
156+
//^ ...libcollections/str.rs
157+
""")
158+
159+
fun testStrUFCS() = expect<IllegalStateException> { stubOnlyResolve ("""
160+
//- main.rs
161+
fn main() { str::to_uppercase("Z"); }
162+
//^ ...libcollections/str.rs
163+
""")
164+
}
165+
166+
fun testF32() = stubOnlyResolve("""
167+
//- main.rs
168+
fn main() { 0.0f32.sqrt(); }
169+
//^ ...libstd/f32.rs
170+
""")
171+
172+
fun testF32UFCS() = expect<IllegalStateException> { stubOnlyResolve ("""
173+
//- main.rs
174+
fn main() { f32::sqrt(0.0f32); }
175+
//^ ...libstd/f32.rs
176+
""")
177+
}
178+
179+
fun testF32UFCS2() = expect<IllegalStateException> { stubOnlyResolve ("""
180+
//- main.rs
181+
fn main() { <f32>::sqrt(0.0f32); }
182+
//^ ...libstd/f32.rs
183+
""")
184+
}
185+
186+
fun testF64() = stubOnlyResolve("""
187+
//- main.rs
188+
fn main() { 0.0f64.sqrt(); }
189+
//^ ...libstd/f64.rs
190+
""")
191+
192+
fun testF64UFCS() = expect<IllegalStateException> { stubOnlyResolve ("""
193+
//- main.rs
194+
fn main() { f64::sqrt(0.0f64); }
195+
//^ ...libstd/f64.rs
196+
""")
197+
}
198+
199+
//TODO add tests for:
200+
// slice, const_ptr, mut_ptr
201+
// u8, u16, u32, u64, u128, usize
202+
// i8, i16, i32, i64, i128, isize
139203
}

0 commit comments

Comments
 (0)