2020-07-04 10:03:27 +02:00
|
|
|
//! Completes references after dot (fields and method calls).
|
2019-09-30 11:58:53 +03:00
|
|
|
|
2022-04-25 18:51:59 +02:00
|
|
|
use ide_db::FxHashSet;
|
2019-01-08 22:33:36 +03:00
|
|
|
|
2022-05-06 12:04:41 +02:00
|
|
|
use crate::{
|
2022-06-20 14:23:46 +02:00
|
|
|
context::{CompletionContext, DotAccess, DotAccessKind, ExprCtx, PathCompletionCtx, Qualified},
|
2022-05-23 17:40:41 +02:00
|
|
|
CompletionItem, CompletionItemKind, Completions,
|
2022-05-06 12:04:41 +02:00
|
|
|
};
|
2019-01-08 22:33:36 +03:00
|
|
|
|
2020-07-04 10:36:12 +02:00
|
|
|
/// Complete dot accesses, i.e. fields or methods.
|
2022-06-17 23:36:39 +02:00
|
|
|
pub(crate) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext, dot_access: &DotAccess) {
|
|
|
|
let receiver_ty = match dot_access {
|
|
|
|
DotAccess { receiver_ty: Some(receiver_ty), .. } => &receiver_ty.original,
|
|
|
|
_ => return,
|
2019-08-04 08:03:17 +07:00
|
|
|
};
|
2019-08-03 01:15:43 +07:00
|
|
|
|
2022-05-23 17:40:41 +02:00
|
|
|
// Suggest .await syntax for types that implement Future trait
|
|
|
|
if receiver_ty.impls_future(ctx.db) {
|
|
|
|
let mut item =
|
|
|
|
CompletionItem::new(CompletionItemKind::Keyword, ctx.source_range(), "await");
|
|
|
|
item.detail("expr.await");
|
|
|
|
item.add_to(acc);
|
|
|
|
}
|
2019-08-03 01:15:43 +07:00
|
|
|
|
2022-05-23 17:40:41 +02:00
|
|
|
if let DotAccessKind::Method { .. } = dot_access.kind {
|
2021-03-08 22:19:44 +02:00
|
|
|
cov_mark::hit!(test_no_struct_field_completion_for_method_call);
|
2020-07-04 10:36:12 +02:00
|
|
|
} else {
|
2022-04-25 18:40:38 +02:00
|
|
|
complete_fields(
|
|
|
|
acc,
|
|
|
|
ctx,
|
|
|
|
&receiver_ty,
|
2022-06-20 20:22:51 +02:00
|
|
|
|acc, field, ty| acc.add_field(ctx, dot_access, None, field, &ty),
|
2022-04-25 18:40:38 +02:00
|
|
|
|acc, field, ty| acc.add_tuple_field(ctx, None, field, &ty),
|
|
|
|
);
|
2020-01-14 14:42:52 +01:00
|
|
|
}
|
2022-06-20 17:41:04 +02:00
|
|
|
complete_methods(ctx, &receiver_ty, |func| acc.add_method(ctx, dot_access, func, None, None));
|
2021-05-28 15:09:10 +02:00
|
|
|
}
|
|
|
|
|
2022-06-17 23:36:39 +02:00
|
|
|
pub(crate) fn complete_undotted_self(
|
|
|
|
acc: &mut Completions,
|
|
|
|
ctx: &CompletionContext,
|
|
|
|
path_ctx: &PathCompletionCtx,
|
2022-06-20 14:23:46 +02:00
|
|
|
expr_ctx: &ExprCtx,
|
2022-06-17 23:36:39 +02:00
|
|
|
) {
|
2021-06-02 15:21:18 +02:00
|
|
|
if !ctx.config.enable_self_on_the_fly {
|
|
|
|
return;
|
|
|
|
}
|
2022-06-20 14:23:46 +02:00
|
|
|
if !path_ctx.is_trivial_path() {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if !ctx.qualifier_ctx.none() {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if !matches!(path_ctx.qualified, Qualified::No) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
let self_param = match expr_ctx {
|
|
|
|
ExprCtx { self_param: Some(self_param), .. } => self_param,
|
2022-05-06 12:04:41 +02:00
|
|
|
_ => return,
|
2022-06-18 09:54:03 +02:00
|
|
|
};
|
2022-05-06 12:04:41 +02:00
|
|
|
|
2022-06-18 09:54:03 +02:00
|
|
|
let ty = self_param.ty(ctx.db);
|
|
|
|
complete_fields(
|
|
|
|
acc,
|
|
|
|
ctx,
|
|
|
|
&ty,
|
2022-06-20 20:22:51 +02:00
|
|
|
|acc, field, ty| {
|
|
|
|
acc.add_field(
|
|
|
|
ctx,
|
|
|
|
&DotAccess {
|
|
|
|
receiver: None,
|
|
|
|
receiver_ty: None,
|
|
|
|
kind: DotAccessKind::Field { receiver_is_ambiguous_float_literal: false },
|
|
|
|
},
|
|
|
|
Some(hir::known::SELF_PARAM),
|
|
|
|
field,
|
|
|
|
&ty,
|
|
|
|
)
|
|
|
|
},
|
2022-06-18 09:54:03 +02:00
|
|
|
|acc, field, ty| acc.add_tuple_field(ctx, Some(hir::known::SELF_PARAM), field, &ty),
|
|
|
|
);
|
|
|
|
complete_methods(ctx, &ty, |func| {
|
2022-06-20 17:41:04 +02:00
|
|
|
acc.add_method(
|
|
|
|
ctx,
|
|
|
|
&DotAccess {
|
|
|
|
receiver: None,
|
|
|
|
receiver_ty: None,
|
|
|
|
kind: DotAccessKind::Method { has_parens: false },
|
|
|
|
},
|
|
|
|
func,
|
|
|
|
Some(hir::known::SELF_PARAM),
|
|
|
|
None,
|
|
|
|
)
|
2022-06-18 09:54:03 +02:00
|
|
|
});
|
2021-05-28 15:09:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
fn complete_fields(
|
2022-04-25 18:40:38 +02:00
|
|
|
acc: &mut Completions,
|
2021-05-28 15:09:10 +02:00
|
|
|
ctx: &CompletionContext,
|
|
|
|
receiver: &hir::Type,
|
2022-04-25 18:40:38 +02:00
|
|
|
mut named_field: impl FnMut(&mut Completions, hir::Field, hir::Type),
|
|
|
|
mut tuple_index: impl FnMut(&mut Completions, usize, hir::Type),
|
2021-05-28 15:09:10 +02:00
|
|
|
) {
|
|
|
|
for receiver in receiver.autoderef(ctx.db) {
|
|
|
|
for (field, ty) in receiver.fields(ctx.db) {
|
2022-04-25 18:40:38 +02:00
|
|
|
named_field(acc, field, ty);
|
2021-05-28 15:09:10 +02:00
|
|
|
}
|
|
|
|
for (i, ty) in receiver.tuple_fields(ctx.db).into_iter().enumerate() {
|
2021-07-23 20:20:41 +02:00
|
|
|
// Tuple fields are always public (tuple struct fields are handled above).
|
2022-04-25 18:40:38 +02:00
|
|
|
tuple_index(acc, i, ty);
|
2021-05-28 15:09:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn complete_methods(
|
|
|
|
ctx: &CompletionContext,
|
|
|
|
receiver: &hir::Type,
|
|
|
|
mut f: impl FnMut(hir::Function),
|
|
|
|
) {
|
Refactor autoderef and method resolution
- don't return the receiver type from method resolution; instead just
return the autorefs/autoderefs that happened and repeat them. This
ensures all the effects like trait obligations and whatever we learned
about type variables from derefing them are actually applied. Also, it
allows us to get rid of `decanonicalize_ty`, which was just wrong in
principle.
- Autoderef itself now directly works with an inference table. Sadly
this has the effect of making it harder to use as an iterator, often
requiring manual `while let` loops. (rustc works around this by using
inner mutability in the inference context, so that things like unifying
types don't require a unique reference.)
- We now record the adjustments (autoref/deref) for method receivers
and index expressions, which we didn't before.
- Removed the redundant crate parameter from method resolution, since
the trait_env contains the crate as well.
- in the HIR API, the methods now take a scope to determine the trait env.
`Type` carries a trait env, but I think that's probably a bad decision
because it's easy to create it with the wrong env, e.g. by using
`Adt::ty`. This mostly didn't matter so far because
`iterate_method_candidates` took a crate parameter and ignored
`self.krate`, but the trait env would still have been wrong in those
cases, which I think would give some wrong results in some edge cases.
Fixes #10058.
2022-02-16 17:44:03 +01:00
|
|
|
let mut seen_methods = FxHashSet::default();
|
|
|
|
receiver.iterate_method_candidates(
|
|
|
|
ctx.db,
|
|
|
|
&ctx.scope,
|
2022-06-20 21:55:33 +02:00
|
|
|
&ctx.traits_in_scope(),
|
2022-03-31 11:12:08 +02:00
|
|
|
Some(ctx.module),
|
Refactor autoderef and method resolution
- don't return the receiver type from method resolution; instead just
return the autorefs/autoderefs that happened and repeat them. This
ensures all the effects like trait obligations and whatever we learned
about type variables from derefing them are actually applied. Also, it
allows us to get rid of `decanonicalize_ty`, which was just wrong in
principle.
- Autoderef itself now directly works with an inference table. Sadly
this has the effect of making it harder to use as an iterator, often
requiring manual `while let` loops. (rustc works around this by using
inner mutability in the inference context, so that things like unifying
types don't require a unique reference.)
- We now record the adjustments (autoref/deref) for method receivers
and index expressions, which we didn't before.
- Removed the redundant crate parameter from method resolution, since
the trait_env contains the crate as well.
- in the HIR API, the methods now take a scope to determine the trait env.
`Type` carries a trait env, but I think that's probably a bad decision
because it's easy to create it with the wrong env, e.g. by using
`Adt::ty`. This mostly didn't matter so far because
`iterate_method_candidates` took a crate parameter and ignored
`self.krate`, but the trait env would still have been wrong in those
cases, which I think would give some wrong results in some edge cases.
Fixes #10058.
2022-02-16 17:44:03 +01:00
|
|
|
None,
|
|
|
|
|func| {
|
|
|
|
if func.self_param(ctx.db).is_some() && seen_methods.insert(func.name(ctx.db)) {
|
|
|
|
f(func);
|
|
|
|
}
|
|
|
|
None::<()>
|
|
|
|
},
|
|
|
|
);
|
2019-01-07 19:12:19 +01:00
|
|
|
}
|
|
|
|
|
2019-01-08 22:33:36 +03:00
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
2020-08-21 13:19:31 +02:00
|
|
|
use expect_test::{expect, Expect};
|
2020-07-04 10:36:12 +02:00
|
|
|
|
2022-06-16 08:52:57 +08:00
|
|
|
use crate::tests::{
|
|
|
|
check_edit, completion_list_no_kw, completion_list_no_kw_with_private_editable,
|
|
|
|
};
|
2019-01-08 22:33:36 +03:00
|
|
|
|
2020-07-04 10:36:12 +02:00
|
|
|
fn check(ra_fixture: &str, expect: Expect) {
|
2021-10-27 16:24:42 +02:00
|
|
|
let actual = completion_list_no_kw(ra_fixture);
|
2020-07-04 10:36:12 +02:00
|
|
|
expect.assert_eq(&actual);
|
2019-01-08 22:33:36 +03:00
|
|
|
}
|
|
|
|
|
2022-06-16 08:52:57 +08:00
|
|
|
fn check_with_private_editable(ra_fixture: &str, expect: Expect) {
|
|
|
|
let actual = completion_list_no_kw_with_private_editable(ra_fixture);
|
|
|
|
expect.assert_eq(&actual);
|
|
|
|
}
|
|
|
|
|
2019-01-08 22:33:36 +03:00
|
|
|
#[test]
|
2020-07-04 10:36:12 +02:00
|
|
|
fn test_struct_field_and_method_completion() {
|
|
|
|
check(
|
|
|
|
r#"
|
|
|
|
struct S { foo: u32 }
|
|
|
|
impl S {
|
|
|
|
fn bar(&self) {}
|
|
|
|
}
|
2021-01-06 20:15:48 +00:00
|
|
|
fn foo(s: S) { s.$0 }
|
2020-07-04 10:36:12 +02:00
|
|
|
"#,
|
|
|
|
expect![[r#"
|
2020-07-04 19:03:58 +02:00
|
|
|
fd foo u32
|
2021-03-06 16:56:07 -08:00
|
|
|
me bar() fn(&self)
|
2020-07-04 10:36:12 +02:00
|
|
|
"#]],
|
2019-01-08 22:33:36 +03:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_struct_field_completion_self() {
|
2020-07-04 10:36:12 +02:00
|
|
|
check(
|
|
|
|
r#"
|
|
|
|
struct S { the_field: (u32,) }
|
|
|
|
impl S {
|
2021-01-06 20:15:48 +00:00
|
|
|
fn foo(self) { self.$0 }
|
2020-07-04 10:36:12 +02:00
|
|
|
}
|
|
|
|
"#,
|
|
|
|
expect![[r#"
|
|
|
|
fd the_field (u32,)
|
2021-03-06 16:56:07 -08:00
|
|
|
me foo() fn(self)
|
2020-07-04 10:36:12 +02:00
|
|
|
"#]],
|
|
|
|
)
|
2019-01-08 22:33:36 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_struct_field_completion_autoderef() {
|
2020-07-04 10:36:12 +02:00
|
|
|
check(
|
|
|
|
r#"
|
|
|
|
struct A { the_field: (u32, i32) }
|
|
|
|
impl A {
|
2021-01-06 20:15:48 +00:00
|
|
|
fn foo(&self) { self.$0 }
|
2020-07-04 10:36:12 +02:00
|
|
|
}
|
|
|
|
"#,
|
|
|
|
expect![[r#"
|
|
|
|
fd the_field (u32, i32)
|
2021-03-06 16:56:07 -08:00
|
|
|
me foo() fn(&self)
|
2020-07-04 10:36:12 +02:00
|
|
|
"#]],
|
|
|
|
)
|
2019-01-08 22:33:36 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_no_struct_field_completion_for_method_call() {
|
2021-03-08 22:19:44 +02:00
|
|
|
cov_mark::check!(test_no_struct_field_completion_for_method_call);
|
2020-07-04 10:36:12 +02:00
|
|
|
check(
|
|
|
|
r#"
|
|
|
|
struct A { the_field: u32 }
|
2021-01-06 20:15:48 +00:00
|
|
|
fn foo(a: A) { a.$0() }
|
2020-07-04 10:36:12 +02:00
|
|
|
"#,
|
2021-10-27 17:18:42 +02:00
|
|
|
expect![[r#""#]],
|
2019-01-08 22:33:36 +03:00
|
|
|
);
|
|
|
|
}
|
2019-01-07 19:12:19 +01:00
|
|
|
|
2019-12-24 21:46:07 +01:00
|
|
|
#[test]
|
2020-07-04 10:36:12 +02:00
|
|
|
fn test_visibility_filtering() {
|
|
|
|
check(
|
|
|
|
r#"
|
2021-07-23 19:57:16 +02:00
|
|
|
//- /lib.rs crate:lib new_source_root:local
|
|
|
|
pub mod m {
|
2020-07-04 10:36:12 +02:00
|
|
|
pub struct A {
|
|
|
|
private_field: u32,
|
|
|
|
pub pub_field: u32,
|
|
|
|
pub(crate) crate_field: u32,
|
2021-07-23 19:57:16 +02:00
|
|
|
pub(super) super_field: u32,
|
2020-04-28 22:45:46 +02:00
|
|
|
}
|
2020-07-04 10:36:12 +02:00
|
|
|
}
|
2021-07-23 19:57:16 +02:00
|
|
|
//- /main.rs crate:main deps:lib new_source_root:local
|
|
|
|
fn foo(a: lib::m::A) { a.$0 }
|
2022-06-16 08:52:57 +08:00
|
|
|
"#,
|
|
|
|
expect![[r#"
|
|
|
|
fd pub_field u32
|
|
|
|
"#]],
|
|
|
|
);
|
|
|
|
|
|
|
|
check(
|
|
|
|
r#"
|
|
|
|
//- /lib.rs crate:lib new_source_root:library
|
|
|
|
pub mod m {
|
|
|
|
pub struct A {
|
|
|
|
private_field: u32,
|
|
|
|
pub pub_field: u32,
|
|
|
|
pub(crate) crate_field: u32,
|
|
|
|
pub(super) super_field: u32,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//- /main.rs crate:main deps:lib new_source_root:local
|
|
|
|
fn foo(a: lib::m::A) { a.$0 }
|
|
|
|
"#,
|
|
|
|
expect![[r#"
|
|
|
|
fd pub_field u32
|
|
|
|
"#]],
|
|
|
|
);
|
|
|
|
|
|
|
|
check(
|
|
|
|
r#"
|
|
|
|
//- /lib.rs crate:lib new_source_root:library
|
|
|
|
pub mod m {
|
|
|
|
pub struct A(
|
|
|
|
i32,
|
|
|
|
pub f64,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
//- /main.rs crate:main deps:lib new_source_root:local
|
|
|
|
fn foo(a: lib::m::A) { a.$0 }
|
|
|
|
"#,
|
|
|
|
expect![[r#"
|
|
|
|
fd 1 f64
|
|
|
|
"#]],
|
|
|
|
);
|
|
|
|
|
|
|
|
check(
|
|
|
|
r#"
|
|
|
|
//- /lib.rs crate:lib new_source_root:local
|
|
|
|
pub struct A {}
|
|
|
|
mod m {
|
|
|
|
impl super::A {
|
|
|
|
fn private_method(&self) {}
|
|
|
|
pub(crate) fn crate_method(&self) {}
|
|
|
|
pub fn pub_method(&self) {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//- /main.rs crate:main deps:lib new_source_root:local
|
|
|
|
fn foo(a: lib::A) { a.$0 }
|
|
|
|
"#,
|
|
|
|
expect![[r#"
|
|
|
|
me pub_method() fn(&self)
|
|
|
|
"#]],
|
|
|
|
);
|
|
|
|
check(
|
|
|
|
r#"
|
|
|
|
//- /lib.rs crate:lib new_source_root:library
|
|
|
|
pub struct A {}
|
|
|
|
mod m {
|
|
|
|
impl super::A {
|
|
|
|
fn private_method(&self) {}
|
|
|
|
pub(crate) fn crate_method(&self) {}
|
|
|
|
pub fn pub_method(&self) {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//- /main.rs crate:main deps:lib new_source_root:local
|
|
|
|
fn foo(a: lib::A) { a.$0 }
|
|
|
|
"#,
|
|
|
|
expect![[r#"
|
|
|
|
me pub_method() fn(&self)
|
|
|
|
"#]],
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_visibility_filtering_with_private_editable_enabled() {
|
|
|
|
check_with_private_editable(
|
|
|
|
r#"
|
|
|
|
//- /lib.rs crate:lib new_source_root:local
|
|
|
|
pub mod m {
|
|
|
|
pub struct A {
|
|
|
|
private_field: u32,
|
|
|
|
pub pub_field: u32,
|
|
|
|
pub(crate) crate_field: u32,
|
|
|
|
pub(super) super_field: u32,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//- /main.rs crate:main deps:lib new_source_root:local
|
|
|
|
fn foo(a: lib::m::A) { a.$0 }
|
2020-07-04 10:36:12 +02:00
|
|
|
"#,
|
|
|
|
expect![[r#"
|
2022-05-05 10:49:43 +02:00
|
|
|
fd crate_field u32
|
2021-07-23 19:57:16 +02:00
|
|
|
fd private_field u32
|
|
|
|
fd pub_field u32
|
|
|
|
fd super_field u32
|
2020-07-04 10:36:12 +02:00
|
|
|
"#]],
|
2019-12-24 21:46:07 +01:00
|
|
|
);
|
|
|
|
|
2022-06-16 08:52:57 +08:00
|
|
|
check_with_private_editable(
|
2020-07-04 10:36:12 +02:00
|
|
|
r#"
|
2021-07-23 19:57:16 +02:00
|
|
|
//- /lib.rs crate:lib new_source_root:library
|
|
|
|
pub mod m {
|
|
|
|
pub struct A {
|
|
|
|
private_field: u32,
|
|
|
|
pub pub_field: u32,
|
|
|
|
pub(crate) crate_field: u32,
|
|
|
|
pub(super) super_field: u32,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//- /main.rs crate:main deps:lib new_source_root:local
|
|
|
|
fn foo(a: lib::m::A) { a.$0 }
|
|
|
|
"#,
|
|
|
|
expect![[r#"
|
|
|
|
fd pub_field u32
|
|
|
|
"#]],
|
|
|
|
);
|
|
|
|
|
2022-06-16 08:52:57 +08:00
|
|
|
check_with_private_editable(
|
2021-07-23 20:20:23 +02:00
|
|
|
r#"
|
|
|
|
//- /lib.rs crate:lib new_source_root:library
|
|
|
|
pub mod m {
|
|
|
|
pub struct A(
|
|
|
|
i32,
|
|
|
|
pub f64,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
//- /main.rs crate:main deps:lib new_source_root:local
|
|
|
|
fn foo(a: lib::m::A) { a.$0 }
|
|
|
|
"#,
|
|
|
|
expect![[r#"
|
2021-10-27 17:18:42 +02:00
|
|
|
fd 1 f64
|
2021-07-23 20:20:23 +02:00
|
|
|
"#]],
|
|
|
|
);
|
|
|
|
|
2022-06-16 08:52:57 +08:00
|
|
|
check_with_private_editable(
|
2021-07-23 19:57:16 +02:00
|
|
|
r#"
|
|
|
|
//- /lib.rs crate:lib new_source_root:local
|
|
|
|
pub struct A {}
|
2020-07-04 10:36:12 +02:00
|
|
|
mod m {
|
|
|
|
impl super::A {
|
|
|
|
fn private_method(&self) {}
|
2021-07-23 19:57:16 +02:00
|
|
|
pub(crate) fn crate_method(&self) {}
|
|
|
|
pub fn pub_method(&self) {}
|
2020-07-04 10:36:12 +02:00
|
|
|
}
|
|
|
|
}
|
2021-07-23 19:57:16 +02:00
|
|
|
//- /main.rs crate:main deps:lib new_source_root:local
|
|
|
|
fn foo(a: lib::A) { a.$0 }
|
2020-07-04 10:36:12 +02:00
|
|
|
"#,
|
|
|
|
expect![[r#"
|
2021-07-23 19:57:16 +02:00
|
|
|
me crate_method() fn(&self)
|
2022-05-05 10:49:43 +02:00
|
|
|
me private_method() fn(&self)
|
2021-07-23 19:57:16 +02:00
|
|
|
me pub_method() fn(&self)
|
|
|
|
"#]],
|
|
|
|
);
|
2022-06-16 08:52:57 +08:00
|
|
|
check_with_private_editable(
|
2021-07-23 19:57:16 +02:00
|
|
|
r#"
|
|
|
|
//- /lib.rs crate:lib new_source_root:library
|
|
|
|
pub struct A {}
|
|
|
|
mod m {
|
|
|
|
impl super::A {
|
|
|
|
fn private_method(&self) {}
|
|
|
|
pub(crate) fn crate_method(&self) {}
|
|
|
|
pub fn pub_method(&self) {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//- /main.rs crate:main deps:lib new_source_root:local
|
|
|
|
fn foo(a: lib::A) { a.$0 }
|
|
|
|
"#,
|
|
|
|
expect![[r#"
|
|
|
|
me pub_method() fn(&self)
|
2020-07-04 10:36:12 +02:00
|
|
|
"#]],
|
2019-01-07 19:12:19 +01:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2022-02-01 23:29:40 +01:00
|
|
|
#[test]
|
|
|
|
fn test_local_impls() {
|
|
|
|
check(
|
|
|
|
r#"
|
|
|
|
//- /lib.rs crate:lib
|
|
|
|
pub struct A {}
|
|
|
|
mod m {
|
|
|
|
impl super::A {
|
|
|
|
pub fn pub_module_method(&self) {}
|
|
|
|
}
|
|
|
|
fn f() {
|
|
|
|
impl super::A {
|
|
|
|
pub fn pub_foreign_local_method(&self) {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//- /main.rs crate:main deps:lib
|
|
|
|
fn foo(a: lib::A) {
|
|
|
|
impl lib::A {
|
|
|
|
fn local_method(&self) {}
|
|
|
|
}
|
|
|
|
a.$0
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
expect![[r#"
|
|
|
|
me local_method() fn(&self)
|
|
|
|
me pub_module_method() fn(&self)
|
|
|
|
"#]],
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2021-07-23 15:36:43 +02:00
|
|
|
#[test]
|
|
|
|
fn test_doc_hidden_filtering() {
|
|
|
|
check(
|
|
|
|
r#"
|
|
|
|
//- /lib.rs crate:lib deps:dep
|
|
|
|
fn foo(a: dep::A) { a.$0 }
|
|
|
|
//- /dep.rs crate:dep
|
|
|
|
pub struct A {
|
|
|
|
#[doc(hidden)]
|
|
|
|
pub hidden_field: u32,
|
|
|
|
pub pub_field: u32,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl A {
|
|
|
|
pub fn pub_method(&self) {}
|
|
|
|
|
|
|
|
#[doc(hidden)]
|
|
|
|
pub fn hidden_method(&self) {}
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
expect![[r#"
|
|
|
|
fd pub_field u32
|
|
|
|
me pub_method() fn(&self)
|
2021-07-23 16:45:14 +02:00
|
|
|
"#]],
|
2021-07-23 15:36:43 +02:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2019-12-02 19:27:31 +01:00
|
|
|
#[test]
|
2020-07-04 10:36:12 +02:00
|
|
|
fn test_union_field_completion() {
|
|
|
|
check(
|
|
|
|
r#"
|
|
|
|
union U { field: u8, other: u16 }
|
2021-01-06 20:15:48 +00:00
|
|
|
fn foo(u: U) { u.$0 }
|
2020-07-04 10:36:12 +02:00
|
|
|
"#,
|
|
|
|
expect![[r#"
|
|
|
|
fd field u8
|
|
|
|
fd other u16
|
|
|
|
"#]],
|
2019-12-02 19:27:31 +01:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2020-03-07 23:03:56 +01:00
|
|
|
#[test]
|
2020-07-04 10:36:12 +02:00
|
|
|
fn test_method_completion_only_fitting_impls() {
|
|
|
|
check(
|
|
|
|
r#"
|
|
|
|
struct A<T> {}
|
|
|
|
impl A<u32> {
|
|
|
|
fn the_method(&self) {}
|
|
|
|
}
|
|
|
|
impl A<i32> {
|
|
|
|
fn the_other_method(&self) {}
|
|
|
|
}
|
2021-01-06 20:15:48 +00:00
|
|
|
fn foo(a: A<u32>) { a.$0 }
|
2020-07-04 10:36:12 +02:00
|
|
|
"#,
|
|
|
|
expect![[r#"
|
2021-03-06 16:56:07 -08:00
|
|
|
me the_method() fn(&self)
|
2020-07-04 10:36:12 +02:00
|
|
|
"#]],
|
|
|
|
)
|
2020-03-07 23:03:56 +01:00
|
|
|
}
|
|
|
|
|
2019-04-14 16:08:10 +02:00
|
|
|
#[test]
|
|
|
|
fn test_trait_method_completion() {
|
2020-07-04 10:36:12 +02:00
|
|
|
check(
|
|
|
|
r#"
|
|
|
|
struct A {}
|
|
|
|
trait Trait { fn the_method(&self); }
|
|
|
|
impl Trait for A {}
|
2021-01-06 20:15:48 +00:00
|
|
|
fn foo(a: A) { a.$0 }
|
2020-07-04 10:36:12 +02:00
|
|
|
"#,
|
|
|
|
expect![[r#"
|
2021-07-05 16:44:44 +04:30
|
|
|
me the_method() (as Trait) fn(&self)
|
2020-07-04 10:36:12 +02:00
|
|
|
"#]],
|
2019-04-14 16:08:10 +02:00
|
|
|
);
|
2021-07-07 19:54:58 +02:00
|
|
|
check_edit(
|
|
|
|
"the_method",
|
|
|
|
r#"
|
|
|
|
struct A {}
|
|
|
|
trait Trait { fn the_method(&self); }
|
|
|
|
impl Trait for A {}
|
|
|
|
fn foo(a: A) { a.$0 }
|
|
|
|
"#,
|
|
|
|
r#"
|
|
|
|
struct A {}
|
|
|
|
trait Trait { fn the_method(&self); }
|
|
|
|
impl Trait for A {}
|
|
|
|
fn foo(a: A) { a.the_method()$0 }
|
|
|
|
"#,
|
|
|
|
);
|
2019-04-14 16:08:10 +02:00
|
|
|
}
|
|
|
|
|
2019-06-29 12:19:03 +02:00
|
|
|
#[test]
|
|
|
|
fn test_trait_method_completion_deduplicated() {
|
2020-07-04 10:36:12 +02:00
|
|
|
check(
|
|
|
|
r"
|
|
|
|
struct A {}
|
|
|
|
trait Trait { fn the_method(&self); }
|
|
|
|
impl<T> Trait for T {}
|
2021-01-06 20:15:48 +00:00
|
|
|
fn foo(a: &A) { a.$0 }
|
2020-07-04 10:36:12 +02:00
|
|
|
",
|
|
|
|
expect![[r#"
|
2021-07-05 16:44:44 +04:30
|
|
|
me the_method() (as Trait) fn(&self)
|
2020-07-04 10:36:12 +02:00
|
|
|
"#]],
|
2019-06-29 12:19:03 +02:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2020-03-14 20:48:36 +01:00
|
|
|
#[test]
|
|
|
|
fn completes_trait_method_from_other_module() {
|
2020-07-04 10:36:12 +02:00
|
|
|
check(
|
2019-01-07 19:12:19 +01:00
|
|
|
r"
|
2020-07-04 10:36:12 +02:00
|
|
|
struct A {}
|
|
|
|
mod m {
|
|
|
|
pub trait Trait { fn the_method(&self); }
|
|
|
|
}
|
|
|
|
use m::Trait;
|
|
|
|
impl Trait for A {}
|
2021-01-06 20:15:48 +00:00
|
|
|
fn foo(a: A) { a.$0 }
|
2020-07-04 10:36:12 +02:00
|
|
|
",
|
|
|
|
expect![[r#"
|
2021-07-05 16:44:44 +04:30
|
|
|
me the_method() (as Trait) fn(&self)
|
2020-07-04 10:36:12 +02:00
|
|
|
"#]],
|
2019-01-07 19:12:19 +01:00
|
|
|
);
|
|
|
|
}
|
2019-01-24 08:25:35 -05:00
|
|
|
|
2019-02-12 19:58:36 +02:00
|
|
|
#[test]
|
2020-07-04 10:36:12 +02:00
|
|
|
fn test_no_non_self_method() {
|
|
|
|
check(
|
|
|
|
r#"
|
|
|
|
struct A {}
|
|
|
|
impl A {
|
|
|
|
fn the_method() {}
|
|
|
|
}
|
|
|
|
fn foo(a: A) {
|
2021-01-06 20:15:48 +00:00
|
|
|
a.$0
|
2020-07-04 10:36:12 +02:00
|
|
|
}
|
|
|
|
"#,
|
2021-10-27 17:18:42 +02:00
|
|
|
expect![[r#""#]],
|
2019-02-12 19:58:36 +02:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2019-01-24 08:25:35 -05:00
|
|
|
#[test]
|
|
|
|
fn test_tuple_field_completion() {
|
2020-07-04 10:36:12 +02:00
|
|
|
check(
|
|
|
|
r#"
|
|
|
|
fn foo() {
|
|
|
|
let b = (0, 3.14);
|
2021-01-06 20:15:48 +00:00
|
|
|
b.$0
|
2020-07-04 10:36:12 +02:00
|
|
|
}
|
|
|
|
"#,
|
|
|
|
expect![[r#"
|
2021-10-27 17:18:42 +02:00
|
|
|
fd 0 i32
|
|
|
|
fd 1 f64
|
2020-07-04 10:36:12 +02:00
|
|
|
"#]],
|
2021-07-23 20:20:23 +02:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_tuple_struct_field_completion() {
|
|
|
|
check(
|
|
|
|
r#"
|
|
|
|
struct S(i32, f64);
|
|
|
|
fn foo() {
|
|
|
|
let b = S(0, 3.14);
|
|
|
|
b.$0
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
expect![[r#"
|
2021-10-27 17:18:42 +02:00
|
|
|
fd 0 i32
|
|
|
|
fd 1 f64
|
2021-07-23 20:20:23 +02:00
|
|
|
"#]],
|
|
|
|
);
|
2019-01-24 08:25:35 -05:00
|
|
|
}
|
2019-04-05 22:59:55 +02:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_tuple_field_inference() {
|
2020-07-04 10:36:12 +02:00
|
|
|
check(
|
|
|
|
r#"
|
|
|
|
pub struct S;
|
|
|
|
impl S { pub fn blah(&self) {} }
|
2019-04-05 22:59:55 +02:00
|
|
|
|
2020-07-04 10:36:12 +02:00
|
|
|
struct T(S);
|
2019-04-05 22:59:55 +02:00
|
|
|
|
2020-07-04 10:36:12 +02:00
|
|
|
impl T {
|
|
|
|
fn foo(&self) {
|
|
|
|
// FIXME: This doesn't work without the trailing `a` as `0.` is a float
|
2021-01-06 20:15:48 +00:00
|
|
|
self.0.a$0
|
2019-04-11 16:22:10 +03:00
|
|
|
}
|
2020-07-04 10:36:12 +02:00
|
|
|
}
|
|
|
|
"#,
|
|
|
|
expect![[r#"
|
2021-03-06 16:56:07 -08:00
|
|
|
me blah() fn(&self)
|
2020-07-04 10:36:12 +02:00
|
|
|
"#]],
|
2019-04-05 22:59:55 +02:00
|
|
|
);
|
|
|
|
}
|
2019-08-03 01:15:43 +07:00
|
|
|
|
|
|
|
#[test]
|
2020-07-04 10:36:12 +02:00
|
|
|
fn test_completion_works_in_consts() {
|
|
|
|
check(
|
|
|
|
r#"
|
|
|
|
struct A { the_field: u32 }
|
|
|
|
const X: u32 = {
|
2021-01-06 20:15:48 +00:00
|
|
|
A { the_field: 92 }.$0
|
2020-07-04 10:36:12 +02:00
|
|
|
};
|
|
|
|
"#,
|
|
|
|
expect![[r#"
|
|
|
|
fd the_field u32
|
|
|
|
"#]],
|
2020-02-29 20:53:01 -08:00
|
|
|
);
|
|
|
|
}
|
2020-03-07 15:27:03 +01:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn works_in_simple_macro_1() {
|
2020-07-04 10:36:12 +02:00
|
|
|
check(
|
|
|
|
r#"
|
|
|
|
macro_rules! m { ($e:expr) => { $e } }
|
|
|
|
struct A { the_field: u32 }
|
|
|
|
fn foo(a: A) {
|
2021-01-06 20:15:48 +00:00
|
|
|
m!(a.x$0)
|
2020-07-04 10:36:12 +02:00
|
|
|
}
|
|
|
|
"#,
|
|
|
|
expect![[r#"
|
|
|
|
fd the_field u32
|
|
|
|
"#]],
|
2020-03-07 15:27:03 +01:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn works_in_simple_macro_2() {
|
|
|
|
// this doesn't work yet because the macro doesn't expand without the token -- maybe it can be fixed with better recovery
|
2020-07-04 10:36:12 +02:00
|
|
|
check(
|
|
|
|
r#"
|
|
|
|
macro_rules! m { ($e:expr) => { $e } }
|
|
|
|
struct A { the_field: u32 }
|
|
|
|
fn foo(a: A) {
|
2021-01-06 20:15:48 +00:00
|
|
|
m!(a.$0)
|
2020-07-04 10:36:12 +02:00
|
|
|
}
|
|
|
|
"#,
|
|
|
|
expect![[r#"
|
|
|
|
fd the_field u32
|
|
|
|
"#]],
|
2020-03-07 15:27:03 +01:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn works_in_simple_macro_recursive_1() {
|
2020-07-04 10:36:12 +02:00
|
|
|
check(
|
|
|
|
r#"
|
|
|
|
macro_rules! m { ($e:expr) => { $e } }
|
|
|
|
struct A { the_field: u32 }
|
|
|
|
fn foo(a: A) {
|
2021-01-06 20:15:48 +00:00
|
|
|
m!(m!(m!(a.x$0)))
|
2020-07-04 10:36:12 +02:00
|
|
|
}
|
|
|
|
"#,
|
|
|
|
expect![[r#"
|
|
|
|
fd the_field u32
|
|
|
|
"#]],
|
2020-03-07 15:27:03 +01:00
|
|
|
);
|
|
|
|
}
|
2020-03-10 20:56:26 +01:00
|
|
|
|
2020-03-13 13:03:31 +01:00
|
|
|
#[test]
|
|
|
|
fn macro_expansion_resilient() {
|
2020-07-04 10:36:12 +02:00
|
|
|
check(
|
|
|
|
r#"
|
2020-12-28 01:20:44 +08:00
|
|
|
macro_rules! d {
|
2020-07-04 10:36:12 +02:00
|
|
|
() => {};
|
|
|
|
($val:expr) => {
|
|
|
|
match $val { tmp => { tmp } }
|
|
|
|
};
|
|
|
|
// Trailing comma with single argument is ignored
|
2020-12-28 01:20:44 +08:00
|
|
|
($val:expr,) => { $crate::d!($val) };
|
2020-07-04 10:36:12 +02:00
|
|
|
($($val:expr),+ $(,)?) => {
|
2020-12-28 01:20:44 +08:00
|
|
|
($($crate::d!($val)),+,)
|
2020-07-04 10:36:12 +02:00
|
|
|
};
|
|
|
|
}
|
|
|
|
struct A { the_field: u32 }
|
|
|
|
fn foo(a: A) {
|
2020-12-28 01:20:44 +08:00
|
|
|
d!(a.$0)
|
2020-07-04 10:36:12 +02:00
|
|
|
}
|
|
|
|
"#,
|
|
|
|
expect![[r#"
|
|
|
|
fd the_field u32
|
|
|
|
"#]],
|
2020-03-13 13:03:31 +01:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2020-03-10 20:56:26 +01:00
|
|
|
#[test]
|
2020-07-04 10:36:12 +02:00
|
|
|
fn test_method_completion_issue_3547() {
|
|
|
|
check(
|
|
|
|
r#"
|
|
|
|
struct HashSet<T> {}
|
|
|
|
impl<T> HashSet<T> {
|
|
|
|
pub fn the_method(&self) {}
|
|
|
|
}
|
|
|
|
fn foo() {
|
|
|
|
let s: HashSet<_>;
|
2021-01-06 20:15:48 +00:00
|
|
|
s.$0
|
2020-07-04 10:36:12 +02:00
|
|
|
}
|
|
|
|
"#,
|
|
|
|
expect![[r#"
|
2021-03-06 16:56:07 -08:00
|
|
|
me the_method() fn(&self)
|
2020-07-04 10:36:12 +02:00
|
|
|
"#]],
|
2020-03-10 20:56:26 +01:00
|
|
|
);
|
|
|
|
}
|
2020-10-17 23:43:13 +02:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn completes_method_call_when_receiver_is_a_macro_call() {
|
|
|
|
check(
|
|
|
|
r#"
|
|
|
|
struct S;
|
|
|
|
impl S { fn foo(&self) {} }
|
|
|
|
macro_rules! make_s { () => { S }; }
|
2021-01-06 20:15:48 +00:00
|
|
|
fn main() { make_s!().f$0; }
|
2020-10-17 23:43:13 +02:00
|
|
|
"#,
|
|
|
|
expect![[r#"
|
2021-03-06 16:56:07 -08:00
|
|
|
me foo() fn(&self)
|
2020-10-17 23:43:13 +02:00
|
|
|
"#]],
|
|
|
|
)
|
|
|
|
}
|
2021-02-23 14:54:01 +01:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn completes_after_macro_call_in_submodule() {
|
|
|
|
check(
|
|
|
|
r#"
|
|
|
|
macro_rules! empty {
|
|
|
|
() => {};
|
|
|
|
}
|
|
|
|
|
|
|
|
mod foo {
|
|
|
|
#[derive(Debug, Default)]
|
|
|
|
struct Template2 {}
|
|
|
|
|
|
|
|
impl Template2 {
|
|
|
|
fn private(&self) {}
|
|
|
|
}
|
|
|
|
fn baz() {
|
|
|
|
let goo: Template2 = Template2 {};
|
|
|
|
empty!();
|
|
|
|
goo.$0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
expect![[r#"
|
2021-03-06 16:56:07 -08:00
|
|
|
me private() fn(&self)
|
2021-02-23 14:54:01 +01:00
|
|
|
"#]],
|
|
|
|
);
|
|
|
|
}
|
2021-05-23 12:52:41 +02:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn issue_8931() {
|
|
|
|
check(
|
|
|
|
r#"
|
2021-06-18 22:14:39 +03:00
|
|
|
//- minicore: fn
|
2021-05-23 12:52:41 +02:00
|
|
|
struct S;
|
|
|
|
|
|
|
|
struct Foo;
|
|
|
|
impl Foo {
|
|
|
|
fn foo(&self) -> &[u8] { loop {} }
|
|
|
|
}
|
|
|
|
|
|
|
|
impl S {
|
|
|
|
fn indented(&mut self, f: impl FnOnce(&mut Self)) {
|
|
|
|
}
|
|
|
|
|
|
|
|
fn f(&mut self, v: Foo) {
|
|
|
|
self.indented(|this| v.$0)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
expect![[r#"
|
2021-05-23 13:00:14 +02:00
|
|
|
me foo() fn(&self) -> &[u8]
|
2021-05-23 12:52:41 +02:00
|
|
|
"#]],
|
|
|
|
);
|
|
|
|
}
|
2021-05-28 15:09:10 +02:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn completes_bare_fields_and_methods_in_methods() {
|
|
|
|
check(
|
|
|
|
r#"
|
|
|
|
struct Foo { field: i32 }
|
|
|
|
|
|
|
|
impl Foo { fn foo(&self) { $0 } }"#,
|
|
|
|
expect![[r#"
|
2022-02-03 16:05:21 +01:00
|
|
|
fd self.field i32
|
2021-05-28 15:09:10 +02:00
|
|
|
lc self &Foo
|
|
|
|
sp Self
|
|
|
|
st Foo
|
2021-10-27 16:24:42 +02:00
|
|
|
bt u32
|
2022-05-05 10:49:43 +02:00
|
|
|
me self.foo() fn(&self)
|
2021-05-28 15:09:10 +02:00
|
|
|
"#]],
|
|
|
|
);
|
|
|
|
check(
|
|
|
|
r#"
|
|
|
|
struct Foo(i32);
|
|
|
|
|
|
|
|
impl Foo { fn foo(&mut self) { $0 } }"#,
|
|
|
|
expect![[r#"
|
2022-02-03 16:05:21 +01:00
|
|
|
fd self.0 i32
|
2021-05-28 15:09:10 +02:00
|
|
|
lc self &mut Foo
|
|
|
|
sp Self
|
|
|
|
st Foo
|
2021-10-27 16:24:42 +02:00
|
|
|
bt u32
|
2022-05-05 10:49:43 +02:00
|
|
|
me self.foo() fn(&mut self)
|
2021-05-28 15:09:10 +02:00
|
|
|
"#]],
|
|
|
|
);
|
|
|
|
}
|
2021-09-06 00:16:12 +02:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn macro_completion_after_dot() {
|
|
|
|
check(
|
|
|
|
r#"
|
|
|
|
macro_rules! m {
|
|
|
|
($e:expr) => { $e };
|
|
|
|
}
|
|
|
|
|
|
|
|
struct Completable;
|
|
|
|
|
|
|
|
impl Completable {
|
|
|
|
fn method(&self) {}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn f() {
|
|
|
|
let c = Completable;
|
|
|
|
m!(c.$0);
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
expect![[r#"
|
|
|
|
me method() fn(&self)
|
|
|
|
"#]],
|
|
|
|
);
|
|
|
|
}
|
2021-09-27 21:44:27 +05:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn completes_method_call_when_receiver_type_has_errors_issue_10297() {
|
|
|
|
check(
|
|
|
|
r#"
|
|
|
|
//- minicore: iterator, sized
|
|
|
|
struct Vec<T>;
|
|
|
|
impl<T> IntoIterator for Vec<T> {
|
|
|
|
type Item = ();
|
|
|
|
type IntoIter = ();
|
|
|
|
fn into_iter(self);
|
|
|
|
}
|
|
|
|
fn main() {
|
|
|
|
let x: Vec<_>;
|
|
|
|
x.$0;
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
expect![[r#"
|
|
|
|
me into_iter() (as IntoIterator) fn(self) -> <Self as IntoIterator>::IntoIter
|
|
|
|
"#]],
|
|
|
|
)
|
|
|
|
}
|
2021-12-22 02:25:38 +01:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn postfix_drop_completion() {
|
|
|
|
cov_mark::check!(postfix_drop_completion);
|
|
|
|
check_edit(
|
|
|
|
"drop",
|
|
|
|
r#"
|
|
|
|
//- minicore: drop
|
|
|
|
struct Vec<T>(T);
|
|
|
|
impl<T> Drop for Vec<T> {
|
|
|
|
fn drop(&mut self) {}
|
|
|
|
}
|
|
|
|
fn main() {
|
|
|
|
let x = Vec(0u32)
|
|
|
|
x.$0;
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
r"
|
|
|
|
struct Vec<T>(T);
|
|
|
|
impl<T> Drop for Vec<T> {
|
|
|
|
fn drop(&mut self) {}
|
|
|
|
}
|
|
|
|
fn main() {
|
|
|
|
let x = Vec(0u32)
|
|
|
|
drop($0x);
|
|
|
|
}
|
|
|
|
",
|
|
|
|
)
|
|
|
|
}
|
2019-01-08 22:33:36 +03:00
|
|
|
}
|