diff options
Diffstat (limited to 'crates')
29 files changed, 686 insertions, 282 deletions
diff --git a/crates/hir_def/src/find_path.rs b/crates/hir_def/src/find_path.rs index ee52794aa..219ed4c07 100644 --- a/crates/hir_def/src/find_path.rs +++ b/crates/hir_def/src/find_path.rs | |||
@@ -682,9 +682,11 @@ pub struct S; | |||
682 | //- /main.rs crate:main deps:std | 682 | //- /main.rs crate:main deps:std |
683 | $0 | 683 | $0 |
684 | //- /std.rs crate:std | 684 | //- /std.rs crate:std |
685 | pub mod prelude { pub struct S; } | 685 | pub mod prelude { |
686 | #[prelude_import] | 686 | pub mod rust_2018 { |
687 | pub use prelude::*; | 687 | pub struct S; |
688 | } | ||
689 | } | ||
688 | "#, | 690 | "#, |
689 | "S", | 691 | "S", |
690 | "S", | 692 | "S", |
@@ -700,11 +702,11 @@ pub use prelude::*; | |||
700 | $0 | 702 | $0 |
701 | //- /std.rs crate:std | 703 | //- /std.rs crate:std |
702 | pub mod prelude { | 704 | pub mod prelude { |
703 | pub enum Option<T> { Some(T), None } | 705 | pub mod rust_2018 { |
704 | pub use Option::*; | 706 | pub enum Option<T> { Some(T), None } |
707 | pub use Option::*; | ||
708 | } | ||
705 | } | 709 | } |
706 | #[prelude_import] | ||
707 | pub use prelude::*; | ||
708 | "#; | 710 | "#; |
709 | check_found_path(code, "None", "None", "None", "None"); | 711 | check_found_path(code, "None", "None", "None", "None"); |
710 | check_found_path(code, "Some", "Some", "Some", "Some"); | 712 | check_found_path(code, "Some", "Some", "Some", "Some"); |
@@ -1080,11 +1082,11 @@ fn f() { | |||
1080 | } | 1082 | } |
1081 | //- /std.rs crate:std | 1083 | //- /std.rs crate:std |
1082 | pub mod prelude { | 1084 | pub mod prelude { |
1083 | pub enum Option { None } | 1085 | pub mod rust_2018 { |
1084 | pub use Option::*; | 1086 | pub enum Option { None } |
1087 | pub use Option::*; | ||
1088 | } | ||
1085 | } | 1089 | } |
1086 | #[prelude_import] | ||
1087 | pub use prelude::*; | ||
1088 | "#, | 1090 | "#, |
1089 | "None", | 1091 | "None", |
1090 | "None", | 1092 | "None", |
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs index 7f9fdb379..6b41921ae 100644 --- a/crates/hir_def/src/nameres/collector.rs +++ b/crates/hir_def/src/nameres/collector.rs | |||
@@ -5,13 +5,13 @@ | |||
5 | 5 | ||
6 | use std::iter; | 6 | use std::iter; |
7 | 7 | ||
8 | use base_db::{CrateId, FileId, ProcMacroId}; | 8 | use base_db::{CrateId, Edition, FileId, ProcMacroId}; |
9 | use cfg::{CfgExpr, CfgOptions}; | 9 | use cfg::{CfgExpr, CfgOptions}; |
10 | use hir_expand::{ | 10 | use hir_expand::{ |
11 | ast_id_map::FileAstId, | 11 | ast_id_map::FileAstId, |
12 | builtin_derive::find_builtin_derive, | 12 | builtin_derive::find_builtin_derive, |
13 | builtin_macro::find_builtin_macro, | 13 | builtin_macro::find_builtin_macro, |
14 | name::{AsName, Name}, | 14 | name::{name, AsName, Name}, |
15 | proc_macro::ProcMacroExpander, | 15 | proc_macro::ProcMacroExpander, |
16 | FragmentKind, HirFileId, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind, | 16 | FragmentKind, HirFileId, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind, |
17 | }; | 17 | }; |
@@ -67,14 +67,6 @@ pub(super) fn collect_defs( | |||
67 | def_map | 67 | def_map |
68 | .extern_prelude | 68 | .extern_prelude |
69 | .insert(dep.as_name(), dep_def_map.module_id(dep_def_map.root).into()); | 69 | .insert(dep.as_name(), dep_def_map.module_id(dep_def_map.root).into()); |
70 | |||
71 | // look for the prelude | ||
72 | // If the dependency defines a prelude, we overwrite an already defined | ||
73 | // prelude. This is necessary to import the "std" prelude if a crate | ||
74 | // depends on both "core" and "std". | ||
75 | if dep_def_map.prelude.is_some() { | ||
76 | def_map.prelude = dep_def_map.prelude; | ||
77 | } | ||
78 | } | 70 | } |
79 | } | 71 | } |
80 | 72 | ||
@@ -283,6 +275,8 @@ impl DefCollector<'_> { | |||
283 | 275 | ||
284 | let attrs = item_tree.top_level_attrs(self.db, self.def_map.krate); | 276 | let attrs = item_tree.top_level_attrs(self.db, self.def_map.krate); |
285 | if attrs.cfg().map_or(true, |cfg| self.cfg_options.check(&cfg) != Some(false)) { | 277 | if attrs.cfg().map_or(true, |cfg| self.cfg_options.check(&cfg) != Some(false)) { |
278 | self.inject_prelude(&attrs); | ||
279 | |||
286 | // Process other crate-level attributes. | 280 | // Process other crate-level attributes. |
287 | for attr in &*attrs { | 281 | for attr in &*attrs { |
288 | let attr_name = match attr.path.as_ident() { | 282 | let attr_name = match attr.path.as_ident() { |
@@ -460,6 +454,71 @@ impl DefCollector<'_> { | |||
460 | } | 454 | } |
461 | } | 455 | } |
462 | 456 | ||
457 | fn inject_prelude(&mut self, crate_attrs: &Attrs) { | ||
458 | // See compiler/rustc_builtin_macros/src/standard_library_imports.rs | ||
459 | |||
460 | if crate_attrs.by_key("no_core").exists() { | ||
461 | // libcore does not get a prelude. | ||
462 | return; | ||
463 | } | ||
464 | |||
465 | let krate = if crate_attrs.by_key("no_std").exists() { | ||
466 | name![core] | ||
467 | } else { | ||
468 | let std = name![std]; | ||
469 | if self.def_map.extern_prelude().any(|(name, _)| *name == std) { | ||
470 | std | ||
471 | } else { | ||
472 | // If `std` does not exist for some reason, fall back to core. This mostly helps | ||
473 | // keep r-a's own tests minimal. | ||
474 | name![core] | ||
475 | } | ||
476 | }; | ||
477 | |||
478 | let edition = match self.def_map.edition { | ||
479 | Edition::Edition2015 => name![rust_2015], | ||
480 | Edition::Edition2018 => name![rust_2018], | ||
481 | Edition::Edition2021 => name![rust_2021], | ||
482 | }; | ||
483 | |||
484 | let path_kind = if self.def_map.edition == Edition::Edition2015 { | ||
485 | PathKind::Plain | ||
486 | } else { | ||
487 | PathKind::Abs | ||
488 | }; | ||
489 | let path = ModPath::from_segments( | ||
490 | path_kind.clone(), | ||
491 | [krate.clone(), name![prelude], edition].iter().cloned(), | ||
492 | ); | ||
493 | // Fall back to the older `std::prelude::v1` for compatibility with Rust <1.52.0 | ||
494 | // FIXME remove this fallback | ||
495 | let fallback_path = | ||
496 | ModPath::from_segments(path_kind, [krate, name![prelude], name![v1]].iter().cloned()); | ||
497 | |||
498 | for path in &[path, fallback_path] { | ||
499 | let (per_ns, _) = self.def_map.resolve_path( | ||
500 | self.db, | ||
501 | self.def_map.root, | ||
502 | &path, | ||
503 | BuiltinShadowMode::Other, | ||
504 | ); | ||
505 | |||
506 | match &per_ns.types { | ||
507 | Some((ModuleDefId::ModuleId(m), _)) => { | ||
508 | self.def_map.prelude = Some(*m); | ||
509 | return; | ||
510 | } | ||
511 | _ => { | ||
512 | log::debug!( | ||
513 | "could not resolve prelude path `{}` to module (resolved to {:?})", | ||
514 | path, | ||
515 | per_ns.types | ||
516 | ); | ||
517 | } | ||
518 | } | ||
519 | } | ||
520 | } | ||
521 | |||
463 | /// Adds a definition of procedural macro `name` to the root module. | 522 | /// Adds a definition of procedural macro `name` to the root module. |
464 | /// | 523 | /// |
465 | /// # Notes on procedural macro resolution | 524 | /// # Notes on procedural macro resolution |
@@ -718,6 +777,8 @@ impl DefCollector<'_> { | |||
718 | match def.take_types() { | 777 | match def.take_types() { |
719 | Some(ModuleDefId::ModuleId(m)) => { | 778 | Some(ModuleDefId::ModuleId(m)) => { |
720 | if import.is_prelude { | 779 | if import.is_prelude { |
780 | // Note: This dodgily overrides the injected prelude. The rustc | ||
781 | // implementation seems to work the same though. | ||
721 | cov_mark::hit!(std_prelude); | 782 | cov_mark::hit!(std_prelude); |
722 | self.def_map.prelude = Some(m); | 783 | self.def_map.prelude = Some(m); |
723 | } else if m.krate != self.def_map.krate { | 784 | } else if m.krate != self.def_map.krate { |
diff --git a/crates/hir_def/src/nameres/tests.rs b/crates/hir_def/src/nameres/tests.rs index 9f652731d..58c01354a 100644 --- a/crates/hir_def/src/nameres/tests.rs +++ b/crates/hir_def/src/nameres/tests.rs | |||
@@ -246,15 +246,16 @@ fn std_prelude() { | |||
246 | check( | 246 | check( |
247 | r#" | 247 | r#" |
248 | //- /main.rs crate:main deps:test_crate | 248 | //- /main.rs crate:main deps:test_crate |
249 | #[prelude_import] | ||
250 | use ::test_crate::prelude::*; | ||
251 | |||
249 | use Foo::*; | 252 | use Foo::*; |
250 | 253 | ||
251 | //- /lib.rs crate:test_crate | 254 | //- /lib.rs crate:test_crate |
252 | mod prelude; | 255 | pub mod prelude; |
253 | #[prelude_import] | ||
254 | use prelude::*; | ||
255 | 256 | ||
256 | //- /prelude.rs | 257 | //- /prelude.rs |
257 | pub enum Foo { Bar, Baz }; | 258 | pub enum Foo { Bar, Baz } |
258 | "#, | 259 | "#, |
259 | expect![[r#" | 260 | expect![[r#" |
260 | crate | 261 | crate |
@@ -467,6 +468,74 @@ pub struct Bar; | |||
467 | } | 468 | } |
468 | 469 | ||
469 | #[test] | 470 | #[test] |
471 | fn no_std_prelude() { | ||
472 | check( | ||
473 | r#" | ||
474 | //- /main.rs crate:main deps:core,std | ||
475 | #![cfg_attr(not(never), no_std)] | ||
476 | use Rust; | ||
477 | |||
478 | //- /core.rs crate:core | ||
479 | pub mod prelude { | ||
480 | pud mod rust_2018 { | ||
481 | pub struct Rust; | ||
482 | } | ||
483 | } | ||
484 | //- /std.rs crate:std deps:core | ||
485 | pub mod prelude { | ||
486 | pud mod rust_2018 { | ||
487 | } | ||
488 | } | ||
489 | "#, | ||
490 | expect![[r#" | ||
491 | crate | ||
492 | Rust: t v | ||
493 | "#]], | ||
494 | ); | ||
495 | } | ||
496 | |||
497 | #[test] | ||
498 | fn edition_specific_preludes() { | ||
499 | // We can't test the 2015 prelude here since you can't reexport its contents with 2015's | ||
500 | // absolute paths. | ||
501 | |||
502 | check( | ||
503 | r#" | ||
504 | //- /main.rs edition:2018 crate:main deps:std | ||
505 | use Rust2018; | ||
506 | |||
507 | //- /std.rs crate:std | ||
508 | pub mod prelude { | ||
509 | pud mod rust_2018 { | ||
510 | pub struct Rust2018; | ||
511 | } | ||
512 | } | ||
513 | "#, | ||
514 | expect![[r#" | ||
515 | crate | ||
516 | Rust2018: t v | ||
517 | "#]], | ||
518 | ); | ||
519 | check( | ||
520 | r#" | ||
521 | //- /main.rs edition:2021 crate:main deps:std | ||
522 | use Rust2021; | ||
523 | |||
524 | //- /std.rs crate:std | ||
525 | pub mod prelude { | ||
526 | pud mod rust_2021 { | ||
527 | pub struct Rust2021; | ||
528 | } | ||
529 | } | ||
530 | "#, | ||
531 | expect![[r#" | ||
532 | crate | ||
533 | Rust2021: t v | ||
534 | "#]], | ||
535 | ); | ||
536 | } | ||
537 | |||
538 | #[test] | ||
470 | fn std_prelude_takes_precedence_above_core_prelude() { | 539 | fn std_prelude_takes_precedence_above_core_prelude() { |
471 | check( | 540 | check( |
472 | r#" | 541 | r#" |
@@ -474,18 +543,18 @@ fn std_prelude_takes_precedence_above_core_prelude() { | |||
474 | use {Foo, Bar}; | 543 | use {Foo, Bar}; |
475 | 544 | ||
476 | //- /std.rs crate:std deps:core | 545 | //- /std.rs crate:std deps:core |
477 | #[prelude_import] | 546 | pub mod prelude { |
478 | pub use self::prelude::*; | 547 | pub mod rust_2018 { |
479 | mod prelude { | 548 | pub struct Foo; |
480 | pub struct Foo; | 549 | pub use core::prelude::rust_2018::Bar; |
481 | pub use core::prelude::Bar; | 550 | } |
482 | } | 551 | } |
483 | 552 | ||
484 | //- /core.rs crate:core | 553 | //- /core.rs crate:core |
485 | #[prelude_import] | 554 | pub mod prelude { |
486 | pub use self::prelude::*; | 555 | pub mod rust_2018 { |
487 | mod prelude { | 556 | pub struct Bar; |
488 | pub struct Bar; | 557 | } |
489 | } | 558 | } |
490 | "#, | 559 | "#, |
491 | expect![[r#" | 560 | expect![[r#" |
@@ -504,15 +573,15 @@ fn cfg_not_test() { | |||
504 | use {Foo, Bar, Baz}; | 573 | use {Foo, Bar, Baz}; |
505 | 574 | ||
506 | //- /lib.rs crate:std | 575 | //- /lib.rs crate:std |
507 | #[prelude_import] | 576 | pub mod prelude { |
508 | pub use self::prelude::*; | 577 | pub mod rust_2018 { |
509 | mod prelude { | 578 | #[cfg(test)] |
510 | #[cfg(test)] | 579 | pub struct Foo; |
511 | pub struct Foo; | 580 | #[cfg(not(test))] |
512 | #[cfg(not(test))] | 581 | pub struct Bar; |
513 | pub struct Bar; | 582 | #[cfg(all(not(any()), feature = "foo", feature = "bar", opt = "42"))] |
514 | #[cfg(all(not(any()), feature = "foo", feature = "bar", opt = "42"))] | 583 | pub struct Baz; |
515 | pub struct Baz; | 584 | } |
516 | } | 585 | } |
517 | "#, | 586 | "#, |
518 | expect![[r#" | 587 | expect![[r#" |
@@ -532,15 +601,15 @@ fn cfg_test() { | |||
532 | use {Foo, Bar, Baz}; | 601 | use {Foo, Bar, Baz}; |
533 | 602 | ||
534 | //- /lib.rs crate:std cfg:test,feature=foo,feature=bar,opt=42 | 603 | //- /lib.rs crate:std cfg:test,feature=foo,feature=bar,opt=42 |
535 | #[prelude_import] | 604 | pub mod prelude { |
536 | pub use self::prelude::*; | 605 | pub mod rust_2018 { |
537 | mod prelude { | 606 | #[cfg(test)] |
538 | #[cfg(test)] | 607 | pub struct Foo; |
539 | pub struct Foo; | 608 | #[cfg(not(test))] |
540 | #[cfg(not(test))] | 609 | pub struct Bar; |
541 | pub struct Bar; | 610 | #[cfg(all(not(any()), feature = "foo", feature = "bar", opt = "42"))] |
542 | #[cfg(all(not(any()), feature = "foo", feature = "bar", opt = "42"))] | 611 | pub struct Baz; |
543 | pub struct Baz; | 612 | } |
544 | } | 613 | } |
545 | "#, | 614 | "#, |
546 | expect![[r#" | 615 | expect![[r#" |
diff --git a/crates/hir_def/src/nameres/tests/macros.rs b/crates/hir_def/src/nameres/tests/macros.rs index 3065efd65..371618438 100644 --- a/crates/hir_def/src/nameres/tests/macros.rs +++ b/crates/hir_def/src/nameres/tests/macros.rs | |||
@@ -264,7 +264,7 @@ fn prelude_is_macro_use() { | |||
264 | cov_mark::check!(prelude_is_macro_use); | 264 | cov_mark::check!(prelude_is_macro_use); |
265 | check( | 265 | check( |
266 | r#" | 266 | r#" |
267 | //- /main.rs crate:main deps:foo | 267 | //- /main.rs crate:main deps:std |
268 | structs!(Foo); | 268 | structs!(Foo); |
269 | structs_priv!(Bar); | 269 | structs_priv!(Bar); |
270 | structs_outside!(Out); | 270 | structs_outside!(Out); |
@@ -276,21 +276,20 @@ mod bar; | |||
276 | structs!(Baz); | 276 | structs!(Baz); |
277 | crate::structs!(MacroNotResolved3); | 277 | crate::structs!(MacroNotResolved3); |
278 | 278 | ||
279 | //- /lib.rs crate:foo | 279 | //- /lib.rs crate:std |
280 | #[prelude_import] | 280 | pub mod prelude { |
281 | use self::prelude::*; | 281 | pub mod rust_2018 { |
282 | |||
283 | mod prelude { | ||
284 | #[macro_export] | ||
285 | macro_rules! structs { | ||
286 | ($i:ident) => { struct $i; } | ||
287 | } | ||
288 | |||
289 | mod priv_mod { | ||
290 | #[macro_export] | 282 | #[macro_export] |
291 | macro_rules! structs_priv { | 283 | macro_rules! structs { |
292 | ($i:ident) => { struct $i; } | 284 | ($i:ident) => { struct $i; } |
293 | } | 285 | } |
286 | |||
287 | mod priv_mod { | ||
288 | #[macro_export] | ||
289 | macro_rules! structs_priv { | ||
290 | ($i:ident) => { struct $i; } | ||
291 | } | ||
292 | } | ||
294 | } | 293 | } |
295 | } | 294 | } |
296 | 295 | ||
@@ -617,12 +616,11 @@ fn macro_dollar_crate_is_correct_in_indirect_deps() { | |||
617 | foo!(); | 616 | foo!(); |
618 | 617 | ||
619 | //- /std.rs crate:std deps:core | 618 | //- /std.rs crate:std deps:core |
620 | #[prelude_import] | ||
621 | use self::prelude::*; | ||
622 | |||
623 | pub use core::foo; | 619 | pub use core::foo; |
624 | 620 | ||
625 | mod prelude {} | 621 | pub mod prelude { |
622 | pub mod rust_2018 {} | ||
623 | } | ||
626 | 624 | ||
627 | #[macro_use] | 625 | #[macro_use] |
628 | mod std_macros; | 626 | mod std_macros; |
diff --git a/crates/hir_expand/src/name.rs b/crates/hir_expand/src/name.rs index b07fbf8b3..00b8adc1e 100644 --- a/crates/hir_expand/src/name.rs +++ b/crates/hir_expand/src/name.rs | |||
@@ -176,6 +176,11 @@ pub mod known { | |||
176 | result, | 176 | result, |
177 | boxed, | 177 | boxed, |
178 | option, | 178 | option, |
179 | prelude, | ||
180 | rust_2015, | ||
181 | rust_2018, | ||
182 | rust_2021, | ||
183 | v1, | ||
179 | // Components of known path (type name) | 184 | // Components of known path (type name) |
180 | Iterator, | 185 | Iterator, |
181 | IntoIterator, | 186 | IntoIterator, |
diff --git a/crates/hir_ty/src/infer/pat.rs b/crates/hir_ty/src/infer/pat.rs index a21f44d6a..25dff7e49 100644 --- a/crates/hir_ty/src/infer/pat.rs +++ b/crates/hir_ty/src/infer/pat.rs | |||
@@ -297,6 +297,10 @@ fn is_non_ref_pat(body: &hir_def::body::Body, pat: PatId) -> bool { | |||
297 | Expr::Literal(Literal::String(..)) => false, | 297 | Expr::Literal(Literal::String(..)) => false, |
298 | _ => true, | 298 | _ => true, |
299 | }, | 299 | }, |
300 | Pat::Bind { mode: BindingAnnotation::Mutable, subpat: Some(subpat), .. } | ||
301 | | Pat::Bind { mode: BindingAnnotation::Unannotated, subpat: Some(subpat), .. } => { | ||
302 | is_non_ref_pat(body, *subpat) | ||
303 | } | ||
300 | Pat::Wild | Pat::Bind { .. } | Pat::Ref { .. } | Pat::Box { .. } | Pat::Missing => false, | 304 | Pat::Wild | Pat::Bind { .. } | Pat::Ref { .. } | Pat::Box { .. } | Pat::Missing => false, |
301 | } | 305 | } |
302 | } | 306 | } |
diff --git a/crates/hir_ty/src/tests/macros.rs b/crates/hir_ty/src/tests/macros.rs index 7647bb08b..d14103aab 100644 --- a/crates/hir_ty/src/tests/macros.rs +++ b/crates/hir_ty/src/tests/macros.rs | |||
@@ -982,14 +982,18 @@ fn test() { | |||
982 | } //^ S | 982 | } //^ S |
983 | 983 | ||
984 | //- /lib.rs crate:core | 984 | //- /lib.rs crate:core |
985 | #[prelude_import] | 985 | pub mod prelude { |
986 | use clone::*; | 986 | pub mod rust_2018 { |
987 | mod clone { | 987 | #[rustc_builtin_macro] |
988 | trait Clone { | 988 | pub macro Clone {} |
989 | pub use crate::clone::Clone; | ||
990 | } | ||
991 | } | ||
992 | |||
993 | pub mod clone { | ||
994 | pub trait Clone { | ||
989 | fn clone(&self) -> Self; | 995 | fn clone(&self) -> Self; |
990 | } | 996 | } |
991 | #[rustc_builtin_macro] | ||
992 | macro Clone {} | ||
993 | } | 997 | } |
994 | "#, | 998 | "#, |
995 | ); | 999 | ); |
@@ -1001,14 +1005,22 @@ fn infer_derive_clone_in_core() { | |||
1001 | r#" | 1005 | r#" |
1002 | //- /lib.rs crate:core | 1006 | //- /lib.rs crate:core |
1003 | #[prelude_import] | 1007 | #[prelude_import] |
1004 | use clone::*; | 1008 | use prelude::rust_2018::*; |
1005 | mod clone { | 1009 | |
1006 | trait Clone { | 1010 | pub mod prelude { |
1011 | pub mod rust_2018 { | ||
1012 | #[rustc_builtin_macro] | ||
1013 | pub macro Clone {} | ||
1014 | pub use crate::clone::Clone; | ||
1015 | } | ||
1016 | } | ||
1017 | |||
1018 | pub mod clone { | ||
1019 | pub trait Clone { | ||
1007 | fn clone(&self) -> Self; | 1020 | fn clone(&self) -> Self; |
1008 | } | 1021 | } |
1009 | #[rustc_builtin_macro] | ||
1010 | macro Clone {} | ||
1011 | } | 1022 | } |
1023 | |||
1012 | #[derive(Clone)] | 1024 | #[derive(Clone)] |
1013 | pub struct S; | 1025 | pub struct S; |
1014 | 1026 | ||
@@ -1037,14 +1049,18 @@ fn test() { | |||
1037 | } | 1049 | } |
1038 | 1050 | ||
1039 | //- /lib.rs crate:core | 1051 | //- /lib.rs crate:core |
1040 | #[prelude_import] | 1052 | pub mod prelude { |
1041 | use clone::*; | 1053 | pub mod rust_2018 { |
1042 | mod clone { | 1054 | #[rustc_builtin_macro] |
1043 | trait Clone { | 1055 | pub macro Clone {} |
1056 | pub use crate::clone::Clone; | ||
1057 | } | ||
1058 | } | ||
1059 | |||
1060 | pub mod clone { | ||
1061 | pub trait Clone { | ||
1044 | fn clone(&self) -> Self; | 1062 | fn clone(&self) -> Self; |
1045 | } | 1063 | } |
1046 | #[rustc_builtin_macro] | ||
1047 | macro Clone {} | ||
1048 | } | 1064 | } |
1049 | "#, | 1065 | "#, |
1050 | ); | 1066 | ); |
diff --git a/crates/hir_ty/src/tests/method_resolution.rs b/crates/hir_ty/src/tests/method_resolution.rs index a4c132bc5..058eb9129 100644 --- a/crates/hir_ty/src/tests/method_resolution.rs +++ b/crates/hir_ty/src/tests/method_resolution.rs | |||
@@ -796,7 +796,7 @@ fn test() { | |||
796 | fn method_resolution_trait_from_prelude() { | 796 | fn method_resolution_trait_from_prelude() { |
797 | check_types( | 797 | check_types( |
798 | r#" | 798 | r#" |
799 | //- /main.rs crate:main deps:other_crate | 799 | //- /main.rs crate:main deps:core |
800 | struct S; | 800 | struct S; |
801 | impl Clone for S {} | 801 | impl Clone for S {} |
802 | 802 | ||
@@ -805,12 +805,12 @@ fn test() { | |||
805 | //^ S | 805 | //^ S |
806 | } | 806 | } |
807 | 807 | ||
808 | //- /lib.rs crate:other_crate | 808 | //- /lib.rs crate:core |
809 | #[prelude_import] use foo::*; | 809 | pub mod prelude { |
810 | 810 | pub mod rust_2018 { | |
811 | mod foo { | 811 | pub trait Clone { |
812 | trait Clone { | 812 | fn clone(&self) -> Self; |
813 | fn clone(&self) -> Self; | 813 | } |
814 | } | 814 | } |
815 | } | 815 | } |
816 | "#, | 816 | "#, |
diff --git a/crates/hir_ty/src/tests/patterns.rs b/crates/hir_ty/src/tests/patterns.rs index cd08b5c7a..7d00cee9b 100644 --- a/crates/hir_ty/src/tests/patterns.rs +++ b/crates/hir_ty/src/tests/patterns.rs | |||
@@ -20,6 +20,8 @@ fn infer_pattern() { | |||
20 | let h = val; | 20 | let h = val; |
21 | } | 21 | } |
22 | 22 | ||
23 | if let x @ true = &true {} | ||
24 | |||
23 | let lambda = |a: u64, b, c: i32| { a + b; c }; | 25 | let lambda = |a: u64, b, c: i32| { a + b; c }; |
24 | 26 | ||
25 | let ref ref_to_x = x; | 27 | let ref ref_to_x = x; |
@@ -30,7 +32,7 @@ fn infer_pattern() { | |||
30 | "#, | 32 | "#, |
31 | expect![[r#" | 33 | expect![[r#" |
32 | 8..9 'x': &i32 | 34 | 8..9 'x': &i32 |
33 | 17..368 '{ ...o_x; }': () | 35 | 17..400 '{ ...o_x; }': () |
34 | 27..28 'y': &i32 | 36 | 27..28 'y': &i32 |
35 | 31..32 'x': &i32 | 37 | 31..32 'x': &i32 |
36 | 42..44 '&z': &i32 | 38 | 42..44 '&z': &i32 |
@@ -59,24 +61,31 @@ fn infer_pattern() { | |||
59 | 176..204 '{ ... }': () | 61 | 176..204 '{ ... }': () |
60 | 190..191 'h': {unknown} | 62 | 190..191 'h': {unknown} |
61 | 194..197 'val': {unknown} | 63 | 194..197 'val': {unknown} |
62 | 214..220 'lambda': |u64, u64, i32| -> i32 | 64 | 210..236 'if let...rue {}': () |
63 | 223..255 '|a: u6...b; c }': |u64, u64, i32| -> i32 | 65 | 217..225 'x @ true': &bool |
64 | 224..225 'a': u64 | 66 | 221..225 'true': bool |
65 | 232..233 'b': u64 | 67 | 221..225 'true': bool |
66 | 235..236 'c': i32 | 68 | 228..233 '&true': &bool |
67 | 243..255 '{ a + b; c }': i32 | 69 | 229..233 'true': bool |
68 | 245..246 'a': u64 | 70 | 234..236 '{}': () |
69 | 245..250 'a + b': u64 | 71 | 246..252 'lambda': |u64, u64, i32| -> i32 |
70 | 249..250 'b': u64 | 72 | 255..287 '|a: u6...b; c }': |u64, u64, i32| -> i32 |
71 | 252..253 'c': i32 | 73 | 256..257 'a': u64 |
72 | 266..278 'ref ref_to_x': &&i32 | 74 | 264..265 'b': u64 |
73 | 281..282 'x': &i32 | 75 | 267..268 'c': i32 |
74 | 292..301 'mut mut_x': &i32 | 76 | 275..287 '{ a + b; c }': i32 |
75 | 304..305 'x': &i32 | 77 | 277..278 'a': u64 |
76 | 315..335 'ref mu...f_to_x': &mut &i32 | 78 | 277..282 'a + b': u64 |
77 | 338..339 'x': &i32 | 79 | 281..282 'b': u64 |
78 | 349..350 'k': &mut &i32 | 80 | 284..285 'c': i32 |
79 | 353..365 'mut_ref_to_x': &mut &i32 | 81 | 298..310 'ref ref_to_x': &&i32 |
82 | 313..314 'x': &i32 | ||
83 | 324..333 'mut mut_x': &i32 | ||
84 | 336..337 'x': &i32 | ||
85 | 347..367 'ref mu...f_to_x': &mut &i32 | ||
86 | 370..371 'x': &i32 | ||
87 | 381..382 'k': &mut &i32 | ||
88 | 385..397 'mut_ref_to_x': &mut &i32 | ||
80 | "#]], | 89 | "#]], |
81 | ); | 90 | ); |
82 | } | 91 | } |
diff --git a/crates/hir_ty/src/tests/regression.rs b/crates/hir_ty/src/tests/regression.rs index ad9edf11c..1019e783b 100644 --- a/crates/hir_ty/src/tests/regression.rs +++ b/crates/hir_ty/src/tests/regression.rs | |||
@@ -426,11 +426,12 @@ fn test() { | |||
426 | 426 | ||
427 | //- /std.rs crate:std | 427 | //- /std.rs crate:std |
428 | #[prelude_import] | 428 | #[prelude_import] |
429 | use prelude::*; | 429 | use self::prelude::rust_2018::*; |
430 | |||
431 | pub mod prelude { | 430 | pub mod prelude { |
432 | pub use crate::iter::Iterator; | 431 | pub mod rust_2018 { |
433 | pub use crate::option::Option; | 432 | pub use crate::iter::Iterator; |
433 | pub use crate::option::Option; | ||
434 | } | ||
434 | } | 435 | } |
435 | 436 | ||
436 | pub mod iter { | 437 | pub mod iter { |
diff --git a/crates/hir_ty/src/tests/simple.rs b/crates/hir_ty/src/tests/simple.rs index ac312981d..3418ed21e 100644 --- a/crates/hir_ty/src/tests/simple.rs +++ b/crates/hir_ty/src/tests/simple.rs | |||
@@ -2712,3 +2712,23 @@ fn main() { | |||
2712 | "#]], | 2712 | "#]], |
2713 | ); | 2713 | ); |
2714 | } | 2714 | } |
2715 | |||
2716 | #[test] | ||
2717 | fn prelude_2015() { | ||
2718 | check_types( | ||
2719 | r#" | ||
2720 | //- /main.rs edition:2015 crate:main deps:core | ||
2721 | fn f() { | ||
2722 | Rust; | ||
2723 | //^ Rust | ||
2724 | } | ||
2725 | |||
2726 | //- /core.rs crate:core | ||
2727 | pub mod prelude { | ||
2728 | pub mod rust_2015 { | ||
2729 | pub struct Rust; | ||
2730 | } | ||
2731 | } | ||
2732 | "#, | ||
2733 | ); | ||
2734 | } | ||
diff --git a/crates/hir_ty/src/tests/traits.rs b/crates/hir_ty/src/tests/traits.rs index 49add4ab9..588f0d1d4 100644 --- a/crates/hir_ty/src/tests/traits.rs +++ b/crates/hir_ty/src/tests/traits.rs | |||
@@ -20,11 +20,12 @@ fn test() { | |||
20 | } //^ u64 | 20 | } //^ u64 |
21 | 21 | ||
22 | //- /core.rs crate:core | 22 | //- /core.rs crate:core |
23 | #[prelude_import] use future::*; | 23 | pub mod prelude { |
24 | mod future { | 24 | pub mod rust_2018 { |
25 | #[lang = "future_trait"] | 25 | #[lang = "future_trait"] |
26 | trait Future { | 26 | pub trait Future { |
27 | type Output; | 27 | type Output; |
28 | } | ||
28 | } | 29 | } |
29 | } | 30 | } |
30 | "#, | 31 | "#, |
@@ -136,17 +137,15 @@ fn test() { | |||
136 | } //^ i32 | 137 | } //^ i32 |
137 | 138 | ||
138 | //- /core.rs crate:core | 139 | //- /core.rs crate:core |
139 | #[prelude_import] use ops::*; | 140 | pub mod ops { |
140 | mod ops { | 141 | pub trait Try { |
141 | trait Try { | ||
142 | type Ok; | 142 | type Ok; |
143 | type Error; | 143 | type Error; |
144 | } | 144 | } |
145 | } | 145 | } |
146 | 146 | ||
147 | #[prelude_import] use result::*; | 147 | pub mod result { |
148 | mod result { | 148 | pub enum Result<O, E> { |
149 | enum Result<O, E> { | ||
150 | Ok(O), | 149 | Ok(O), |
151 | Err(E) | 150 | Err(E) |
152 | } | 151 | } |
@@ -156,6 +155,12 @@ mod result { | |||
156 | type Error = E; | 155 | type Error = E; |
157 | } | 156 | } |
158 | } | 157 | } |
158 | |||
159 | pub mod prelude { | ||
160 | pub mod rust_2018 { | ||
161 | pub use crate::{result::*, ops::*}; | ||
162 | } | ||
163 | } | ||
159 | "#, | 164 | "#, |
160 | ); | 165 | ); |
161 | } | 166 | } |
@@ -190,8 +195,7 @@ mov convert { | |||
190 | impl<T> From<T> for T {} | 195 | impl<T> From<T> for T {} |
191 | } | 196 | } |
192 | 197 | ||
193 | #[prelude_import] use result::*; | 198 | pub mod result { |
194 | mod result { | ||
195 | use crate::convert::From; | 199 | use crate::convert::From; |
196 | use crate::ops::{Try, FromResidual}; | 200 | use crate::ops::{Try, FromResidual}; |
197 | 201 | ||
@@ -208,6 +212,12 @@ mod result { | |||
208 | 212 | ||
209 | impl<T, E, F: From<E>> FromResidual<Result<Infallible, E>> for Result<T, F> {} | 213 | impl<T, E, F: From<E>> FromResidual<Result<Infallible, E>> for Result<T, F> {} |
210 | } | 214 | } |
215 | |||
216 | pub mod prelude { | ||
217 | pub mod rust_2018 { | ||
218 | pub use crate::result::*; | ||
219 | } | ||
220 | } | ||
211 | "#, | 221 | "#, |
212 | ); | 222 | ); |
213 | } | 223 | } |
@@ -217,6 +227,7 @@ fn infer_for_loop() { | |||
217 | check_types( | 227 | check_types( |
218 | r#" | 228 | r#" |
219 | //- /main.rs crate:main deps:core,alloc | 229 | //- /main.rs crate:main deps:core,alloc |
230 | #![no_std] | ||
220 | use alloc::collections::Vec; | 231 | use alloc::collections::Vec; |
221 | 232 | ||
222 | fn test() { | 233 | fn test() { |
@@ -228,14 +239,19 @@ fn test() { | |||
228 | } | 239 | } |
229 | 240 | ||
230 | //- /core.rs crate:core | 241 | //- /core.rs crate:core |
231 | #[prelude_import] use iter::*; | 242 | pub mod iter { |
232 | mod iter { | 243 | pub trait IntoIterator { |
233 | trait IntoIterator { | ||
234 | type Item; | 244 | type Item; |
235 | } | 245 | } |
236 | } | 246 | } |
247 | pub mod prelude { | ||
248 | pub mod rust_2018 { | ||
249 | pub use crate::iter::*; | ||
250 | } | ||
251 | } | ||
237 | 252 | ||
238 | //- /alloc.rs crate:alloc deps:core | 253 | //- /alloc.rs crate:alloc deps:core |
254 | #![no_std] | ||
239 | mod collections { | 255 | mod collections { |
240 | struct Vec<T> {} | 256 | struct Vec<T> {} |
241 | impl<T> Vec<T> { | 257 | impl<T> Vec<T> { |
diff --git a/crates/ide/src/expand_macro.rs b/crates/ide/src/expand_macro.rs index eebae5ebe..e0d01fa96 100644 --- a/crates/ide/src/expand_macro.rs +++ b/crates/ide/src/expand_macro.rs | |||
@@ -28,8 +28,8 @@ pub struct ExpandedMacro { | |||
28 | pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option<ExpandedMacro> { | 28 | pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option<ExpandedMacro> { |
29 | let sema = Semantics::new(db); | 29 | let sema = Semantics::new(db); |
30 | let file = sema.parse(position.file_id); | 30 | let file = sema.parse(position.file_id); |
31 | let name_ref = find_node_at_offset::<ast::NameRef>(file.syntax(), position.offset)?; | 31 | let mac = find_node_at_offset::<ast::MacroCall>(file.syntax(), position.offset)?; |
32 | let mac = name_ref.syntax().ancestors().find_map(ast::MacroCall::cast)?; | 32 | let name = mac.path()?.segment()?.name_ref()?; |
33 | 33 | ||
34 | let expanded = expand_macro_recur(&sema, &mac)?; | 34 | let expanded = expand_macro_recur(&sema, &mac)?; |
35 | 35 | ||
@@ -37,7 +37,7 @@ pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option< | |||
37 | // macro expansion may lose all white space information | 37 | // macro expansion may lose all white space information |
38 | // But we hope someday we can use ra_fmt for that | 38 | // But we hope someday we can use ra_fmt for that |
39 | let expansion = insert_whitespaces(expanded); | 39 | let expansion = insert_whitespaces(expanded); |
40 | Some(ExpandedMacro { name: name_ref.text().to_string(), expansion }) | 40 | Some(ExpandedMacro { name: name.to_string(), expansion }) |
41 | } | 41 | } |
42 | 42 | ||
43 | fn expand_macro_recur( | 43 | fn expand_macro_recur( |
diff --git a/crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs b/crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs index 007aba23d..d3ff7b65c 100644 --- a/crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs +++ b/crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs | |||
@@ -11,14 +11,19 @@ use ide_db::{ | |||
11 | search::FileReference, | 11 | search::FileReference, |
12 | RootDatabase, | 12 | RootDatabase, |
13 | }; | 13 | }; |
14 | use itertools::Itertools; | ||
14 | use rustc_hash::FxHashSet; | 15 | use rustc_hash::FxHashSet; |
15 | use syntax::{ | 16 | use syntax::{ |
16 | algo::find_node_at_offset, | 17 | ast::{ |
17 | ast::{self, make, AstNode, NameOwner, VisibilityOwner}, | 18 | self, make, AstNode, AttrsOwner, GenericParamsOwner, NameOwner, TypeBoundsOwner, |
18 | ted, SyntaxNode, T, | 19 | VisibilityOwner, |
20 | }, | ||
21 | match_ast, | ||
22 | ted::{self, Position}, | ||
23 | SyntaxNode, T, | ||
19 | }; | 24 | }; |
20 | 25 | ||
21 | use crate::{AssistContext, AssistId, AssistKind, Assists}; | 26 | use crate::{assist_context::AssistBuilder, AssistContext, AssistId, AssistKind, Assists}; |
22 | 27 | ||
23 | // Assist: extract_struct_from_enum_variant | 28 | // Assist: extract_struct_from_enum_variant |
24 | // | 29 | // |
@@ -70,11 +75,10 @@ pub(crate) fn extract_struct_from_enum_variant( | |||
70 | continue; | 75 | continue; |
71 | } | 76 | } |
72 | builder.edit_file(file_id); | 77 | builder.edit_file(file_id); |
73 | let source_file = builder.make_mut(ctx.sema.parse(file_id)); | ||
74 | let processed = process_references( | 78 | let processed = process_references( |
75 | ctx, | 79 | ctx, |
80 | builder, | ||
76 | &mut visited_modules_set, | 81 | &mut visited_modules_set, |
77 | source_file.syntax(), | ||
78 | &enum_module_def, | 82 | &enum_module_def, |
79 | &variant_hir_name, | 83 | &variant_hir_name, |
80 | references, | 84 | references, |
@@ -84,13 +88,12 @@ pub(crate) fn extract_struct_from_enum_variant( | |||
84 | }); | 88 | }); |
85 | } | 89 | } |
86 | builder.edit_file(ctx.frange.file_id); | 90 | builder.edit_file(ctx.frange.file_id); |
87 | let source_file = builder.make_mut(ctx.sema.parse(ctx.frange.file_id)); | ||
88 | let variant = builder.make_mut(variant.clone()); | 91 | let variant = builder.make_mut(variant.clone()); |
89 | if let Some(references) = def_file_references { | 92 | if let Some(references) = def_file_references { |
90 | let processed = process_references( | 93 | let processed = process_references( |
91 | ctx, | 94 | ctx, |
95 | builder, | ||
92 | &mut visited_modules_set, | 96 | &mut visited_modules_set, |
93 | source_file.syntax(), | ||
94 | &enum_module_def, | 97 | &enum_module_def, |
95 | &variant_hir_name, | 98 | &variant_hir_name, |
96 | references, | 99 | references, |
@@ -100,12 +103,12 @@ pub(crate) fn extract_struct_from_enum_variant( | |||
100 | }); | 103 | }); |
101 | } | 104 | } |
102 | 105 | ||
103 | let def = create_struct_def(variant_name.clone(), &field_list, enum_ast.visibility()); | 106 | let def = create_struct_def(variant_name.clone(), &field_list, &enum_ast); |
104 | let start_offset = &variant.parent_enum().syntax().clone(); | 107 | let start_offset = &variant.parent_enum().syntax().clone(); |
105 | ted::insert_raw(ted::Position::before(start_offset), def.syntax()); | 108 | ted::insert_raw(ted::Position::before(start_offset), def.syntax()); |
106 | ted::insert_raw(ted::Position::before(start_offset), &make::tokens::blank_line()); | 109 | ted::insert_raw(ted::Position::before(start_offset), &make::tokens::blank_line()); |
107 | 110 | ||
108 | update_variant(&variant); | 111 | update_variant(&variant, enum_ast.generic_param_list()); |
109 | }, | 112 | }, |
110 | ) | 113 | ) |
111 | } | 114 | } |
@@ -149,7 +152,7 @@ fn existing_definition(db: &RootDatabase, variant_name: &ast::Name, variant: &Va | |||
149 | fn create_struct_def( | 152 | fn create_struct_def( |
150 | variant_name: ast::Name, | 153 | variant_name: ast::Name, |
151 | field_list: &Either<ast::RecordFieldList, ast::TupleFieldList>, | 154 | field_list: &Either<ast::RecordFieldList, ast::TupleFieldList>, |
152 | visibility: Option<ast::Visibility>, | 155 | enum_: &ast::Enum, |
153 | ) -> ast::Struct { | 156 | ) -> ast::Struct { |
154 | let pub_vis = make::visibility_pub(); | 157 | let pub_vis = make::visibility_pub(); |
155 | 158 | ||
@@ -184,12 +187,38 @@ fn create_struct_def( | |||
184 | } | 187 | } |
185 | }; | 188 | }; |
186 | 189 | ||
187 | make::struct_(visibility, variant_name, None, field_list).clone_for_update() | 190 | // FIXME: This uses all the generic params of the enum, but the variant might not use all of them. |
191 | let strukt = | ||
192 | make::struct_(enum_.visibility(), variant_name, enum_.generic_param_list(), field_list) | ||
193 | .clone_for_update(); | ||
194 | |||
195 | // copy attributes | ||
196 | ted::insert_all( | ||
197 | Position::first_child_of(strukt.syntax()), | ||
198 | enum_.attrs().map(|it| it.syntax().clone_for_update().into()).collect(), | ||
199 | ); | ||
200 | strukt | ||
188 | } | 201 | } |
189 | 202 | ||
190 | fn update_variant(variant: &ast::Variant) -> Option<()> { | 203 | fn update_variant(variant: &ast::Variant, generic: Option<ast::GenericParamList>) -> Option<()> { |
191 | let name = variant.name()?; | 204 | let name = variant.name()?; |
192 | let tuple_field = make::tuple_field(None, make::ty(&name.text())); | 205 | let ty = match generic { |
206 | // FIXME: This uses all the generic params of the enum, but the variant might not use all of them. | ||
207 | Some(gpl) => { | ||
208 | let gpl = gpl.clone_for_update(); | ||
209 | gpl.generic_params().for_each(|gp| { | ||
210 | match gp { | ||
211 | ast::GenericParam::LifetimeParam(it) => it.type_bound_list(), | ||
212 | ast::GenericParam::TypeParam(it) => it.type_bound_list(), | ||
213 | ast::GenericParam::ConstParam(_) => return, | ||
214 | } | ||
215 | .map(|it| it.remove()); | ||
216 | }); | ||
217 | make::ty(&format!("{}<{}>", name.text(), gpl.generic_params().join(", "))) | ||
218 | } | ||
219 | None => make::ty(&name.text()), | ||
220 | }; | ||
221 | let tuple_field = make::tuple_field(None, ty); | ||
193 | let replacement = make::variant( | 222 | let replacement = make::variant( |
194 | name, | 223 | name, |
195 | Some(ast::FieldList::TupleFieldList(make::tuple_field_list(iter::once(tuple_field)))), | 224 | Some(ast::FieldList::TupleFieldList(make::tuple_field_list(iter::once(tuple_field)))), |
@@ -208,18 +237,17 @@ fn apply_references( | |||
208 | if let Some((scope, path)) = import { | 237 | if let Some((scope, path)) = import { |
209 | insert_use(&scope, mod_path_to_ast(&path), insert_use_cfg); | 238 | insert_use(&scope, mod_path_to_ast(&path), insert_use_cfg); |
210 | } | 239 | } |
211 | ted::insert_raw( | 240 | // deep clone to prevent cycle |
212 | ted::Position::before(segment.syntax()), | 241 | let path = make::path_from_segments(iter::once(segment.clone_subtree()), false); |
213 | make::path_from_text(&format!("{}", segment)).clone_for_update().syntax(), | 242 | ted::insert_raw(ted::Position::before(segment.syntax()), path.clone_for_update().syntax()); |
214 | ); | ||
215 | ted::insert_raw(ted::Position::before(segment.syntax()), make::token(T!['('])); | 243 | ted::insert_raw(ted::Position::before(segment.syntax()), make::token(T!['('])); |
216 | ted::insert_raw(ted::Position::after(&node), make::token(T![')'])); | 244 | ted::insert_raw(ted::Position::after(&node), make::token(T![')'])); |
217 | } | 245 | } |
218 | 246 | ||
219 | fn process_references( | 247 | fn process_references( |
220 | ctx: &AssistContext, | 248 | ctx: &AssistContext, |
249 | builder: &mut AssistBuilder, | ||
221 | visited_modules: &mut FxHashSet<Module>, | 250 | visited_modules: &mut FxHashSet<Module>, |
222 | source_file: &SyntaxNode, | ||
223 | enum_module_def: &ModuleDef, | 251 | enum_module_def: &ModuleDef, |
224 | variant_hir_name: &Name, | 252 | variant_hir_name: &Name, |
225 | refs: Vec<FileReference>, | 253 | refs: Vec<FileReference>, |
@@ -228,8 +256,9 @@ fn process_references( | |||
228 | // and corresponding nodes up front | 256 | // and corresponding nodes up front |
229 | refs.into_iter() | 257 | refs.into_iter() |
230 | .flat_map(|reference| { | 258 | .flat_map(|reference| { |
231 | let (segment, scope_node, module) = | 259 | let (segment, scope_node, module) = reference_to_node(&ctx.sema, reference)?; |
232 | reference_to_node(&ctx.sema, source_file, reference)?; | 260 | let segment = builder.make_mut(segment); |
261 | let scope_node = builder.make_syntax_mut(scope_node); | ||
233 | if !visited_modules.contains(&module) { | 262 | if !visited_modules.contains(&module) { |
234 | let mod_path = module.find_use_path_prefixed( | 263 | let mod_path = module.find_use_path_prefixed( |
235 | ctx.sema.db, | 264 | ctx.sema.db, |
@@ -251,23 +280,22 @@ fn process_references( | |||
251 | 280 | ||
252 | fn reference_to_node( | 281 | fn reference_to_node( |
253 | sema: &hir::Semantics<RootDatabase>, | 282 | sema: &hir::Semantics<RootDatabase>, |
254 | source_file: &SyntaxNode, | ||
255 | reference: FileReference, | 283 | reference: FileReference, |
256 | ) -> Option<(ast::PathSegment, SyntaxNode, hir::Module)> { | 284 | ) -> Option<(ast::PathSegment, SyntaxNode, hir::Module)> { |
257 | let offset = reference.range.start(); | 285 | let segment = |
258 | if let Some(path_expr) = find_node_at_offset::<ast::PathExpr>(source_file, offset) { | 286 | reference.name.as_name_ref()?.syntax().parent().and_then(ast::PathSegment::cast)?; |
259 | // tuple variant | 287 | let parent = segment.parent_path().syntax().parent()?; |
260 | Some((path_expr.path()?.segment()?, path_expr.syntax().parent()?)) | 288 | let expr_or_pat = match_ast! { |
261 | } else if let Some(record_expr) = find_node_at_offset::<ast::RecordExpr>(source_file, offset) { | 289 | match parent { |
262 | // record variant | 290 | ast::PathExpr(_it) => parent.parent()?, |
263 | Some((record_expr.path()?.segment()?, record_expr.syntax().clone())) | 291 | ast::RecordExpr(_it) => parent, |
264 | } else { | 292 | ast::TupleStructPat(_it) => parent, |
265 | None | 293 | ast::RecordPat(_it) => parent, |
266 | } | 294 | _ => return None, |
267 | .and_then(|(segment, expr)| { | 295 | } |
268 | let module = sema.scope(&expr).module()?; | 296 | }; |
269 | Some((segment, expr, module)) | 297 | let module = sema.scope(&expr_or_pat).module()?; |
270 | }) | 298 | Some((segment, expr_or_pat, module)) |
271 | } | 299 | } |
272 | 300 | ||
273 | #[cfg(test)] | 301 | #[cfg(test)] |
@@ -278,6 +306,12 @@ mod tests { | |||
278 | 306 | ||
279 | use super::*; | 307 | use super::*; |
280 | 308 | ||
309 | fn check_not_applicable(ra_fixture: &str) { | ||
310 | let fixture = | ||
311 | format!("//- /main.rs crate:main deps:core\n{}\n{}", ra_fixture, FamousDefs::FIXTURE); | ||
312 | check_assist_not_applicable(extract_struct_from_enum_variant, &fixture) | ||
313 | } | ||
314 | |||
281 | #[test] | 315 | #[test] |
282 | fn test_extract_struct_several_fields_tuple() { | 316 | fn test_extract_struct_several_fields_tuple() { |
283 | check_assist( | 317 | check_assist( |
@@ -312,6 +346,32 @@ enum A { One(One) }"#, | |||
312 | } | 346 | } |
313 | 347 | ||
314 | #[test] | 348 | #[test] |
349 | fn test_extract_struct_carries_over_generics() { | ||
350 | check_assist( | ||
351 | extract_struct_from_enum_variant, | ||
352 | r"enum En<T> { Var { a: T$0 } }", | ||
353 | r#"struct Var<T>{ pub a: T } | ||
354 | |||
355 | enum En<T> { Var(Var<T>) }"#, | ||
356 | ); | ||
357 | } | ||
358 | |||
359 | #[test] | ||
360 | fn test_extract_struct_carries_over_attributes() { | ||
361 | check_assist( | ||
362 | extract_struct_from_enum_variant, | ||
363 | r#"#[derive(Debug)] | ||
364 | #[derive(Clone)] | ||
365 | enum Enum { Variant{ field: u32$0 } }"#, | ||
366 | r#"#[derive(Debug)]#[derive(Clone)] struct Variant{ pub field: u32 } | ||
367 | |||
368 | #[derive(Debug)] | ||
369 | #[derive(Clone)] | ||
370 | enum Enum { Variant(Variant) }"#, | ||
371 | ); | ||
372 | } | ||
373 | |||
374 | #[test] | ||
315 | fn test_extract_struct_keep_comments_and_attrs_one_field_named() { | 375 | fn test_extract_struct_keep_comments_and_attrs_one_field_named() { |
316 | check_assist( | 376 | check_assist( |
317 | extract_struct_from_enum_variant, | 377 | extract_struct_from_enum_variant, |
@@ -496,7 +556,7 @@ enum E { | |||
496 | } | 556 | } |
497 | 557 | ||
498 | fn f() { | 558 | fn f() { |
499 | let e = E::V { i: 9, j: 2 }; | 559 | let E::V { i, j } = E::V { i: 9, j: 2 }; |
500 | } | 560 | } |
501 | "#, | 561 | "#, |
502 | r#" | 562 | r#" |
@@ -507,7 +567,34 @@ enum E { | |||
507 | } | 567 | } |
508 | 568 | ||
509 | fn f() { | 569 | fn f() { |
510 | let e = E::V(V { i: 9, j: 2 }); | 570 | let E::V(V { i, j }) = E::V(V { i: 9, j: 2 }); |
571 | } | ||
572 | "#, | ||
573 | ) | ||
574 | } | ||
575 | |||
576 | #[test] | ||
577 | fn extract_record_fix_references2() { | ||
578 | check_assist( | ||
579 | extract_struct_from_enum_variant, | ||
580 | r#" | ||
581 | enum E { | ||
582 | $0V(i32, i32) | ||
583 | } | ||
584 | |||
585 | fn f() { | ||
586 | let E::V(i, j) = E::V(9, 2); | ||
587 | } | ||
588 | "#, | ||
589 | r#" | ||
590 | struct V(pub i32, pub i32); | ||
591 | |||
592 | enum E { | ||
593 | V(V) | ||
594 | } | ||
595 | |||
596 | fn f() { | ||
597 | let E::V(V(i, j)) = E::V(V(9, 2)); | ||
511 | } | 598 | } |
512 | "#, | 599 | "#, |
513 | ) | 600 | ) |
@@ -610,12 +697,6 @@ fn foo() { | |||
610 | ); | 697 | ); |
611 | } | 698 | } |
612 | 699 | ||
613 | fn check_not_applicable(ra_fixture: &str) { | ||
614 | let fixture = | ||
615 | format!("//- /main.rs crate:main deps:core\n{}\n{}", ra_fixture, FamousDefs::FIXTURE); | ||
616 | check_assist_not_applicable(extract_struct_from_enum_variant, &fixture) | ||
617 | } | ||
618 | |||
619 | #[test] | 700 | #[test] |
620 | fn test_extract_enum_not_applicable_for_element_with_no_fields() { | 701 | fn test_extract_enum_not_applicable_for_element_with_no_fields() { |
621 | check_not_applicable("enum A { $0One }"); | 702 | check_not_applicable("enum A { $0One }"); |
diff --git a/crates/ide_assists/src/handlers/extract_type_alias.rs b/crates/ide_assists/src/handlers/extract_type_alias.rs index 442a209b9..4bccf5984 100644 --- a/crates/ide_assists/src/handlers/extract_type_alias.rs +++ b/crates/ide_assists/src/handlers/extract_type_alias.rs | |||
@@ -1,4 +1,7 @@ | |||
1 | use syntax::ast::{self, AstNode}; | 1 | use syntax::{ |
2 | ast::{self, edit::IndentLevel, AstNode}, | ||
3 | match_ast, | ||
4 | }; | ||
2 | 5 | ||
3 | use crate::{AssistContext, AssistId, AssistKind, Assists}; | 6 | use crate::{AssistContext, AssistId, AssistKind, Assists}; |
4 | 7 | ||
@@ -25,7 +28,15 @@ pub(crate) fn extract_type_alias(acc: &mut Assists, ctx: &AssistContext) -> Opti | |||
25 | } | 28 | } |
26 | 29 | ||
27 | let node = ctx.find_node_at_range::<ast::Type>()?; | 30 | let node = ctx.find_node_at_range::<ast::Type>()?; |
28 | let insert = ctx.find_node_at_offset::<ast::Item>()?.syntax().text_range().start(); | 31 | let item = ctx.find_node_at_offset::<ast::Item>()?; |
32 | let insert = match_ast! { | ||
33 | match (item.syntax().parent()?) { | ||
34 | ast::AssocItemList(it) => it.syntax().parent()?.clone(), | ||
35 | _ => item.syntax().clone(), | ||
36 | } | ||
37 | }; | ||
38 | let indent = IndentLevel::from_node(&insert); | ||
39 | let insert = insert.text_range().start(); | ||
29 | let target = node.syntax().text_range(); | 40 | let target = node.syntax().text_range(); |
30 | 41 | ||
31 | acc.add( | 42 | acc.add( |
@@ -37,10 +48,14 @@ pub(crate) fn extract_type_alias(acc: &mut Assists, ctx: &AssistContext) -> Opti | |||
37 | builder.replace(target, "Type"); | 48 | builder.replace(target, "Type"); |
38 | match ctx.config.snippet_cap { | 49 | match ctx.config.snippet_cap { |
39 | Some(cap) => { | 50 | Some(cap) => { |
40 | builder.insert_snippet(cap, insert, format!("type $0Type = {};\n\n", node)); | 51 | builder.insert_snippet( |
52 | cap, | ||
53 | insert, | ||
54 | format!("type $0Type = {};\n\n{}", node, indent), | ||
55 | ); | ||
41 | } | 56 | } |
42 | None => { | 57 | None => { |
43 | builder.insert(insert, format!("type Type = {};\n\n", node)); | 58 | builder.insert(insert, format!("type Type = {};\n\n{}", node, indent)); |
44 | } | 59 | } |
45 | } | 60 | } |
46 | }, | 61 | }, |
@@ -146,4 +161,59 @@ struct S { | |||
146 | "#, | 161 | "#, |
147 | ); | 162 | ); |
148 | } | 163 | } |
164 | |||
165 | #[test] | ||
166 | fn extract_from_impl_or_trait() { | ||
167 | // When invoked in an impl/trait, extracted type alias should be placed next to the | ||
168 | // impl/trait, not inside. | ||
169 | check_assist( | ||
170 | extract_type_alias, | ||
171 | r#" | ||
172 | impl S { | ||
173 | fn f() -> $0(u8, u8)$0 {} | ||
174 | } | ||
175 | "#, | ||
176 | r#" | ||
177 | type $0Type = (u8, u8); | ||
178 | |||
179 | impl S { | ||
180 | fn f() -> Type {} | ||
181 | } | ||
182 | "#, | ||
183 | ); | ||
184 | check_assist( | ||
185 | extract_type_alias, | ||
186 | r#" | ||
187 | trait Tr { | ||
188 | fn f() -> $0(u8, u8)$0 {} | ||
189 | } | ||
190 | "#, | ||
191 | r#" | ||
192 | type $0Type = (u8, u8); | ||
193 | |||
194 | trait Tr { | ||
195 | fn f() -> Type {} | ||
196 | } | ||
197 | "#, | ||
198 | ); | ||
199 | } | ||
200 | |||
201 | #[test] | ||
202 | fn indentation() { | ||
203 | check_assist( | ||
204 | extract_type_alias, | ||
205 | r#" | ||
206 | mod m { | ||
207 | fn f() -> $0u8$0 {} | ||
208 | } | ||
209 | "#, | ||
210 | r#" | ||
211 | mod m { | ||
212 | type $0Type = u8; | ||
213 | |||
214 | fn f() -> Type {} | ||
215 | } | ||
216 | "#, | ||
217 | ); | ||
218 | } | ||
149 | } | 219 | } |
diff --git a/crates/ide_assists/src/handlers/extract_variable.rs b/crates/ide_assists/src/handlers/extract_variable.rs index ae084c86c..46b54a5f5 100644 --- a/crates/ide_assists/src/handlers/extract_variable.rs +++ b/crates/ide_assists/src/handlers/extract_variable.rs | |||
@@ -36,6 +36,11 @@ pub(crate) fn extract_variable(acc: &mut Assists, ctx: &AssistContext) -> Option | |||
36 | return None; | 36 | return None; |
37 | } | 37 | } |
38 | let to_extract = node.ancestors().find_map(valid_target_expr)?; | 38 | let to_extract = node.ancestors().find_map(valid_target_expr)?; |
39 | if let Some(ty) = ctx.sema.type_of_expr(&to_extract) { | ||
40 | if ty.is_unit() { | ||
41 | return None; | ||
42 | } | ||
43 | } | ||
39 | let anchor = Anchor::from(&to_extract)?; | 44 | let anchor = Anchor::from(&to_extract)?; |
40 | let indent = anchor.syntax().prev_sibling_or_token()?.as_token()?.clone(); | 45 | let indent = anchor.syntax().prev_sibling_or_token()?.as_token()?.clone(); |
41 | let target = to_extract.syntax().text_range(); | 46 | let target = to_extract.syntax().text_range(); |
@@ -275,15 +280,23 @@ fn foo() { | |||
275 | check_assist( | 280 | check_assist( |
276 | extract_variable, | 281 | extract_variable, |
277 | r#" | 282 | r#" |
278 | fn foo() { | 283 | fn foo() -> i32 { |
279 | $0bar(1 + 1)$0 | 284 | $0bar(1 + 1)$0 |
280 | } | 285 | } |
286 | |||
287 | fn bar(i: i32) -> i32 { | ||
288 | i | ||
289 | } | ||
281 | "#, | 290 | "#, |
282 | r#" | 291 | r#" |
283 | fn foo() { | 292 | fn foo() -> i32 { |
284 | let $0bar = bar(1 + 1); | 293 | let $0bar = bar(1 + 1); |
285 | bar | 294 | bar |
286 | } | 295 | } |
296 | |||
297 | fn bar(i: i32) -> i32 { | ||
298 | i | ||
299 | } | ||
287 | "#, | 300 | "#, |
288 | ) | 301 | ) |
289 | } | 302 | } |
@@ -796,6 +809,22 @@ fn foo() { | |||
796 | check_assist_not_applicable(extract_variable, "fn main() { loop { $0break$0; }; }"); | 809 | check_assist_not_applicable(extract_variable, "fn main() { loop { $0break$0; }; }"); |
797 | } | 810 | } |
798 | 811 | ||
812 | #[test] | ||
813 | fn test_extract_var_unit_expr_not_applicable() { | ||
814 | check_assist_not_applicable( | ||
815 | extract_variable, | ||
816 | r#" | ||
817 | fn foo() { | ||
818 | let mut i = 3; | ||
819 | $0if i >= 0 { | ||
820 | i += 1; | ||
821 | } else { | ||
822 | i -= 1; | ||
823 | }$0 | ||
824 | }"#, | ||
825 | ); | ||
826 | } | ||
827 | |||
799 | // FIXME: This is not quite correct, but good enough(tm) for the sorting heuristic | 828 | // FIXME: This is not quite correct, but good enough(tm) for the sorting heuristic |
800 | #[test] | 829 | #[test] |
801 | fn extract_var_target() { | 830 | fn extract_var_target() { |
diff --git a/crates/ide_completion/src/completions/dot.rs b/crates/ide_completion/src/completions/dot.rs index 302c9ccbd..e0a7021fd 100644 --- a/crates/ide_completion/src/completions/dot.rs +++ b/crates/ide_completion/src/completions/dot.rs | |||
@@ -8,7 +8,7 @@ use crate::{context::CompletionContext, Completions}; | |||
8 | 8 | ||
9 | /// Complete dot accesses, i.e. fields or methods. | 9 | /// Complete dot accesses, i.e. fields or methods. |
10 | pub(crate) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) { | 10 | pub(crate) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) { |
11 | let dot_receiver = match &ctx.dot_receiver { | 11 | let dot_receiver = match ctx.dot_receiver() { |
12 | Some(expr) => expr, | 12 | Some(expr) => expr, |
13 | _ => return complete_undotted_self(acc, ctx), | 13 | _ => return complete_undotted_self(acc, ctx), |
14 | }; | 14 | }; |
@@ -30,7 +30,10 @@ pub(crate) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) { | |||
30 | } | 30 | } |
31 | 31 | ||
32 | fn complete_undotted_self(acc: &mut Completions, ctx: &CompletionContext) { | 32 | fn complete_undotted_self(acc: &mut Completions, ctx: &CompletionContext) { |
33 | if !ctx.is_trivial_path || !ctx.config.enable_self_on_the_fly { | 33 | if !ctx.config.enable_self_on_the_fly { |
34 | return; | ||
35 | } | ||
36 | if !ctx.is_trivial_path || ctx.is_path_disallowed() { | ||
34 | return; | 37 | return; |
35 | } | 38 | } |
36 | ctx.scope.process_all_names(&mut |name, def| { | 39 | ctx.scope.process_all_names(&mut |name, def| { |
diff --git a/crates/ide_completion/src/completions/flyimport.rs b/crates/ide_completion/src/completions/flyimport.rs index df27e7a84..d72bf13d3 100644 --- a/crates/ide_completion/src/completions/flyimport.rs +++ b/crates/ide_completion/src/completions/flyimport.rs | |||
@@ -162,19 +162,19 @@ pub(crate) fn position_for_import<'a>( | |||
162 | Some(match import_candidate { | 162 | Some(match import_candidate { |
163 | Some(ImportCandidate::Path(_)) => ctx.name_ref_syntax.as_ref()?.syntax(), | 163 | Some(ImportCandidate::Path(_)) => ctx.name_ref_syntax.as_ref()?.syntax(), |
164 | Some(ImportCandidate::TraitAssocItem(_)) => ctx.path_qual.as_ref()?.syntax(), | 164 | Some(ImportCandidate::TraitAssocItem(_)) => ctx.path_qual.as_ref()?.syntax(), |
165 | Some(ImportCandidate::TraitMethod(_)) => ctx.dot_receiver.as_ref()?.syntax(), | 165 | Some(ImportCandidate::TraitMethod(_)) => ctx.dot_receiver()?.syntax(), |
166 | None => ctx | 166 | None => ctx |
167 | .name_ref_syntax | 167 | .name_ref_syntax |
168 | .as_ref() | 168 | .as_ref() |
169 | .map(|name_ref| name_ref.syntax()) | 169 | .map(|name_ref| name_ref.syntax()) |
170 | .or_else(|| ctx.path_qual.as_ref().map(|path| path.syntax())) | 170 | .or_else(|| ctx.path_qual.as_ref().map(|path| path.syntax())) |
171 | .or_else(|| ctx.dot_receiver.as_ref().map(|expr| expr.syntax()))?, | 171 | .or_else(|| ctx.dot_receiver().map(|expr| expr.syntax()))?, |
172 | }) | 172 | }) |
173 | } | 173 | } |
174 | 174 | ||
175 | fn import_assets(ctx: &CompletionContext, fuzzy_name: String) -> Option<ImportAssets> { | 175 | fn import_assets(ctx: &CompletionContext, fuzzy_name: String) -> Option<ImportAssets> { |
176 | let current_module = ctx.scope.module()?; | 176 | let current_module = ctx.scope.module()?; |
177 | if let Some(dot_receiver) = &ctx.dot_receiver { | 177 | if let Some(dot_receiver) = ctx.dot_receiver() { |
178 | ImportAssets::for_fuzzy_method_call( | 178 | ImportAssets::for_fuzzy_method_call( |
179 | current_module, | 179 | current_module, |
180 | ctx.sema.type_of_expr(dot_receiver)?, | 180 | ctx.sema.type_of_expr(dot_receiver)?, |
diff --git a/crates/ide_completion/src/completions/keyword.rs b/crates/ide_completion/src/completions/keyword.rs index 0d035c611..1a7a484a4 100644 --- a/crates/ide_completion/src/completions/keyword.rs +++ b/crates/ide_completion/src/completions/keyword.rs | |||
@@ -31,7 +31,7 @@ pub(crate) fn complete_use_tree_keyword(acc: &mut Completions, ctx: &CompletionC | |||
31 | } | 31 | } |
32 | 32 | ||
33 | // Suggest .await syntax for types that implement Future trait | 33 | // Suggest .await syntax for types that implement Future trait |
34 | if let Some(receiver) = &ctx.dot_receiver { | 34 | if let Some(receiver) = ctx.dot_receiver() { |
35 | if let Some(ty) = ctx.sema.type_of_expr(receiver) { | 35 | if let Some(ty) = ctx.sema.type_of_expr(receiver) { |
36 | if ty.impls_future(ctx.db) { | 36 | if ty.impls_future(ctx.db) { |
37 | let mut item = kw_completion("await"); | 37 | let mut item = kw_completion("await"); |
diff --git a/crates/ide_completion/src/completions/macro_in_item_position.rs b/crates/ide_completion/src/completions/macro_in_item_position.rs index 202e71215..781b96ff1 100644 --- a/crates/ide_completion/src/completions/macro_in_item_position.rs +++ b/crates/ide_completion/src/completions/macro_in_item_position.rs | |||
@@ -5,7 +5,7 @@ use crate::{CompletionContext, Completions}; | |||
5 | // Ideally this should be removed and moved into `(un)qualified_path` respectively | 5 | // Ideally this should be removed and moved into `(un)qualified_path` respectively |
6 | pub(crate) fn complete_macro_in_item_position(acc: &mut Completions, ctx: &CompletionContext) { | 6 | pub(crate) fn complete_macro_in_item_position(acc: &mut Completions, ctx: &CompletionContext) { |
7 | // Show only macros in top level. | 7 | // Show only macros in top level. |
8 | if !ctx.is_new_item { | 8 | if !ctx.expects_item() { |
9 | return; | 9 | return; |
10 | } | 10 | } |
11 | 11 | ||
diff --git a/crates/ide_completion/src/completions/postfix.rs b/crates/ide_completion/src/completions/postfix.rs index 962aaf0df..86bbb58e2 100644 --- a/crates/ide_completion/src/completions/postfix.rs +++ b/crates/ide_completion/src/completions/postfix.rs | |||
@@ -14,6 +14,7 @@ use crate::{ | |||
14 | completions::postfix::format_like::add_format_like_completions, | 14 | completions::postfix::format_like::add_format_like_completions, |
15 | context::CompletionContext, | 15 | context::CompletionContext, |
16 | item::{Builder, CompletionKind}, | 16 | item::{Builder, CompletionKind}, |
17 | patterns::ImmediateLocation, | ||
17 | CompletionItem, CompletionItemKind, Completions, | 18 | CompletionItem, CompletionItemKind, Completions, |
18 | }; | 19 | }; |
19 | 20 | ||
@@ -22,13 +23,16 @@ pub(crate) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) { | |||
22 | return; | 23 | return; |
23 | } | 24 | } |
24 | 25 | ||
25 | let dot_receiver = match &ctx.dot_receiver { | 26 | let (dot_receiver, receiver_is_ambiguous_float_literal) = match &ctx.completion_location { |
26 | Some(it) => it, | 27 | Some(ImmediateLocation::MethodCall { receiver: Some(it) }) => (it, false), |
27 | None => return, | 28 | Some(ImmediateLocation::FieldAccess { |
29 | receiver: Some(it), | ||
30 | receiver_is_ambiguous_float_literal, | ||
31 | }) => (it, *receiver_is_ambiguous_float_literal), | ||
32 | _ => return, | ||
28 | }; | 33 | }; |
29 | 34 | ||
30 | let receiver_text = | 35 | let receiver_text = get_receiver_text(dot_receiver, receiver_is_ambiguous_float_literal); |
31 | get_receiver_text(dot_receiver, ctx.dot_receiver_is_ambiguous_float_literal); | ||
32 | 36 | ||
33 | let receiver_ty = match ctx.sema.type_of_expr(&dot_receiver) { | 37 | let receiver_ty = match ctx.sema.type_of_expr(&dot_receiver) { |
34 | Some(it) => it, | 38 | Some(it) => it, |
@@ -123,8 +127,7 @@ pub(crate) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) { | |||
123 | // The rest of the postfix completions create an expression that moves an argument, | 127 | // The rest of the postfix completions create an expression that moves an argument, |
124 | // so it's better to consider references now to avoid breaking the compilation | 128 | // so it's better to consider references now to avoid breaking the compilation |
125 | let dot_receiver = include_references(dot_receiver); | 129 | let dot_receiver = include_references(dot_receiver); |
126 | let receiver_text = | 130 | let receiver_text = get_receiver_text(&dot_receiver, receiver_is_ambiguous_float_literal); |
127 | get_receiver_text(&dot_receiver, ctx.dot_receiver_is_ambiguous_float_literal); | ||
128 | 131 | ||
129 | match try_enum { | 132 | match try_enum { |
130 | Some(try_enum) => match try_enum { | 133 | Some(try_enum) => match try_enum { |
diff --git a/crates/ide_completion/src/completions/snippet.rs b/crates/ide_completion/src/completions/snippet.rs index defc25b00..6e6a6eb92 100644 --- a/crates/ide_completion/src/completions/snippet.rs +++ b/crates/ide_completion/src/completions/snippet.rs | |||
@@ -29,7 +29,7 @@ pub(crate) fn complete_expr_snippet(acc: &mut Completions, ctx: &CompletionConte | |||
29 | } | 29 | } |
30 | 30 | ||
31 | pub(crate) fn complete_item_snippet(acc: &mut Completions, ctx: &CompletionContext) { | 31 | pub(crate) fn complete_item_snippet(acc: &mut Completions, ctx: &CompletionContext) { |
32 | if !ctx.is_new_item { | 32 | if !ctx.expects_item() { |
33 | return; | 33 | return; |
34 | } | 34 | } |
35 | let cap = match ctx.config.snippet_cap { | 35 | let cap = match ctx.config.snippet_cap { |
diff --git a/crates/ide_completion/src/completions/unqualified_path.rs b/crates/ide_completion/src/completions/unqualified_path.rs index 20188a7dd..bd955aa85 100644 --- a/crates/ide_completion/src/completions/unqualified_path.rs +++ b/crates/ide_completion/src/completions/unqualified_path.rs | |||
@@ -385,10 +385,11 @@ fn foo() { | |||
385 | fn foo() { let x: $0 } | 385 | fn foo() { let x: $0 } |
386 | 386 | ||
387 | //- /std/lib.rs crate:std | 387 | //- /std/lib.rs crate:std |
388 | #[prelude_import] | 388 | pub mod prelude { |
389 | use prelude::*; | 389 | pub mod rust_2018 { |
390 | 390 | pub struct Option; | |
391 | mod prelude { struct Option; } | 391 | } |
392 | } | ||
392 | "#, | 393 | "#, |
393 | expect![[r#" | 394 | expect![[r#" |
394 | fn foo() fn() | 395 | fn foo() fn() |
@@ -406,12 +407,10 @@ mod prelude { struct Option; } | |||
406 | fn f() {$0} | 407 | fn f() {$0} |
407 | 408 | ||
408 | //- /std/lib.rs crate:std | 409 | //- /std/lib.rs crate:std |
409 | #[prelude_import] | 410 | pub mod prelude { |
410 | pub use prelude::*; | 411 | pub mod rust_2018 { |
411 | 412 | pub use crate::concat; | |
412 | #[macro_use] | 413 | } |
413 | mod prelude { | ||
414 | pub use crate::concat; | ||
415 | } | 414 | } |
416 | 415 | ||
417 | mod macros { | 416 | mod macros { |
@@ -436,16 +435,18 @@ mod macros { | |||
436 | fn foo() { let x: $0 } | 435 | fn foo() { let x: $0 } |
437 | 436 | ||
438 | //- /core/lib.rs crate:core | 437 | //- /core/lib.rs crate:core |
439 | #[prelude_import] | 438 | pub mod prelude { |
440 | use prelude::*; | 439 | pub mod rust_2018 { |
441 | 440 | pub struct Option; | |
442 | mod prelude { struct Option; } | 441 | } |
442 | } | ||
443 | 443 | ||
444 | //- /std/lib.rs crate:std deps:core | 444 | //- /std/lib.rs crate:std deps:core |
445 | #[prelude_import] | 445 | pub mod prelude { |
446 | use prelude::*; | 446 | pub mod rust_2018 { |
447 | 447 | pub struct String; | |
448 | mod prelude { struct String; } | 448 | } |
449 | } | ||
449 | "#, | 450 | "#, |
450 | expect![[r#" | 451 | expect![[r#" |
451 | fn foo() fn() | 452 | fn foo() fn() |
diff --git a/crates/ide_completion/src/context.rs b/crates/ide_completion/src/context.rs index 7c46c815d..6f685c02f 100644 --- a/crates/ide_completion/src/context.rs +++ b/crates/ide_completion/src/context.rs | |||
@@ -78,11 +78,6 @@ pub(crate) struct CompletionContext<'a> { | |||
78 | pub(super) can_be_stmt: bool, | 78 | pub(super) can_be_stmt: bool, |
79 | /// `true` if we expect an expression at the cursor position. | 79 | /// `true` if we expect an expression at the cursor position. |
80 | pub(super) is_expr: bool, | 80 | pub(super) is_expr: bool, |
81 | /// Something is typed at the "top" level, in module or impl/trait. | ||
82 | pub(super) is_new_item: bool, | ||
83 | /// The receiver if this is a field or method access, i.e. writing something.$0 | ||
84 | pub(super) dot_receiver: Option<ast::Expr>, | ||
85 | pub(super) dot_receiver_is_ambiguous_float_literal: bool, | ||
86 | /// If this is a call (method or function) in particular, i.e. the () are already there. | 81 | /// If this is a call (method or function) in particular, i.e. the () are already there. |
87 | pub(super) is_call: bool, | 82 | pub(super) is_call: bool, |
88 | /// Like `is_call`, but for tuple patterns. | 83 | /// Like `is_call`, but for tuple patterns. |
@@ -158,9 +153,6 @@ impl<'a> CompletionContext<'a> { | |||
158 | path_qual: None, | 153 | path_qual: None, |
159 | can_be_stmt: false, | 154 | can_be_stmt: false, |
160 | is_expr: false, | 155 | is_expr: false, |
161 | is_new_item: false, | ||
162 | dot_receiver: None, | ||
163 | dot_receiver_is_ambiguous_float_literal: false, | ||
164 | is_call: false, | 156 | is_call: false, |
165 | is_pattern_call: false, | 157 | is_pattern_call: false, |
166 | is_macro_call: false, | 158 | is_macro_call: false, |
@@ -255,6 +247,22 @@ impl<'a> CompletionContext<'a> { | |||
255 | ) | 247 | ) |
256 | } | 248 | } |
257 | 249 | ||
250 | pub(crate) fn has_dot_receiver(&self) -> bool { | ||
251 | matches!( | ||
252 | &self.completion_location, | ||
253 | Some(ImmediateLocation::FieldAccess { receiver, .. }) | Some(ImmediateLocation::MethodCall { receiver }) | ||
254 | if receiver.is_some() | ||
255 | ) | ||
256 | } | ||
257 | |||
258 | pub(crate) fn dot_receiver(&self) -> Option<&ast::Expr> { | ||
259 | match &self.completion_location { | ||
260 | Some(ImmediateLocation::MethodCall { receiver }) | ||
261 | | Some(ImmediateLocation::FieldAccess { receiver, .. }) => receiver.as_ref(), | ||
262 | _ => None, | ||
263 | } | ||
264 | } | ||
265 | |||
258 | pub(crate) fn expects_use_tree(&self) -> bool { | 266 | pub(crate) fn expects_use_tree(&self) -> bool { |
259 | matches!(self.completion_location, Some(ImmediateLocation::Use)) | 267 | matches!(self.completion_location, Some(ImmediateLocation::Use)) |
260 | } | 268 | } |
@@ -267,6 +275,7 @@ impl<'a> CompletionContext<'a> { | |||
267 | matches!(self.completion_location, Some(ImmediateLocation::ItemList)) | 275 | matches!(self.completion_location, Some(ImmediateLocation::ItemList)) |
268 | } | 276 | } |
269 | 277 | ||
278 | // fn expects_value(&self) -> bool { | ||
270 | pub(crate) fn expects_expression(&self) -> bool { | 279 | pub(crate) fn expects_expression(&self) -> bool { |
271 | self.is_expr | 280 | self.is_expr |
272 | } | 281 | } |
@@ -540,16 +549,7 @@ impl<'a> CompletionContext<'a> { | |||
540 | self.name_ref_syntax = | 549 | self.name_ref_syntax = |
541 | find_node_at_offset(original_file, name_ref.syntax().text_range().start()); | 550 | find_node_at_offset(original_file, name_ref.syntax().text_range().start()); |
542 | 551 | ||
543 | let name_range = name_ref.syntax().text_range(); | 552 | if matches!(self.completion_location, Some(ImmediateLocation::ItemList)) { |
544 | let top_node = name_ref | ||
545 | .syntax() | ||
546 | .ancestors() | ||
547 | .take_while(|it| it.text_range() == name_range) | ||
548 | .last() | ||
549 | .unwrap(); | ||
550 | |||
551 | if matches!(top_node.parent().map(|it| it.kind()), Some(SOURCE_FILE) | Some(ITEM_LIST)) { | ||
552 | self.is_new_item = true; | ||
553 | return; | 553 | return; |
554 | } | 554 | } |
555 | 555 | ||
@@ -623,33 +623,8 @@ impl<'a> CompletionContext<'a> { | |||
623 | .unwrap_or(false); | 623 | .unwrap_or(false); |
624 | self.is_expr = path.syntax().parent().and_then(ast::PathExpr::cast).is_some(); | 624 | self.is_expr = path.syntax().parent().and_then(ast::PathExpr::cast).is_some(); |
625 | } | 625 | } |
626 | 626 | self.is_call |= | |
627 | if let Some(field_expr) = ast::FieldExpr::cast(parent.clone()) { | 627 | matches!(self.completion_location, Some(ImmediateLocation::MethodCall { .. })); |
628 | // The receiver comes before the point of insertion of the fake | ||
629 | // ident, so it should have the same range in the non-modified file | ||
630 | self.dot_receiver = field_expr | ||
631 | .expr() | ||
632 | .map(|e| e.syntax().text_range()) | ||
633 | .and_then(|r| find_node_with_range(original_file, r)); | ||
634 | self.dot_receiver_is_ambiguous_float_literal = | ||
635 | if let Some(ast::Expr::Literal(l)) = &self.dot_receiver { | ||
636 | match l.kind() { | ||
637 | ast::LiteralKind::FloatNumber { .. } => l.token().text().ends_with('.'), | ||
638 | _ => false, | ||
639 | } | ||
640 | } else { | ||
641 | false | ||
642 | }; | ||
643 | } | ||
644 | |||
645 | if let Some(method_call_expr) = ast::MethodCallExpr::cast(parent) { | ||
646 | // As above | ||
647 | self.dot_receiver = method_call_expr | ||
648 | .receiver() | ||
649 | .map(|e| e.syntax().text_range()) | ||
650 | .and_then(|r| find_node_with_range(original_file, r)); | ||
651 | self.is_call = true; | ||
652 | } | ||
653 | } | 628 | } |
654 | } | 629 | } |
655 | 630 | ||
diff --git a/crates/ide_completion/src/patterns.rs b/crates/ide_completion/src/patterns.rs index 26516046b..080898aef 100644 --- a/crates/ide_completion/src/patterns.rs +++ b/crates/ide_completion/src/patterns.rs | |||
@@ -7,13 +7,13 @@ use syntax::{ | |||
7 | ast::{self, LoopBodyOwner}, | 7 | ast::{self, LoopBodyOwner}, |
8 | match_ast, AstNode, Direction, SyntaxElement, | 8 | match_ast, AstNode, Direction, SyntaxElement, |
9 | SyntaxKind::*, | 9 | SyntaxKind::*, |
10 | SyntaxNode, SyntaxToken, TextSize, T, | 10 | SyntaxNode, SyntaxToken, TextRange, TextSize, T, |
11 | }; | 11 | }; |
12 | 12 | ||
13 | #[cfg(test)] | 13 | #[cfg(test)] |
14 | use crate::test_utils::{check_pattern_is_applicable, check_pattern_is_not_applicable}; | 14 | use crate::test_utils::{check_pattern_is_applicable, check_pattern_is_not_applicable}; |
15 | 15 | ||
16 | /// Direct parent container of the cursor position | 16 | /// Immediate previous node to what we are completing. |
17 | #[derive(Copy, Clone, Debug, PartialEq, Eq)] | 17 | #[derive(Copy, Clone, Debug, PartialEq, Eq)] |
18 | pub(crate) enum ImmediatePrevSibling { | 18 | pub(crate) enum ImmediatePrevSibling { |
19 | IfExpr, | 19 | IfExpr, |
@@ -21,7 +21,7 @@ pub(crate) enum ImmediatePrevSibling { | |||
21 | ImplDefType, | 21 | ImplDefType, |
22 | } | 22 | } |
23 | 23 | ||
24 | /// Direct parent container of the cursor position | 24 | /// Direct parent "thing" of what we are currently completing. |
25 | #[derive(Clone, Debug, PartialEq, Eq)] | 25 | #[derive(Clone, Debug, PartialEq, Eq)] |
26 | pub(crate) enum ImmediateLocation { | 26 | pub(crate) enum ImmediateLocation { |
27 | Use, | 27 | Use, |
@@ -37,6 +37,15 @@ pub(crate) enum ImmediateLocation { | |||
37 | // Fake file ast node | 37 | // Fake file ast node |
38 | ModDeclaration(ast::Module), | 38 | ModDeclaration(ast::Module), |
39 | // Original file ast node | 39 | // Original file ast node |
40 | MethodCall { | ||
41 | receiver: Option<ast::Expr>, | ||
42 | }, | ||
43 | // Original file ast node | ||
44 | FieldAccess { | ||
45 | receiver: Option<ast::Expr>, | ||
46 | receiver_is_ambiguous_float_literal: bool, | ||
47 | }, | ||
48 | // Original file ast node | ||
40 | /// The record expr of the field name we are completing | 49 | /// The record expr of the field name we are completing |
41 | RecordExpr(ast::RecordExpr), | 50 | RecordExpr(ast::RecordExpr), |
42 | // Original file ast node | 51 | // Original file ast node |
@@ -164,12 +173,38 @@ pub(crate) fn determine_location( | |||
164 | Some(TRAIT) => ImmediateLocation::Trait, | 173 | Some(TRAIT) => ImmediateLocation::Trait, |
165 | _ => return None, | 174 | _ => return None, |
166 | }, | 175 | }, |
167 | ast::Module(it) => if it.item_list().is_none() { | 176 | ast::Module(it) => { |
177 | if it.item_list().is_none() { | ||
168 | ImmediateLocation::ModDeclaration(it) | 178 | ImmediateLocation::ModDeclaration(it) |
169 | } else { | 179 | } else { |
170 | return None | 180 | return None; |
181 | } | ||
171 | }, | 182 | }, |
172 | ast::Attr(it) => ImmediateLocation::Attribute(it), | 183 | ast::Attr(it) => ImmediateLocation::Attribute(it), |
184 | ast::FieldExpr(it) => { | ||
185 | let receiver = it | ||
186 | .expr() | ||
187 | .map(|e| e.syntax().text_range()) | ||
188 | .and_then(|r| find_node_with_range(original_file, r)); | ||
189 | let receiver_is_ambiguous_float_literal = if let Some(ast::Expr::Literal(l)) = &receiver { | ||
190 | match l.kind() { | ||
191 | ast::LiteralKind::FloatNumber { .. } => l.token().text().ends_with('.'), | ||
192 | _ => false, | ||
193 | } | ||
194 | } else { | ||
195 | false | ||
196 | }; | ||
197 | ImmediateLocation::FieldAccess { | ||
198 | receiver, | ||
199 | receiver_is_ambiguous_float_literal, | ||
200 | } | ||
201 | }, | ||
202 | ast::MethodCallExpr(it) => ImmediateLocation::MethodCall { | ||
203 | receiver: it | ||
204 | .receiver() | ||
205 | .map(|e| e.syntax().text_range()) | ||
206 | .and_then(|r| find_node_with_range(original_file, r)), | ||
207 | }, | ||
173 | _ => return None, | 208 | _ => return None, |
174 | } | 209 | } |
175 | }; | 210 | }; |
@@ -194,6 +229,10 @@ fn maximize_name_ref(name_ref: &ast::NameRef) -> SyntaxNode { | |||
194 | name_ref.syntax().clone() | 229 | name_ref.syntax().clone() |
195 | } | 230 | } |
196 | 231 | ||
232 | fn find_node_with_range<N: AstNode>(syntax: &SyntaxNode, range: TextRange) -> Option<N> { | ||
233 | syntax.covering_element(range).ancestors().find_map(N::cast) | ||
234 | } | ||
235 | |||
197 | pub(crate) fn inside_impl_trait_block(element: SyntaxElement) -> bool { | 236 | pub(crate) fn inside_impl_trait_block(element: SyntaxElement) -> bool { |
198 | // Here we search `impl` keyword up through the all ancestors, unlike in `has_impl_parent`, | 237 | // Here we search `impl` keyword up through the all ancestors, unlike in `has_impl_parent`, |
199 | // where we only check the first parent with different text range. | 238 | // where we only check the first parent with different text range. |
diff --git a/crates/ide_completion/src/render/function.rs b/crates/ide_completion/src/render/function.rs index 3ec77ca0f..1abeed96d 100644 --- a/crates/ide_completion/src/render/function.rs +++ b/crates/ide_completion/src/render/function.rs | |||
@@ -154,7 +154,7 @@ impl<'a> FunctionRender<'a> { | |||
154 | }; | 154 | }; |
155 | 155 | ||
156 | let mut params_pats = Vec::new(); | 156 | let mut params_pats = Vec::new(); |
157 | let params_ty = if self.ctx.completion.dot_receiver.is_some() || self.receiver.is_some() { | 157 | let params_ty = if self.ctx.completion.has_dot_receiver() || self.receiver.is_some() { |
158 | self.func.method_params(self.ctx.db()).unwrap_or_default() | 158 | self.func.method_params(self.ctx.db()).unwrap_or_default() |
159 | } else { | 159 | } else { |
160 | if let Some(s) = ast_params.self_param() { | 160 | if let Some(s) = ast_params.self_param() { |
diff --git a/crates/ide_db/src/helpers/famous_defs_fixture.rs b/crates/ide_db/src/helpers/famous_defs_fixture.rs index 29ae12dcf..312851966 100644 --- a/crates/ide_db/src/helpers/famous_defs_fixture.rs +++ b/crates/ide_db/src/helpers/famous_defs_fixture.rs | |||
@@ -128,17 +128,19 @@ pub mod option { | |||
128 | } | 128 | } |
129 | 129 | ||
130 | pub mod prelude { | 130 | pub mod prelude { |
131 | pub use crate::{ | 131 | pub mod rust_2018 { |
132 | cmp::Ord, | 132 | pub use crate::{ |
133 | convert::{From, Into}, | 133 | cmp::Ord, |
134 | default::Default, | 134 | convert::{From, Into}, |
135 | iter::{IntoIterator, Iterator}, | 135 | default::Default, |
136 | ops::{Fn, FnMut, FnOnce}, | 136 | iter::{IntoIterator, Iterator}, |
137 | option::Option::{self, *}, | 137 | ops::{Fn, FnMut, FnOnce}, |
138 | }; | 138 | option::Option::{self, *}, |
139 | }; | ||
140 | } | ||
139 | } | 141 | } |
140 | #[prelude_import] | 142 | #[prelude_import] |
141 | pub use prelude::*; | 143 | pub use prelude::rust_2018::*; |
142 | //- /libstd.rs crate:std deps:core | 144 | //- /libstd.rs crate:std deps:core |
143 | //! Signatures of traits, types and functions from the std lib for use in tests. | 145 | //! Signatures of traits, types and functions from the std lib for use in tests. |
144 | 146 | ||
@@ -148,4 +150,4 @@ mod return_keyword {} | |||
148 | /// Docs for prim_str | 150 | /// Docs for prim_str |
149 | mod prim_str {} | 151 | mod prim_str {} |
150 | 152 | ||
151 | pub use core::ops; \ No newline at end of file | 153 | pub use core::ops; |
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index ae78fd4f6..c33cdb740 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs | |||
@@ -92,6 +92,7 @@ config_data! { | |||
92 | checkOnSave_overrideCommand: Option<Vec<String>> = "null", | 92 | checkOnSave_overrideCommand: Option<Vec<String>> = "null", |
93 | 93 | ||
94 | /// Whether to add argument snippets when completing functions. | 94 | /// Whether to add argument snippets when completing functions. |
95 | /// Only applies when `#rust-analyzer.completion.addCallParenthesis#` is set. | ||
95 | completion_addCallArgumentSnippets: bool = "true", | 96 | completion_addCallArgumentSnippets: bool = "true", |
96 | /// Whether to add parenthesis when completing functions. | 97 | /// Whether to add parenthesis when completing functions. |
97 | completion_addCallParenthesis: bool = "true", | 98 | completion_addCallParenthesis: bool = "true", |
diff --git a/crates/syntax/src/ast/make.rs b/crates/syntax/src/ast/make.rs index 0cf170626..4c3c9661d 100644 --- a/crates/syntax/src/ast/make.rs +++ b/crates/syntax/src/ast/make.rs | |||
@@ -580,12 +580,11 @@ pub fn fn_( | |||
580 | pub fn struct_( | 580 | pub fn struct_( |
581 | visibility: Option<ast::Visibility>, | 581 | visibility: Option<ast::Visibility>, |
582 | strukt_name: ast::Name, | 582 | strukt_name: ast::Name, |
583 | type_params: Option<ast::GenericParamList>, | 583 | generic_param_list: Option<ast::GenericParamList>, |
584 | field_list: ast::FieldList, | 584 | field_list: ast::FieldList, |
585 | ) -> ast::Struct { | 585 | ) -> ast::Struct { |
586 | let semicolon = if matches!(field_list, ast::FieldList::TupleFieldList(_)) { ";" } else { "" }; | 586 | let semicolon = if matches!(field_list, ast::FieldList::TupleFieldList(_)) { ";" } else { "" }; |
587 | let type_params = | 587 | let type_params = generic_param_list.map_or_else(String::new, |it| it.to_string()); |
588 | if let Some(type_params) = type_params { format!("<{}>", type_params) } else { "".into() }; | ||
589 | let visibility = match visibility { | 588 | let visibility = match visibility { |
590 | None => String::new(), | 589 | None => String::new(), |
591 | Some(it) => format!("{} ", it), | 590 | Some(it) => format!("{} ", it), |