Skip to content

Commit

Permalink
T: Initial type inference for const generics
Browse files Browse the repository at this point in the history
  • Loading branch information
mchernyavsky committed Mar 10, 2020
1 parent 1fb5dd4 commit 7c168be
Show file tree
Hide file tree
Showing 6 changed files with 457 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,15 @@ class SpecifyTypeExplicitlyIntentionTest : RsIntentionTestBase(SpecifyTypeExplic
)

fun `test generic type`() = doAvailableTest(
"""struct A<T>(T);fn main() { let var/*caret*/ = A(42); } """,
"""struct A<T>(T);fn main() { let var: A<i32> = A(42); } """
"""struct A<T>(T); fn main() { let var/*caret*/ = A(42); } """,
"""struct A<T>(T); fn main() { let var: A<i32> = A(42); } """
)

fun `test type with const generic`() = doAvailableTest(
"""struct A<const N: usize>; fn main() { let var/*caret*/ = A::<1>; } """,
"""struct A<const N: usize>; fn main() { let var: A<1> = A::<1>; } """
)

fun `test complex pattern`() = doAvailableTest(
""" fn main() { let (a, b)/*caret*/ = (1, 2); } """,
""" fn main() { let (a, b): (i32, i32) = (1, 2); } """
Expand Down Expand Up @@ -52,7 +58,11 @@ class SpecifyTypeExplicitlyIntentionTest : RsIntentionTestBase(SpecifyTypeExplic
)

fun `test generic type with not inferred type`() = doUnavailableTest(
"""struct A<T>(T);fn main() { let var/*caret*/ = A(a); } """
"""struct A<T>(T); fn main() { let var/*caret*/ = A(a); } """
)

fun `test generic type with not inferred const generic`() = doUnavailableTest(
"""struct A<const N: usize>; fn main() { let var/*caret*/ = A; } """
)

fun `test anon type`() = doUnavailableTest("""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -561,6 +561,104 @@ class ImplementMembersHandlerTest : RsTestBase() {
}
""")

fun `test implement generic trait with consts 1`() = doTest("""
struct S<const N: usize>;
trait T<const M: usize> {
fn f1(_: S<{ M }>) -> S<{ M }>;
const C1: S<{ M }>;
fn f2(_: S<{ UNKNOWN }>) -> S<{ UNKNOWN }>;
const C2: S<{ UNKNOWN }>;
fn f3(_: [i32; M]) -> [i32; M];
const C3: [i32; M];
fn f4(_: [i32; UNKNOWN]) -> [i32; UNKNOWN];
const C4: [i32; UNKNOWN];
}
impl T<1> for S<1> {/*caret*/}
""", listOf(
ImplementMemberSelection("f1(_: S<{ M }>) -> S<{ M }>", true),
ImplementMemberSelection("C1: S<{ M }>", true),
ImplementMemberSelection("f2(_: S<{ UNKNOWN }>) -> S<{ UNKNOWN }>", true),
ImplementMemberSelection("C2: S<{ UNKNOWN }>", true),
ImplementMemberSelection("f3(_: [i32; M]) -> [i32; M]", true),
ImplementMemberSelection("C3: [i32; M]", true),
ImplementMemberSelection("f4(_: [i32; UNKNOWN]) -> [i32; UNKNOWN]", true),
ImplementMemberSelection("C4: [i32; UNKNOWN]", true)
), """
struct S<const N: usize>;
trait T<const M: usize> {
fn f1(_: S<{ M }>) -> S<{ M }>;
const C1: S<{ M }>;
fn f2(_: S<{ UNKNOWN }>) -> S<{ UNKNOWN }>;
const C2: S<{ UNKNOWN }>;
fn f3(_: [i32; M]) -> [i32; M];
const C3: [i32; M];
fn f4(_: [i32; UNKNOWN]) -> [i32; UNKNOWN];
const C4: [i32; UNKNOWN];
}
impl T<1> for S<1> {
fn f1(_: S<1>) -> S<1> {
unimplemented!()
}
const C1: S<1> = S;
fn f2(_: S<{}>) -> S<{}> {
unimplemented!()
}
const C2: S<{}> = S;
fn f3(_: [i32; 1]) -> [i32; 1] {
unimplemented!()
}
const C3: [i32; 1] = [];
fn f4(_: [i32; {}]) -> [i32; {}] {
unimplemented!()
}
const C4: [i32; {}] = [];
}
""")

fun `test implement generic trait with consts 2`() = doTest("""
struct S<const N: usize>;
trait T<const M: usize> {
fn f1(_: S<{ M }>) -> S<{ M }>;
const C1: S<{ M }>;
fn f2(_: [i32; M]) -> [i32; M];
const C2: [i32; M];
}
impl <const K: usize> T<{ K }> for S<{ K }> {/*caret*/}
""", listOf(
ImplementMemberSelection("f1(_: S<{ M }>) -> S<{ M }>", true),
ImplementMemberSelection("C1: S<{ M }>", true),
ImplementMemberSelection("f2(_: [i32; M]) -> [i32; M]", true),
ImplementMemberSelection("C2: [i32; M]", true)
), """
struct S<const N: usize>;
trait T<const M: usize> {
fn f1(_: S<{ M }>) -> S<{ M }>;
const C1: S<{ M }>;
fn f2(_: [i32; M]) -> [i32; M];
const C2: [i32; M];
}
impl <const K: usize> T<{ K }> for S<{ K }> {
fn f1(_: S<{ K }>) -> S<{ K }> {
unimplemented!()
}
const C1: S<{ K }> = S;
fn f2(_: [i32; K]) -> [i32; K] {
unimplemented!()
}
const C2: [i32; K] = [];
}
""")

fun `test do not implement methods already present`() = doTest("""
trait T {
fn f1();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,23 @@ class RsLookupElementTest : RsTestBase() {
}
""", tailText = "(x: i32) of T<i32>", typeText = "i32")

fun `test const generic function`() = checkProvider("""
struct S<const N: usize>(i32);
trait T<const M: usize> {
fn foo();
}
impl <const K: usize> T<{ K }> for S<{ K }> {
fn foo() {}
}
fn main() {
S::<1>::foo;
//^
}
""", tailText = "() of T<1>", typeText = "()")

private fun check(
@Language("Rust") code: String,
tailText: String? = null,
Expand Down
12 changes: 12 additions & 0 deletions src/test/kotlin/org/rust/lang/core/resolve/RsResolveCacheTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,18 @@ class RsResolveCacheTest : RsTestBase() {
//^
""", "\b2")

fun `test edit const expr`() = checkResolvedToXY("""
struct S<const N: usize>;
fn foo<
const N1: usize,
//X
const N2: usize
//Y
>() {
let _: S<{ N1/*caret*/ }>;
} //^
""", "\b2")

private fun checkResolvedToXY(@Language("Rust") code: String, textToType: String) {
InlineFile(code).withCaret()

Expand Down
132 changes: 132 additions & 0 deletions src/test/kotlin/org/rust/lang/core/resolve/RsStubOnlyResolveTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -581,4 +581,136 @@ class RsStubOnlyResolveTest : RsResolveTestBase() {
}
}
""")

fun `test trait impl for const generic 1`() = stubOnlyResolve("""
//- main.rs
#![feature(const_generics)]
mod bar;
use bar::T;
fn main() {
let s = [0];
s.foo()
//^ bar.rs
}
//- bar.rs
pub trait T {
fn foo(&self);
}
impl T for [i32; 1] {
fn foo(&self) {}
}
""")

fun `test trait impl for const generic 2`() = stubOnlyResolve("""
//- main.rs
#![feature(const_generics)]
mod bar;
use bar::T;
fn main() {
let s = [0, 1];
s.foo()
//^ unresolved
}
//- bar.rs
pub trait T {
fn foo(&self);
}
impl T for [i32; 1] {
fn foo(&self) {}
}
""")

fun `test trait impl for const generic 3`() = stubOnlyResolve("""
//- main.rs
#![feature(const_generics)]
mod bar;
use bar::T;
fn main() {
let s = [0];
s.foo()
//^ bar.rs
}
//- bar.rs
pub trait T {
fn foo(&self);
}
impl <const N: usize> T for [i32; N] {
fn foo(&self) {}
}
""")

fun `test trait impl const generic 4`() = stubOnlyResolve("""
//- main.rs
#![feature(const_generics)]
mod bar;
use bar::T;
fn main() {
let s = bar::S::<0>;
s.foo()
//^ bar.rs
}
//- bar.rs
pub struct S<const N: usize>;
pub trait T {
fn foo(&self);
}
impl T for S<{ 0 }> {
fn foo(&self) {}
}
""")

fun `test trait impl const generic 5`() = stubOnlyResolve("""
//- main.rs
#![feature(const_generics)]
mod bar;
use bar::T;
fn main() {
let s = bar::S::<1>;
s.foo()
//^ unresolved
}
//- bar.rs
pub struct S<const N: usize>;
pub trait T {
fn foo(&self);
}
impl T for S<{ 0 }> {
fn foo(&self) {}
}
""")

fun `test trait impl const generic 6`() = stubOnlyResolve("""
//- main.rs
#![feature(const_generics)]
mod bar;
use bar::T;
fn main() {
let s = bar::S::<0>;
s.foo()
//^ bar.rs
}
//- bar.rs
pub struct S<const N: usize>;
pub trait T {
fn foo(&self);
}
impl <const N: usize> T for S<{ N }> {
fn foo(&self) {}
}
""")
}

0 comments on commit 7c168be

Please sign in to comment.