aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock11
-rw-r--r--crates/ra_hir/src/semantics.rs8
-rw-r--r--crates/ra_hir/src/source_analyzer.rs99
-rw-r--r--crates/ra_hir_def/src/body.rs4
-rw-r--r--crates/ra_hir_def/src/body/lower.rs16
-rw-r--r--crates/ra_hir_def/src/builtin_type.rs54
-rw-r--r--crates/ra_hir_def/src/diagnostics.rs2
-rw-r--r--crates/ra_hir_def/src/find_path.rs21
-rw-r--r--crates/ra_hir_expand/src/diagnostics.rs5
-rw-r--r--crates/ra_hir_ty/src/diagnostics.rs2
-rw-r--r--crates/ra_hir_ty/src/infer.rs4
-rw-r--r--crates/ra_hir_ty/src/infer/coerce.rs4
-rw-r--r--crates/ra_hir_ty/src/infer/unify.rs42
-rw-r--r--crates/ra_hir_ty/src/lib.rs4
-rw-r--r--crates/ra_hir_ty/src/lower.rs69
-rw-r--r--crates/ra_hir_ty/src/tests/regression.rs49
-rw-r--r--crates/ra_hir_ty/src/tests/traits.rs234
-rw-r--r--crates/ra_hir_ty/src/traits/chalk.rs10
-rw-r--r--crates/ra_ide/src/completion/complete_trait_impl.rs19
-rw-r--r--crates/ra_ide/src/completion/complete_unqualified_path.rs40
-rw-r--r--crates/ra_ide/src/diagnostics.rs72
-rw-r--r--crates/ra_ide/src/inlay_hints.rs11
-rw-r--r--crates/ra_ide/src/marks.rs1
-rw-r--r--crates/ra_ide/src/syntax_highlighting.rs3
-rw-r--r--crates/ra_ide/src/syntax_highlighting/tests.rs12
-rw-r--r--crates/ra_proc_macro_srv/Cargo.toml1
-rw-r--r--crates/ra_proc_macro_srv/src/dylib.rs77
-rw-r--r--crates/rust-analyzer/src/cli/load_cargo.rs4
-rw-r--r--crates/rust-analyzer/src/config.rs4
-rw-r--r--xtask/tests/tidy-tests/main.rs6
30 files changed, 705 insertions, 183 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 89a734c9b..3826ae1c6 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -676,6 +676,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
676checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" 676checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400"
677 677
678[[package]] 678[[package]]
679name = "memmap"
680version = "0.7.0"
681source = "registry+https://github.com/rust-lang/crates.io-index"
682checksum = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b"
683dependencies = [
684 "libc",
685 "winapi 0.3.8",
686]
687
688[[package]]
679name = "memoffset" 689name = "memoffset"
680version = "0.5.4" 690version = "0.5.4"
681source = "registry+https://github.com/rust-lang/crates.io-index" 691source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1112,6 +1122,7 @@ dependencies = [
1112 "difference", 1122 "difference",
1113 "goblin", 1123 "goblin",
1114 "libloading", 1124 "libloading",
1125 "memmap",
1115 "ra_mbe", 1126 "ra_mbe",
1116 "ra_proc_macro", 1127 "ra_proc_macro",
1117 "ra_tt", 1128 "ra_tt",
diff --git a/crates/ra_hir/src/semantics.rs b/crates/ra_hir/src/semantics.rs
index 2707e422d..0b477f0e9 100644
--- a/crates/ra_hir/src/semantics.rs
+++ b/crates/ra_hir/src/semantics.rs
@@ -20,6 +20,7 @@ use rustc_hash::{FxHashMap, FxHashSet};
20 20
21use crate::{ 21use crate::{
22 db::HirDatabase, 22 db::HirDatabase,
23 diagnostics::Diagnostic,
23 semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx}, 24 semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx},
24 source_analyzer::{resolve_hir_path, SourceAnalyzer}, 25 source_analyzer::{resolve_hir_path, SourceAnalyzer},
25 AssocItem, Function, HirFileId, ImplDef, InFile, Local, MacroDef, Module, ModuleDef, Name, 26 AssocItem, Function, HirFileId, ImplDef, InFile, Local, MacroDef, Module, ModuleDef, Name,
@@ -126,6 +127,13 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
126 original_range(self.db, node.as_ref()) 127 original_range(self.db, node.as_ref())
127 } 128 }
128 129
130 pub fn diagnostics_range(&self, diagnostics: &dyn Diagnostic) -> FileRange {
131 let src = diagnostics.source();
132 let root = self.db.parse_or_expand(src.file_id).unwrap();
133 let node = src.value.to_node(&root);
134 original_range(self.db, src.with_value(&node))
135 }
136
129 pub fn ancestors_with_macros(&self, node: SyntaxNode) -> impl Iterator<Item = SyntaxNode> + '_ { 137 pub fn ancestors_with_macros(&self, node: SyntaxNode) -> impl Iterator<Item = SyntaxNode> + '_ {
130 let node = self.find_file(node); 138 let node = self.find_file(node);
131 node.ancestors_with_macros(self.db).map(|it| it.value) 139 node.ancestors_with_macros(self.db).map(|it| it.value)
diff --git a/crates/ra_hir/src/source_analyzer.rs b/crates/ra_hir/src/source_analyzer.rs
index 58ae6ce41..23af400b8 100644
--- a/crates/ra_hir/src/source_analyzer.rs
+++ b/crates/ra_hir/src/source_analyzer.rs
@@ -23,7 +23,7 @@ use hir_ty::{
23}; 23};
24use ra_syntax::{ 24use ra_syntax::{
25 ast::{self, AstNode}, 25 ast::{self, AstNode},
26 SyntaxNode, SyntaxNodePtr, TextUnit, 26 SyntaxNode, TextRange, TextUnit,
27}; 27};
28 28
29use crate::{ 29use crate::{
@@ -56,7 +56,7 @@ impl SourceAnalyzer {
56 let scopes = db.expr_scopes(def); 56 let scopes = db.expr_scopes(def);
57 let scope = match offset { 57 let scope = match offset {
58 None => scope_for(&scopes, &source_map, node), 58 None => scope_for(&scopes, &source_map, node),
59 Some(offset) => scope_for_offset(&scopes, &source_map, node.with_value(offset)), 59 Some(offset) => scope_for_offset(db, &scopes, &source_map, node.with_value(offset)),
60 }; 60 };
61 let resolver = resolver_for_scope(db.upcast(), def, scope); 61 let resolver = resolver_for_scope(db.upcast(), def, scope);
62 SourceAnalyzer { 62 SourceAnalyzer {
@@ -304,6 +304,7 @@ fn scope_for(
304} 304}
305 305
306fn scope_for_offset( 306fn scope_for_offset(
307 db: &dyn HirDatabase,
307 scopes: &ExprScopes, 308 scopes: &ExprScopes,
308 source_map: &BodySourceMap, 309 source_map: &BodySourceMap,
309 offset: InFile<TextUnit>, 310 offset: InFile<TextUnit>,
@@ -317,21 +318,63 @@ fn scope_for_offset(
317 if source.file_id != offset.file_id { 318 if source.file_id != offset.file_id {
318 return None; 319 return None;
319 } 320 }
320 let syntax_node_ptr = source.value.syntax_node_ptr(); 321 let root = source.file_syntax(db.upcast());
321 Some((syntax_node_ptr, scope)) 322 let node = source.value.to_node(&root);
323 Some((node.syntax().text_range(), scope))
322 }) 324 })
323 // find containing scope 325 // find containing scope
324 .min_by_key(|(ptr, _scope)| { 326 .min_by_key(|(expr_range, _scope)| {
325 ( 327 (
326 !(ptr.range().start() <= offset.value && offset.value <= ptr.range().end()), 328 !(expr_range.start() <= offset.value && offset.value <= expr_range.end()),
327 ptr.range().len(), 329 expr_range.len(),
328 ) 330 )
329 }) 331 })
330 .map(|(ptr, scope)| { 332 .map(|(expr_range, scope)| {
331 adjust(scopes, source_map, ptr, offset.file_id, offset.value).unwrap_or(*scope) 333 adjust(db, scopes, source_map, expr_range, offset.file_id, offset.value)
334 .unwrap_or(*scope)
332 }) 335 })
333} 336}
334 337
338// XXX: during completion, cursor might be outside of any particular
339// expression. Try to figure out the correct scope...
340fn adjust(
341 db: &dyn HirDatabase,
342 scopes: &ExprScopes,
343 source_map: &BodySourceMap,
344 expr_range: TextRange,
345 file_id: HirFileId,
346 offset: TextUnit,
347) -> Option<ScopeId> {
348 let child_scopes = scopes
349 .scope_by_expr()
350 .iter()
351 .filter_map(|(id, scope)| {
352 let source = source_map.expr_syntax(*id).ok()?;
353 // FIXME: correctly handle macro expansion
354 if source.file_id != file_id {
355 return None;
356 }
357 let root = source.file_syntax(db.upcast());
358 let node = source.value.to_node(&root);
359 Some((node.syntax().text_range(), scope))
360 })
361 .filter(|(range, _)| {
362 range.start() <= offset && range.is_subrange(&expr_range) && *range != expr_range
363 });
364
365 child_scopes
366 .max_by(|(r1, _), (r2, _)| {
367 if r2.is_subrange(&r1) {
368 std::cmp::Ordering::Greater
369 } else if r1.is_subrange(&r2) {
370 std::cmp::Ordering::Less
371 } else {
372 r1.start().cmp(&r2.start())
373 }
374 })
375 .map(|(_ptr, scope)| *scope)
376}
377
335pub(crate) fn resolve_hir_path( 378pub(crate) fn resolve_hir_path(
336 db: &dyn HirDatabase, 379 db: &dyn HirDatabase,
337 resolver: &Resolver, 380 resolver: &Resolver,
@@ -376,41 +419,3 @@ pub(crate) fn resolve_hir_path(
376 .map(|def| PathResolution::Macro(def.into())) 419 .map(|def| PathResolution::Macro(def.into()))
377 }) 420 })
378} 421}
379
380// XXX: during completion, cursor might be outside of any particular
381// expression. Try to figure out the correct scope...
382fn adjust(
383 scopes: &ExprScopes,
384 source_map: &BodySourceMap,
385 ptr: SyntaxNodePtr,
386 file_id: HirFileId,
387 offset: TextUnit,
388) -> Option<ScopeId> {
389 let r = ptr.range();
390 let child_scopes = scopes
391 .scope_by_expr()
392 .iter()
393 .filter_map(|(id, scope)| {
394 let source = source_map.expr_syntax(*id).ok()?;
395 // FIXME: correctly handle macro expansion
396 if source.file_id != file_id {
397 return None;
398 }
399 let syntax_node_ptr = source.value.syntax_node_ptr();
400 Some((syntax_node_ptr, scope))
401 })
402 .map(|(ptr, scope)| (ptr.range(), scope))
403 .filter(|(range, _)| range.start() <= offset && range.is_subrange(&r) && *range != r);
404
405 child_scopes
406 .max_by(|(r1, _), (r2, _)| {
407 if r2.is_subrange(&r1) {
408 std::cmp::Ordering::Greater
409 } else if r1.is_subrange(&r2) {
410 std::cmp::Ordering::Less
411 } else {
412 r1.start().cmp(&r2.start())
413 }
414 })
415 .map(|(_ptr, scope)| *scope)
416}
diff --git a/crates/ra_hir_def/src/body.rs b/crates/ra_hir_def/src/body.rs
index eafaf48c1..3b169440a 100644
--- a/crates/ra_hir_def/src/body.rs
+++ b/crates/ra_hir_def/src/body.rs
@@ -210,7 +210,7 @@ pub struct BodySourceMap {
210 expr_map_back: ArenaMap<ExprId, Result<ExprSource, SyntheticSyntax>>, 210 expr_map_back: ArenaMap<ExprId, Result<ExprSource, SyntheticSyntax>>,
211 pat_map: FxHashMap<PatSource, PatId>, 211 pat_map: FxHashMap<PatSource, PatId>,
212 pat_map_back: ArenaMap<PatId, Result<PatSource, SyntheticSyntax>>, 212 pat_map_back: ArenaMap<PatId, Result<PatSource, SyntheticSyntax>>,
213 field_map: FxHashMap<(ExprId, usize), AstPtr<ast::RecordField>>, 213 field_map: FxHashMap<(ExprId, usize), InFile<AstPtr<ast::RecordField>>>,
214 expansions: FxHashMap<InFile<AstPtr<ast::MacroCall>>, HirFileId>, 214 expansions: FxHashMap<InFile<AstPtr<ast::MacroCall>>, HirFileId>,
215} 215}
216 216
@@ -303,7 +303,7 @@ impl BodySourceMap {
303 self.pat_map.get(&src).cloned() 303 self.pat_map.get(&src).cloned()
304 } 304 }
305 305
306 pub fn field_syntax(&self, expr: ExprId, field: usize) -> AstPtr<ast::RecordField> { 306 pub fn field_syntax(&self, expr: ExprId, field: usize) -> InFile<AstPtr<ast::RecordField>> {
307 self.field_map[&(expr, field)].clone() 307 self.field_map[&(expr, field)].clone()
308 } 308 }
309} 309}
diff --git a/crates/ra_hir_def/src/body/lower.rs b/crates/ra_hir_def/src/body/lower.rs
index 79abe55ce..82a52804d 100644
--- a/crates/ra_hir_def/src/body/lower.rs
+++ b/crates/ra_hir_def/src/body/lower.rs
@@ -320,7 +320,8 @@ impl ExprCollector<'_> {
320 320
321 let res = self.alloc_expr(record_lit, syntax_ptr); 321 let res = self.alloc_expr(record_lit, syntax_ptr);
322 for (i, ptr) in field_ptrs.into_iter().enumerate() { 322 for (i, ptr) in field_ptrs.into_iter().enumerate() {
323 self.source_map.field_map.insert((res, i), ptr); 323 let src = self.expander.to_source(ptr);
324 self.source_map.field_map.insert((res, i), src);
324 } 325 }
325 res 326 res
326 } 327 }
@@ -650,6 +651,7 @@ impl ExprCollector<'_> {
650 ast::Pat::SlicePat(p) => { 651 ast::Pat::SlicePat(p) => {
651 let SlicePatComponents { prefix, slice, suffix } = p.components(); 652 let SlicePatComponents { prefix, slice, suffix } = p.components();
652 653
654 // FIXME properly handle `DotDotPat`
653 Pat::Slice { 655 Pat::Slice {
654 prefix: prefix.into_iter().map(|p| self.collect_pat(p)).collect(), 656 prefix: prefix.into_iter().map(|p| self.collect_pat(p)).collect(),
655 slice: slice.map(|p| self.collect_pat(p)), 657 slice: slice.map(|p| self.collect_pat(p)),
@@ -666,9 +668,15 @@ impl ExprCollector<'_> {
666 Pat::Missing 668 Pat::Missing
667 } 669 }
668 } 670 }
669 ast::Pat::DotDotPat(_) => unreachable!( 671 ast::Pat::DotDotPat(_) => {
670 "`DotDotPat` requires special handling and should not be mapped to a Pat." 672 // `DotDotPat` requires special handling and should not be mapped
671 ), 673 // to a Pat. Here we are using `Pat::Missing` as a fallback for
674 // when `DotDotPat` is mapped to `Pat`, which can easily happen
675 // when the source code being analyzed has a malformed pattern
676 // which includes `..` in a place where it isn't valid.
677
678 Pat::Missing
679 }
672 // FIXME: implement 680 // FIXME: implement
673 ast::Pat::BoxPat(_) | ast::Pat::RangePat(_) | ast::Pat::MacroPat(_) => Pat::Missing, 681 ast::Pat::BoxPat(_) | ast::Pat::RangePat(_) | ast::Pat::MacroPat(_) => Pat::Missing,
674 }; 682 };
diff --git a/crates/ra_hir_def/src/builtin_type.rs b/crates/ra_hir_def/src/builtin_type.rs
index d14901a9b..0f872b5c0 100644
--- a/crates/ra_hir_def/src/builtin_type.rs
+++ b/crates/ra_hir_def/src/builtin_type.rs
@@ -5,7 +5,7 @@
5 5
6use std::fmt; 6use std::fmt;
7 7
8use hir_expand::name::{name, Name}; 8use hir_expand::name::{name, AsName, Name};
9 9
10#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] 10#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
11pub enum Signedness { 11pub enum Signedness {
@@ -75,33 +75,39 @@ impl BuiltinType {
75 ]; 75 ];
76} 76}
77 77
78impl fmt::Display for BuiltinType { 78impl AsName for BuiltinType {
79 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 79 fn as_name(&self) -> Name {
80 let type_name = match self { 80 match self {
81 BuiltinType::Char => "char", 81 BuiltinType::Char => name![char],
82 BuiltinType::Bool => "bool", 82 BuiltinType::Bool => name![bool],
83 BuiltinType::Str => "str", 83 BuiltinType::Str => name![str],
84 BuiltinType::Int(BuiltinInt { signedness, bitness }) => match (signedness, bitness) { 84 BuiltinType::Int(BuiltinInt { signedness, bitness }) => match (signedness, bitness) {
85 (Signedness::Signed, IntBitness::Xsize) => "isize", 85 (Signedness::Signed, IntBitness::Xsize) => name![isize],
86 (Signedness::Signed, IntBitness::X8) => "i8", 86 (Signedness::Signed, IntBitness::X8) => name![i8],
87 (Signedness::Signed, IntBitness::X16) => "i16", 87 (Signedness::Signed, IntBitness::X16) => name![i16],
88 (Signedness::Signed, IntBitness::X32) => "i32", 88 (Signedness::Signed, IntBitness::X32) => name![i32],
89 (Signedness::Signed, IntBitness::X64) => "i64", 89 (Signedness::Signed, IntBitness::X64) => name![i64],
90 (Signedness::Signed, IntBitness::X128) => "i128", 90 (Signedness::Signed, IntBitness::X128) => name![i128],
91 91
92 (Signedness::Unsigned, IntBitness::Xsize) => "usize", 92 (Signedness::Unsigned, IntBitness::Xsize) => name![usize],
93 (Signedness::Unsigned, IntBitness::X8) => "u8", 93 (Signedness::Unsigned, IntBitness::X8) => name![u8],
94 (Signedness::Unsigned, IntBitness::X16) => "u16", 94 (Signedness::Unsigned, IntBitness::X16) => name![u16],
95 (Signedness::Unsigned, IntBitness::X32) => "u32", 95 (Signedness::Unsigned, IntBitness::X32) => name![u32],
96 (Signedness::Unsigned, IntBitness::X64) => "u64", 96 (Signedness::Unsigned, IntBitness::X64) => name![u64],
97 (Signedness::Unsigned, IntBitness::X128) => "u128", 97 (Signedness::Unsigned, IntBitness::X128) => name![u128],
98 }, 98 },
99 BuiltinType::Float(BuiltinFloat { bitness }) => match bitness { 99 BuiltinType::Float(BuiltinFloat { bitness }) => match bitness {
100 FloatBitness::X32 => "f32", 100 FloatBitness::X32 => name![f32],
101 FloatBitness::X64 => "f64", 101 FloatBitness::X64 => name![f64],
102 }, 102 },
103 }; 103 }
104 f.write_str(type_name) 104 }
105}
106
107impl fmt::Display for BuiltinType {
108 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
109 let type_name = self.as_name();
110 type_name.fmt(f)
105 } 111 }
106} 112}
107 113
diff --git a/crates/ra_hir_def/src/diagnostics.rs b/crates/ra_hir_def/src/diagnostics.rs
index cfa0f2f76..510c5e064 100644
--- a/crates/ra_hir_def/src/diagnostics.rs
+++ b/crates/ra_hir_def/src/diagnostics.rs
@@ -20,7 +20,7 @@ impl Diagnostic for UnresolvedModule {
20 "unresolved module".to_string() 20 "unresolved module".to_string()
21 } 21 }
22 fn source(&self) -> InFile<SyntaxNodePtr> { 22 fn source(&self) -> InFile<SyntaxNodePtr> {
23 InFile { file_id: self.file, value: self.decl.clone().into() } 23 InFile::new(self.file, self.decl.clone().into())
24 } 24 }
25 fn as_any(&self) -> &(dyn Any + Send + 'static) { 25 fn as_any(&self) -> &(dyn Any + Send + 'static) {
26 self 26 self
diff --git a/crates/ra_hir_def/src/find_path.rs b/crates/ra_hir_def/src/find_path.rs
index d58ac6ba5..81eff5bfe 100644
--- a/crates/ra_hir_def/src/find_path.rs
+++ b/crates/ra_hir_def/src/find_path.rs
@@ -7,7 +7,7 @@ use crate::{
7 visibility::Visibility, 7 visibility::Visibility,
8 CrateId, ModuleDefId, ModuleId, 8 CrateId, ModuleDefId, ModuleId,
9}; 9};
10use hir_expand::name::{known, Name}; 10use hir_expand::name::{known, AsName, Name};
11use test_utils::tested_by; 11use test_utils::tested_by;
12 12
13const MAX_PATH_LEN: usize = 15; 13const MAX_PATH_LEN: usize = 15;
@@ -113,6 +113,11 @@ fn find_path_inner(
113 } 113 }
114 } 114 }
115 115
116 // - if the item is a builtin, it's in scope
117 if let ItemInNs::Types(ModuleDefId::BuiltinType(builtin)) = item {
118 return Some(ModPath::from_segments(PathKind::Plain, vec![builtin.as_name()]));
119 }
120
116 // Recursive case: 121 // Recursive case:
117 // - if the item is an enum variant, refer to it via the enum 122 // - if the item is an enum variant, refer to it via the enum
118 if let Some(ModuleDefId::EnumVariantId(variant)) = item.as_module_def_id() { 123 if let Some(ModuleDefId::EnumVariantId(variant)) = item.as_module_def_id() {
@@ -523,4 +528,18 @@ mod tests {
523 "#; 528 "#;
524 check_found_path(code, "megaalloc::Arc"); 529 check_found_path(code, "megaalloc::Arc");
525 } 530 }
531
532 #[test]
533 fn builtins_are_in_scope() {
534 let code = r#"
535 //- /main.rs
536 <|>
537
538 pub mod primitive {
539 pub use u8;
540 }
541 "#;
542 check_found_path(code, "u8");
543 check_found_path(code, "u16");
544 }
526} 545}
diff --git a/crates/ra_hir_expand/src/diagnostics.rs b/crates/ra_hir_expand/src/diagnostics.rs
index 108c1e38c..99209c6e8 100644
--- a/crates/ra_hir_expand/src/diagnostics.rs
+++ b/crates/ra_hir_expand/src/diagnostics.rs
@@ -16,16 +16,13 @@
16 16
17use std::{any::Any, fmt}; 17use std::{any::Any, fmt};
18 18
19use ra_syntax::{SyntaxNode, SyntaxNodePtr, TextRange}; 19use ra_syntax::{SyntaxNode, SyntaxNodePtr};
20 20
21use crate::{db::AstDatabase, InFile}; 21use crate::{db::AstDatabase, InFile};
22 22
23pub trait Diagnostic: Any + Send + Sync + fmt::Debug + 'static { 23pub trait Diagnostic: Any + Send + Sync + fmt::Debug + 'static {
24 fn message(&self) -> String; 24 fn message(&self) -> String;
25 fn source(&self) -> InFile<SyntaxNodePtr>; 25 fn source(&self) -> InFile<SyntaxNodePtr>;
26 fn highlight_range(&self) -> TextRange {
27 self.source().value.range()
28 }
29 fn as_any(&self) -> &(dyn Any + Send + 'static); 26 fn as_any(&self) -> &(dyn Any + Send + 'static);
30} 27}
31 28
diff --git a/crates/ra_hir_ty/src/diagnostics.rs b/crates/ra_hir_ty/src/diagnostics.rs
index 927896d6f..c8fd54861 100644
--- a/crates/ra_hir_ty/src/diagnostics.rs
+++ b/crates/ra_hir_ty/src/diagnostics.rs
@@ -21,7 +21,7 @@ impl Diagnostic for NoSuchField {
21 } 21 }
22 22
23 fn source(&self) -> InFile<SyntaxNodePtr> { 23 fn source(&self) -> InFile<SyntaxNodePtr> {
24 InFile { file_id: self.file, value: self.field.clone().into() } 24 InFile::new(self.file, self.field.clone().into())
25 } 25 }
26 26
27 fn as_any(&self) -> &(dyn Any + Send + 'static) { 27 fn as_any(&self) -> &(dyn Any + Send + 'static) {
diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs
index 246b0e9be..b6d9b3438 100644
--- a/crates/ra_hir_ty/src/infer.rs
+++ b/crates/ra_hir_ty/src/infer.rs
@@ -682,10 +682,10 @@ mod diagnostics {
682 ) { 682 ) {
683 match self { 683 match self {
684 InferenceDiagnostic::NoSuchField { expr, field } => { 684 InferenceDiagnostic::NoSuchField { expr, field } => {
685 let file = owner.lookup(db.upcast()).source(db.upcast()).file_id; 685 let source = owner.lookup(db.upcast()).source(db.upcast());
686 let (_, source_map) = db.body_with_source_map(owner.into()); 686 let (_, source_map) = db.body_with_source_map(owner.into());
687 let field = source_map.field_syntax(*expr, *field); 687 let field = source_map.field_syntax(*expr, *field);
688 sink.push(NoSuchField { file, field }) 688 sink.push(NoSuchField { file: source.file_id, field: field.value })
689 } 689 }
690 } 690 }
691 } 691 }
diff --git a/crates/ra_hir_ty/src/infer/coerce.rs b/crates/ra_hir_ty/src/infer/coerce.rs
index 959b1e212..89200255a 100644
--- a/crates/ra_hir_ty/src/infer/coerce.rs
+++ b/crates/ra_hir_ty/src/infer/coerce.rs
@@ -51,7 +51,7 @@ impl<'a> InferenceContext<'a> {
51 // Trivial cases, this should go after `never` check to 51 // Trivial cases, this should go after `never` check to
52 // avoid infer result type to be never 52 // avoid infer result type to be never
53 _ => { 53 _ => {
54 if self.table.unify_inner_trivial(&from_ty, &to_ty) { 54 if self.table.unify_inner_trivial(&from_ty, &to_ty, 0) {
55 return true; 55 return true;
56 } 56 }
57 } 57 }
@@ -175,7 +175,7 @@ impl<'a> InferenceContext<'a> {
175 return self.table.unify_substs(st1, st2, 0); 175 return self.table.unify_substs(st1, st2, 0);
176 } 176 }
177 _ => { 177 _ => {
178 if self.table.unify_inner_trivial(&derefed_ty, &to_ty) { 178 if self.table.unify_inner_trivial(&derefed_ty, &to_ty, 0) {
179 return true; 179 return true;
180 } 180 }
181 } 181 }
diff --git a/crates/ra_hir_ty/src/infer/unify.rs b/crates/ra_hir_ty/src/infer/unify.rs
index 5f6cea8d3..ab0bc8b70 100644
--- a/crates/ra_hir_ty/src/infer/unify.rs
+++ b/crates/ra_hir_ty/src/infer/unify.rs
@@ -8,7 +8,8 @@ use test_utils::tested_by;
8 8
9use super::{InferenceContext, Obligation}; 9use super::{InferenceContext, Obligation};
10use crate::{ 10use crate::{
11 BoundVar, Canonical, DebruijnIndex, InEnvironment, InferTy, Substs, Ty, TypeCtor, TypeWalk, 11 BoundVar, Canonical, DebruijnIndex, GenericPredicate, InEnvironment, InferTy, Substs, Ty,
12 TypeCtor, TypeWalk,
12}; 13};
13 14
14impl<'a> InferenceContext<'a> { 15impl<'a> InferenceContext<'a> {
@@ -226,16 +227,26 @@ impl InferenceTable {
226 (Ty::Apply(a_ty1), Ty::Apply(a_ty2)) if a_ty1.ctor == a_ty2.ctor => { 227 (Ty::Apply(a_ty1), Ty::Apply(a_ty2)) if a_ty1.ctor == a_ty2.ctor => {
227 self.unify_substs(&a_ty1.parameters, &a_ty2.parameters, depth + 1) 228 self.unify_substs(&a_ty1.parameters, &a_ty2.parameters, depth + 1)
228 } 229 }
229 _ => self.unify_inner_trivial(&ty1, &ty2), 230
231 _ => self.unify_inner_trivial(&ty1, &ty2, depth),
230 } 232 }
231 } 233 }
232 234
233 pub(super) fn unify_inner_trivial(&mut self, ty1: &Ty, ty2: &Ty) -> bool { 235 pub(super) fn unify_inner_trivial(&mut self, ty1: &Ty, ty2: &Ty, depth: usize) -> bool {
234 match (ty1, ty2) { 236 match (ty1, ty2) {
235 (Ty::Unknown, _) | (_, Ty::Unknown) => true, 237 (Ty::Unknown, _) | (_, Ty::Unknown) => true,
236 238
237 (Ty::Placeholder(p1), Ty::Placeholder(p2)) if *p1 == *p2 => true, 239 (Ty::Placeholder(p1), Ty::Placeholder(p2)) if *p1 == *p2 => true,
238 240
241 (Ty::Dyn(dyn1), Ty::Dyn(dyn2)) if dyn1.len() == dyn2.len() => {
242 for (pred1, pred2) in dyn1.iter().zip(dyn2.iter()) {
243 if !self.unify_preds(pred1, pred2, depth + 1) {
244 return false;
245 }
246 }
247 true
248 }
249
239 (Ty::Infer(InferTy::TypeVar(tv1)), Ty::Infer(InferTy::TypeVar(tv2))) 250 (Ty::Infer(InferTy::TypeVar(tv1)), Ty::Infer(InferTy::TypeVar(tv2)))
240 | (Ty::Infer(InferTy::IntVar(tv1)), Ty::Infer(InferTy::IntVar(tv2))) 251 | (Ty::Infer(InferTy::IntVar(tv1)), Ty::Infer(InferTy::IntVar(tv2)))
241 | (Ty::Infer(InferTy::FloatVar(tv1)), Ty::Infer(InferTy::FloatVar(tv2))) 252 | (Ty::Infer(InferTy::FloatVar(tv1)), Ty::Infer(InferTy::FloatVar(tv2)))
@@ -268,6 +279,31 @@ impl InferenceTable {
268 } 279 }
269 } 280 }
270 281
282 fn unify_preds(
283 &mut self,
284 pred1: &GenericPredicate,
285 pred2: &GenericPredicate,
286 depth: usize,
287 ) -> bool {
288 match (pred1, pred2) {
289 (GenericPredicate::Implemented(tr1), GenericPredicate::Implemented(tr2))
290 if tr1.trait_ == tr2.trait_ =>
291 {
292 self.unify_substs(&tr1.substs, &tr2.substs, depth + 1)
293 }
294 (GenericPredicate::Projection(proj1), GenericPredicate::Projection(proj2))
295 if proj1.projection_ty.associated_ty == proj2.projection_ty.associated_ty =>
296 {
297 self.unify_substs(
298 &proj1.projection_ty.parameters,
299 &proj2.projection_ty.parameters,
300 depth + 1,
301 ) && self.unify_inner(&proj1.ty, &proj2.ty, depth + 1)
302 }
303 _ => false,
304 }
305 }
306
271 /// If `ty` is a type variable with known type, returns that type; 307 /// If `ty` is a type variable with known type, returns that type;
272 /// otherwise, return ty. 308 /// otherwise, return ty.
273 pub fn resolve_ty_shallow<'b>(&mut self, ty: &'b Ty) -> Cow<'b, Ty> { 309 pub fn resolve_ty_shallow<'b>(&mut self, ty: &'b Ty) -> Cow<'b, Ty> {
diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs
index 2677f3af2..a4b8d6683 100644
--- a/crates/ra_hir_ty/src/lib.rs
+++ b/crates/ra_hir_ty/src/lib.rs
@@ -396,12 +396,12 @@ impl Substs {
396 } 396 }
397 397
398 /// Return Substs that replace each parameter by a bound variable. 398 /// Return Substs that replace each parameter by a bound variable.
399 pub(crate) fn bound_vars(generic_params: &Generics) -> Substs { 399 pub(crate) fn bound_vars(generic_params: &Generics, debruijn: DebruijnIndex) -> Substs {
400 Substs( 400 Substs(
401 generic_params 401 generic_params
402 .iter() 402 .iter()
403 .enumerate() 403 .enumerate()
404 .map(|(idx, _)| Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, idx))) 404 .map(|(idx, _)| Ty::Bound(BoundVar::new(debruijn, idx)))
405 .collect(), 405 .collect(),
406 ) 406 )
407 } 407 }
diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs
index cc1ac8e3e..c2812e178 100644
--- a/crates/ra_hir_ty/src/lower.rs
+++ b/crates/ra_hir_ty/src/lower.rs
@@ -39,6 +39,7 @@ use crate::{
39pub struct TyLoweringContext<'a> { 39pub struct TyLoweringContext<'a> {
40 pub db: &'a dyn HirDatabase, 40 pub db: &'a dyn HirDatabase,
41 pub resolver: &'a Resolver, 41 pub resolver: &'a Resolver,
42 in_binders: DebruijnIndex,
42 /// Note: Conceptually, it's thinkable that we could be in a location where 43 /// Note: Conceptually, it's thinkable that we could be in a location where
43 /// some type params should be represented as placeholders, and others 44 /// some type params should be represented as placeholders, and others
44 /// should be converted to variables. I think in practice, this isn't 45 /// should be converted to variables. I think in practice, this isn't
@@ -53,7 +54,27 @@ impl<'a> TyLoweringContext<'a> {
53 let impl_trait_counter = std::cell::Cell::new(0); 54 let impl_trait_counter = std::cell::Cell::new(0);
54 let impl_trait_mode = ImplTraitLoweringMode::Disallowed; 55 let impl_trait_mode = ImplTraitLoweringMode::Disallowed;
55 let type_param_mode = TypeParamLoweringMode::Placeholder; 56 let type_param_mode = TypeParamLoweringMode::Placeholder;
56 Self { db, resolver, impl_trait_mode, impl_trait_counter, type_param_mode } 57 let in_binders = DebruijnIndex::INNERMOST;
58 Self { db, resolver, in_binders, impl_trait_mode, impl_trait_counter, type_param_mode }
59 }
60
61 pub fn with_shifted_in<T>(
62 &self,
63 debruijn: DebruijnIndex,
64 f: impl FnOnce(&TyLoweringContext) -> T,
65 ) -> T {
66 let new_ctx = Self {
67 in_binders: self.in_binders.shifted_in_from(debruijn),
68 impl_trait_counter: std::cell::Cell::new(self.impl_trait_counter.get()),
69 ..*self
70 };
71 let result = f(&new_ctx);
72 self.impl_trait_counter.set(new_ctx.impl_trait_counter.get());
73 result
74 }
75
76 pub fn shifted_in(self, debruijn: DebruijnIndex) -> Self {
77 Self { in_binders: self.in_binders.shifted_in_from(debruijn), ..self }
57 } 78 }
58 79
59 pub fn with_impl_trait_mode(self, impl_trait_mode: ImplTraitLoweringMode) -> Self { 80 pub fn with_impl_trait_mode(self, impl_trait_mode: ImplTraitLoweringMode) -> Self {
@@ -134,22 +155,26 @@ impl Ty {
134 } 155 }
135 TypeRef::DynTrait(bounds) => { 156 TypeRef::DynTrait(bounds) => {
136 let self_ty = Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, 0)); 157 let self_ty = Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, 0));
137 let predicates = bounds 158 let predicates = ctx.with_shifted_in(DebruijnIndex::ONE, |ctx| {
138 .iter() 159 bounds
139 .flat_map(|b| GenericPredicate::from_type_bound(ctx, b, self_ty.clone())) 160 .iter()
140 .collect(); 161 .flat_map(|b| GenericPredicate::from_type_bound(ctx, b, self_ty.clone()))
162 .collect()
163 });
141 Ty::Dyn(predicates) 164 Ty::Dyn(predicates)
142 } 165 }
143 TypeRef::ImplTrait(bounds) => { 166 TypeRef::ImplTrait(bounds) => {
144 match ctx.impl_trait_mode { 167 match ctx.impl_trait_mode {
145 ImplTraitLoweringMode::Opaque => { 168 ImplTraitLoweringMode::Opaque => {
146 let self_ty = Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, 0)); 169 let self_ty = Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, 0));
147 let predicates = bounds 170 let predicates = ctx.with_shifted_in(DebruijnIndex::ONE, |ctx| {
148 .iter() 171 bounds
149 .flat_map(|b| { 172 .iter()
150 GenericPredicate::from_type_bound(ctx, b, self_ty.clone()) 173 .flat_map(|b| {
151 }) 174 GenericPredicate::from_type_bound(ctx, b, self_ty.clone())
152 .collect(); 175 })
176 .collect()
177 });
153 Ty::Opaque(predicates) 178 Ty::Opaque(predicates)
154 } 179 }
155 ImplTraitLoweringMode::Param => { 180 ImplTraitLoweringMode::Param => {
@@ -180,7 +205,7 @@ impl Ty {
180 (0, 0, 0, 0) 205 (0, 0, 0, 0)
181 }; 206 };
182 Ty::Bound(BoundVar::new( 207 Ty::Bound(BoundVar::new(
183 DebruijnIndex::INNERMOST, 208 ctx.in_binders,
184 idx as usize + parent_params + self_params + list_params, 209 idx as usize + parent_params + self_params + list_params,
185 )) 210 ))
186 } 211 }
@@ -293,7 +318,7 @@ impl Ty {
293 TypeParamLoweringMode::Placeholder => Ty::Placeholder(param_id), 318 TypeParamLoweringMode::Placeholder => Ty::Placeholder(param_id),
294 TypeParamLoweringMode::Variable => { 319 TypeParamLoweringMode::Variable => {
295 let idx = generics.param_idx(param_id).expect("matching generics"); 320 let idx = generics.param_idx(param_id).expect("matching generics");
296 Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, idx)) 321 Ty::Bound(BoundVar::new(ctx.in_binders, idx))
297 } 322 }
298 } 323 }
299 } 324 }
@@ -303,7 +328,9 @@ impl Ty {
303 TypeParamLoweringMode::Placeholder => { 328 TypeParamLoweringMode::Placeholder => {
304 Substs::type_params_for_generics(&generics) 329 Substs::type_params_for_generics(&generics)
305 } 330 }
306 TypeParamLoweringMode::Variable => Substs::bound_vars(&generics), 331 TypeParamLoweringMode::Variable => {
332 Substs::bound_vars(&generics, ctx.in_binders)
333 }
307 }; 334 };
308 ctx.db.impl_self_ty(impl_id).subst(&substs) 335 ctx.db.impl_self_ty(impl_id).subst(&substs)
309 } 336 }
@@ -313,7 +340,9 @@ impl Ty {
313 TypeParamLoweringMode::Placeholder => { 340 TypeParamLoweringMode::Placeholder => {
314 Substs::type_params_for_generics(&generics) 341 Substs::type_params_for_generics(&generics)
315 } 342 }
316 TypeParamLoweringMode::Variable => Substs::bound_vars(&generics), 343 TypeParamLoweringMode::Variable => {
344 Substs::bound_vars(&generics, ctx.in_binders)
345 }
317 }; 346 };
318 ctx.db.ty(adt.into()).subst(&substs) 347 ctx.db.ty(adt.into()).subst(&substs)
319 } 348 }
@@ -797,7 +826,7 @@ fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> PolyFnSig {
797/// function body. 826/// function body.
798fn type_for_fn(db: &dyn HirDatabase, def: FunctionId) -> Binders<Ty> { 827fn type_for_fn(db: &dyn HirDatabase, def: FunctionId) -> Binders<Ty> {
799 let generics = generics(db.upcast(), def.into()); 828 let generics = generics(db.upcast(), def.into());
800 let substs = Substs::bound_vars(&generics); 829 let substs = Substs::bound_vars(&generics, DebruijnIndex::INNERMOST);
801 Binders::new(substs.len(), Ty::apply(TypeCtor::FnDef(def.into()), substs)) 830 Binders::new(substs.len(), Ty::apply(TypeCtor::FnDef(def.into()), substs))
802} 831}
803 832
@@ -851,7 +880,7 @@ fn type_for_struct_constructor(db: &dyn HirDatabase, def: StructId) -> Binders<T
851 return type_for_adt(db, def.into()); 880 return type_for_adt(db, def.into());
852 } 881 }
853 let generics = generics(db.upcast(), def.into()); 882 let generics = generics(db.upcast(), def.into());
854 let substs = Substs::bound_vars(&generics); 883 let substs = Substs::bound_vars(&generics, DebruijnIndex::INNERMOST);
855 Binders::new(substs.len(), Ty::apply(TypeCtor::FnDef(def.into()), substs)) 884 Binders::new(substs.len(), Ty::apply(TypeCtor::FnDef(def.into()), substs))
856} 885}
857 886
@@ -876,13 +905,13 @@ fn type_for_enum_variant_constructor(db: &dyn HirDatabase, def: EnumVariantId) -
876 return type_for_adt(db, def.parent.into()); 905 return type_for_adt(db, def.parent.into());
877 } 906 }
878 let generics = generics(db.upcast(), def.parent.into()); 907 let generics = generics(db.upcast(), def.parent.into());
879 let substs = Substs::bound_vars(&generics); 908 let substs = Substs::bound_vars(&generics, DebruijnIndex::INNERMOST);
880 Binders::new(substs.len(), Ty::apply(TypeCtor::FnDef(def.into()), substs)) 909 Binders::new(substs.len(), Ty::apply(TypeCtor::FnDef(def.into()), substs))
881} 910}
882 911
883fn type_for_adt(db: &dyn HirDatabase, adt: AdtId) -> Binders<Ty> { 912fn type_for_adt(db: &dyn HirDatabase, adt: AdtId) -> Binders<Ty> {
884 let generics = generics(db.upcast(), adt.into()); 913 let generics = generics(db.upcast(), adt.into());
885 let substs = Substs::bound_vars(&generics); 914 let substs = Substs::bound_vars(&generics, DebruijnIndex::INNERMOST);
886 Binders::new(substs.len(), Ty::apply(TypeCtor::Adt(adt), substs)) 915 Binders::new(substs.len(), Ty::apply(TypeCtor::Adt(adt), substs))
887} 916}
888 917
@@ -892,7 +921,7 @@ fn type_for_type_alias(db: &dyn HirDatabase, t: TypeAliasId) -> Binders<Ty> {
892 let ctx = 921 let ctx =
893 TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable); 922 TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable);
894 let type_ref = &db.type_alias_data(t).type_ref; 923 let type_ref = &db.type_alias_data(t).type_ref;
895 let substs = Substs::bound_vars(&generics); 924 let substs = Substs::bound_vars(&generics, DebruijnIndex::INNERMOST);
896 let inner = Ty::from_hir(&ctx, type_ref.as_ref().unwrap_or(&TypeRef::Error)); 925 let inner = Ty::from_hir(&ctx, type_ref.as_ref().unwrap_or(&TypeRef::Error));
897 Binders::new(substs.len(), inner) 926 Binders::new(substs.len(), inner)
898} 927}
diff --git a/crates/ra_hir_ty/src/tests/regression.rs b/crates/ra_hir_ty/src/tests/regression.rs
index d69115a2f..61284d672 100644
--- a/crates/ra_hir_ty/src/tests/regression.rs
+++ b/crates/ra_hir_ty/src/tests/regression.rs
@@ -484,3 +484,52 @@ fn main() {
484 484
485 assert_eq!("()", super::type_at_pos(&db, pos)); 485 assert_eq!("()", super::type_at_pos(&db, pos));
486} 486}
487
488#[test]
489fn issue_3999_slice() {
490 assert_snapshot!(
491 infer(r#"
492fn foo(params: &[usize]) {
493 match params {
494 [ps @ .., _] => {}
495 }
496}
497"#),
498 @r###"
499 [8; 14) 'params': &[usize]
500 [26; 81) '{ ... } }': ()
501 [32; 79) 'match ... }': ()
502 [38; 44) 'params': &[usize]
503 [55; 67) '[ps @ .., _]': [usize]
504 [65; 66) '_': usize
505 [71; 73) '{}': ()
506 "###
507 );
508}
509
510#[test]
511fn issue_3999_struct() {
512 // rust-analyzer should not panic on seeing this malformed
513 // record pattern.
514 assert_snapshot!(
515 infer(r#"
516struct Bar {
517 a: bool,
518}
519fn foo(b: Bar) {
520 match b {
521 Bar { a: .. } => {},
522 }
523}
524"#),
525 @r###"
526 [36; 37) 'b': Bar
527 [44; 96) '{ ... } }': ()
528 [50; 94) 'match ... }': ()
529 [56; 57) 'b': Bar
530 [68; 81) 'Bar { a: .. }': Bar
531 [77; 79) '..': bool
532 [85; 87) '{}': ()
533 "###
534 );
535}
diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs
index 0a889f805..a46f03b7f 100644
--- a/crates/ra_hir_ty/src/tests/traits.rs
+++ b/crates/ra_hir_ty/src/tests/traits.rs
@@ -1211,6 +1211,42 @@ fn test(x: dyn Trait<u64>, y: &dyn Trait<u64>) {
1211} 1211}
1212 1212
1213#[test] 1213#[test]
1214fn dyn_trait_in_impl() {
1215 assert_snapshot!(
1216 infer(r#"
1217trait Trait<T, U> {
1218 fn foo(&self) -> (T, U);
1219}
1220struct S<T, U> {}
1221impl<T, U> S<T, U> {
1222 fn bar(&self) -> &dyn Trait<T, U> { loop {} }
1223}
1224trait Trait2<T, U> {
1225 fn baz(&self) -> (T, U);
1226}
1227impl<T, U> Trait2<T, U> for dyn Trait<T, U> { }
1228
1229fn test(s: S<u32, i32>) {
1230 s.bar().baz();
1231}
1232"#),
1233 @r###"
1234 [33; 37) 'self': &Self
1235 [103; 107) 'self': &S<T, U>
1236 [129; 140) '{ loop {} }': &dyn Trait<T, U>
1237 [131; 138) 'loop {}': !
1238 [136; 138) '{}': ()
1239 [176; 180) 'self': &Self
1240 [252; 253) 's': S<u32, i32>
1241 [268; 290) '{ ...z(); }': ()
1242 [274; 275) 's': S<u32, i32>
1243 [274; 281) 's.bar()': &dyn Trait<u32, i32>
1244 [274; 287) 's.bar().baz()': (u32, i32)
1245 "###
1246 );
1247}
1248
1249#[test]
1214fn dyn_trait_bare() { 1250fn dyn_trait_bare() {
1215 assert_snapshot!( 1251 assert_snapshot!(
1216 infer(r#" 1252 infer(r#"
@@ -2204,3 +2240,201 @@ fn test(x: Box<dyn Trait>) {
2204 ); 2240 );
2205 assert_eq!(t, "()"); 2241 assert_eq!(t, "()");
2206} 2242}
2243
2244#[test]
2245fn string_to_owned() {
2246 let t = type_at(
2247 r#"
2248//- /main.rs
2249struct String {}
2250pub trait ToOwned {
2251 type Owned;
2252 fn to_owned(&self) -> Self::Owned;
2253}
2254impl ToOwned for str {
2255 type Owned = String;
2256}
2257fn test() {
2258 "foo".to_owned()<|>;
2259}
2260"#,
2261 );
2262 assert_eq!(t, "String");
2263}
2264
2265#[test]
2266fn iterator_chain() {
2267 assert_snapshot!(
2268 infer(r#"
2269//- /main.rs
2270#[lang = "fn_once"]
2271trait FnOnce<Args> {
2272 type Output;
2273}
2274#[lang = "fn_mut"]
2275trait FnMut<Args>: FnOnce<Args> { }
2276
2277enum Option<T> { Some(T), None }
2278use Option::*;
2279
2280pub trait Iterator {
2281 type Item;
2282
2283 fn filter_map<B, F>(self, f: F) -> FilterMap<Self, F>
2284 where
2285 F: FnMut(Self::Item) -> Option<B>,
2286 { loop {} }
2287
2288 fn for_each<F>(self, f: F)
2289 where
2290 F: FnMut(Self::Item),
2291 { loop {} }
2292}
2293
2294pub trait IntoIterator {
2295 type Item;
2296 type IntoIter: Iterator<Item = Self::Item>;
2297 fn into_iter(self) -> Self::IntoIter;
2298}
2299
2300pub struct FilterMap<I, F> { }
2301impl<B, I: Iterator, F> Iterator for FilterMap<I, F>
2302where
2303 F: FnMut(I::Item) -> Option<B>,
2304{
2305 type Item = B;
2306}
2307
2308#[stable(feature = "rust1", since = "1.0.0")]
2309impl<I: Iterator> IntoIterator for I {
2310 type Item = I::Item;
2311 type IntoIter = I;
2312
2313 fn into_iter(self) -> I {
2314 self
2315 }
2316}
2317
2318struct Vec<T> {}
2319impl<T> Vec<T> {
2320 fn new() -> Self { loop {} }
2321}
2322
2323impl<T> IntoIterator for Vec<T> {
2324 type Item = T;
2325 type IntoIter = IntoIter<T>;
2326}
2327
2328pub struct IntoIter<T> { }
2329impl<T> Iterator for IntoIter<T> {
2330 type Item = T;
2331}
2332
2333fn main() {
2334 Vec::<i32>::new().into_iter()
2335 .filter_map(|x| if x > 0 { Some(x as u32) } else { None })
2336 .for_each(|y| { y; });
2337}
2338"#),
2339 @r###"
2340 [240; 244) 'self': Self
2341 [246; 247) 'f': F
2342 [331; 342) '{ loop {} }': FilterMap<Self, F>
2343 [333; 340) 'loop {}': !
2344 [338; 340) '{}': ()
2345 [363; 367) 'self': Self
2346 [369; 370) 'f': F
2347 [419; 430) '{ loop {} }': ()
2348 [421; 428) 'loop {}': !
2349 [426; 428) '{}': ()
2350 [539; 543) 'self': Self
2351 [868; 872) 'self': I
2352 [879; 899) '{ ... }': I
2353 [889; 893) 'self': I
2354 [958; 969) '{ loop {} }': Vec<T>
2355 [960; 967) 'loop {}': !
2356 [965; 967) '{}': ()
2357 [1156; 1287) '{ ... }); }': ()
2358 [1162; 1177) 'Vec::<i32>::new': fn new<i32>() -> Vec<i32>
2359 [1162; 1179) 'Vec::<...:new()': Vec<i32>
2360 [1162; 1191) 'Vec::<...iter()': IntoIter<i32>
2361 [1162; 1256) 'Vec::<...one })': FilterMap<IntoIter<i32>, |i32| -> Option<u32>>
2362 [1162; 1284) 'Vec::<... y; })': ()
2363 [1210; 1255) '|x| if...None }': |i32| -> Option<u32>
2364 [1211; 1212) 'x': i32
2365 [1214; 1255) 'if x >...None }': Option<u32>
2366 [1217; 1218) 'x': i32
2367 [1217; 1222) 'x > 0': bool
2368 [1221; 1222) '0': i32
2369 [1223; 1241) '{ Some...u32) }': Option<u32>
2370 [1225; 1229) 'Some': Some<u32>(u32) -> Option<u32>
2371 [1225; 1239) 'Some(x as u32)': Option<u32>
2372 [1230; 1231) 'x': i32
2373 [1230; 1238) 'x as u32': u32
2374 [1247; 1255) '{ None }': Option<u32>
2375 [1249; 1253) 'None': Option<u32>
2376 [1273; 1283) '|y| { y; }': |u32| -> ()
2377 [1274; 1275) 'y': u32
2378 [1277; 1283) '{ y; }': ()
2379 [1279; 1280) 'y': u32
2380 "###
2381 );
2382}
2383
2384#[test]
2385fn nested_assoc() {
2386 let t = type_at(
2387 r#"
2388//- /main.rs
2389struct Bar;
2390struct Foo;
2391
2392trait A {
2393 type OutputA;
2394}
2395
2396impl A for Bar {
2397 type OutputA = Foo;
2398}
2399
2400trait B {
2401 type Output;
2402 fn foo() -> Self::Output;
2403}
2404
2405impl<T:A> B for T {
2406 type Output = T::OutputA;
2407 fn foo() -> Self::Output { loop {} }
2408}
2409
2410fn main() {
2411 Bar::foo()<|>;
2412}
2413"#,
2414 );
2415 assert_eq!(t, "Foo");
2416}
2417
2418#[test]
2419fn trait_object_no_coercion() {
2420 assert_snapshot!(
2421 infer_with_mismatches(r#"
2422trait Foo {}
2423
2424fn foo(x: &dyn Foo) {}
2425
2426fn test(x: &dyn Foo) {
2427 foo(x);
2428}
2429"#, true),
2430 @r###"
2431 [22; 23) 'x': &dyn Foo
2432 [35; 37) '{}': ()
2433 [47; 48) 'x': &dyn Foo
2434 [60; 75) '{ foo(x); }': ()
2435 [66; 69) 'foo': fn foo(&dyn Foo)
2436 [66; 72) 'foo(x)': ()
2437 [70; 71) 'x': &dyn Foo
2438 "###
2439 );
2440}
diff --git a/crates/ra_hir_ty/src/traits/chalk.rs b/crates/ra_hir_ty/src/traits/chalk.rs
index 60d70d18e..e00a82db2 100644
--- a/crates/ra_hir_ty/src/traits/chalk.rs
+++ b/crates/ra_hir_ty/src/traits/chalk.rs
@@ -17,7 +17,7 @@ use ra_db::{
17use super::{builtin, AssocTyValue, Canonical, ChalkContext, Impl, Obligation}; 17use super::{builtin, AssocTyValue, Canonical, ChalkContext, Impl, Obligation};
18use crate::{ 18use crate::{
19 db::HirDatabase, display::HirDisplay, method_resolution::TyFingerprint, utils::generics, 19 db::HirDatabase, display::HirDisplay, method_resolution::TyFingerprint, utils::generics,
20 ApplicationTy, GenericPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor, 20 ApplicationTy, DebruijnIndex, GenericPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor,
21}; 21};
22 22
23pub(super) mod tls; 23pub(super) mod tls;
@@ -815,7 +815,7 @@ pub(crate) fn associated_ty_data_query(
815 // Lower bounds -- we could/should maybe move this to a separate query in `lower` 815 // Lower bounds -- we could/should maybe move this to a separate query in `lower`
816 let type_alias_data = db.type_alias_data(type_alias); 816 let type_alias_data = db.type_alias_data(type_alias);
817 let generic_params = generics(db.upcast(), type_alias.into()); 817 let generic_params = generics(db.upcast(), type_alias.into());
818 let bound_vars = Substs::bound_vars(&generic_params); 818 let bound_vars = Substs::bound_vars(&generic_params, DebruijnIndex::INNERMOST);
819 let resolver = hir_def::resolver::HasResolver::resolver(type_alias, db.upcast()); 819 let resolver = hir_def::resolver::HasResolver::resolver(type_alias, db.upcast());
820 let ctx = crate::TyLoweringContext::new(db, &resolver) 820 let ctx = crate::TyLoweringContext::new(db, &resolver)
821 .with_type_param_mode(crate::lower::TypeParamLoweringMode::Variable); 821 .with_type_param_mode(crate::lower::TypeParamLoweringMode::Variable);
@@ -849,7 +849,7 @@ pub(crate) fn trait_datum_query(
849 let trait_data = db.trait_data(trait_); 849 let trait_data = db.trait_data(trait_);
850 debug!("trait {:?} = {:?}", trait_id, trait_data.name); 850 debug!("trait {:?} = {:?}", trait_id, trait_data.name);
851 let generic_params = generics(db.upcast(), trait_.into()); 851 let generic_params = generics(db.upcast(), trait_.into());
852 let bound_vars = Substs::bound_vars(&generic_params); 852 let bound_vars = Substs::bound_vars(&generic_params, DebruijnIndex::INNERMOST);
853 let flags = chalk_rust_ir::TraitFlags { 853 let flags = chalk_rust_ir::TraitFlags {
854 auto: trait_data.auto, 854 auto: trait_data.auto,
855 upstream: trait_.lookup(db.upcast()).container.module(db.upcast()).krate != krate, 855 upstream: trait_.lookup(db.upcast()).container.module(db.upcast()).krate != krate,
@@ -888,7 +888,7 @@ pub(crate) fn struct_datum_query(
888 .as_generic_def() 888 .as_generic_def()
889 .map(|generic_def| { 889 .map(|generic_def| {
890 let generic_params = generics(db.upcast(), generic_def); 890 let generic_params = generics(db.upcast(), generic_def);
891 let bound_vars = Substs::bound_vars(&generic_params); 891 let bound_vars = Substs::bound_vars(&generic_params, DebruijnIndex::INNERMOST);
892 convert_where_clauses(db, generic_def, &bound_vars) 892 convert_where_clauses(db, generic_def, &bound_vars)
893 }) 893 })
894 .unwrap_or_else(Vec::new); 894 .unwrap_or_else(Vec::new);
@@ -934,7 +934,7 @@ fn impl_def_datum(
934 let impl_data = db.impl_data(impl_id); 934 let impl_data = db.impl_data(impl_id);
935 935
936 let generic_params = generics(db.upcast(), impl_id.into()); 936 let generic_params = generics(db.upcast(), impl_id.into());
937 let bound_vars = Substs::bound_vars(&generic_params); 937 let bound_vars = Substs::bound_vars(&generic_params, DebruijnIndex::INNERMOST);
938 let trait_ = trait_ref.trait_; 938 let trait_ = trait_ref.trait_;
939 let impl_type = if impl_id.lookup(db.upcast()).container.module(db.upcast()).krate == krate { 939 let impl_type = if impl_id.lookup(db.upcast()).container.module(db.upcast()).krate == krate {
940 chalk_rust_ir::ImplType::Local 940 chalk_rust_ir::ImplType::Local
diff --git a/crates/ra_ide/src/completion/complete_trait_impl.rs b/crates/ra_ide/src/completion/complete_trait_impl.rs
index fab02945c..2ec0e7ce9 100644
--- a/crates/ra_ide/src/completion/complete_trait_impl.rs
+++ b/crates/ra_ide/src/completion/complete_trait_impl.rs
@@ -142,11 +142,11 @@ fn add_function_impl(
142 CompletionItemKind::Function 142 CompletionItemKind::Function
143 }; 143 };
144 144
145 let snippet = format!("{} {{}}", display); 145 let snippet = format!("{} {{\n $0\n}}", display);
146 146
147 let range = TextRange::from_to(fn_def_node.text_range().start(), ctx.source_range().end()); 147 let range = TextRange::from_to(fn_def_node.text_range().start(), ctx.source_range().end());
148 148
149 builder.text_edit(TextEdit::replace(range, snippet)).kind(completion_kind).add_to(acc); 149 builder.snippet_edit(TextEdit::replace(range, snippet)).kind(completion_kind).add_to(acc);
150} 150}
151 151
152fn add_type_alias_impl( 152fn add_type_alias_impl(
@@ -217,9 +217,10 @@ fn make_const_compl_syntax(const_: &ast::ConstDef) -> String {
217 217
218#[cfg(test)] 218#[cfg(test)]
219mod tests { 219mod tests {
220 use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind};
221 use insta::assert_debug_snapshot; 220 use insta::assert_debug_snapshot;
222 221
222 use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind};
223
223 fn complete(code: &str) -> Vec<CompletionItem> { 224 fn complete(code: &str) -> Vec<CompletionItem> {
224 do_completion(code, CompletionKind::Magic) 225 do_completion(code, CompletionKind::Magic)
225 } 226 }
@@ -255,7 +256,7 @@ mod tests {
255 label: "fn test()", 256 label: "fn test()",
256 source_range: [209; 210), 257 source_range: [209; 210),
257 delete: [209; 210), 258 delete: [209; 210),
258 insert: "fn test() {}", 259 insert: "fn test() {\n $0\n}",
259 kind: Function, 260 kind: Function,
260 lookup: "test", 261 lookup: "test",
261 }, 262 },
@@ -313,7 +314,7 @@ mod tests {
313 label: "fn test()", 314 label: "fn test()",
314 source_range: [139; 140), 315 source_range: [139; 140),
315 delete: [139; 140), 316 delete: [139; 140),
316 insert: "fn test() {}", 317 insert: "fn test() {\n $0\n}",
317 kind: Function, 318 kind: Function,
318 lookup: "test", 319 lookup: "test",
319 }, 320 },
@@ -342,7 +343,7 @@ mod tests {
342 label: "fn foo()", 343 label: "fn foo()",
343 source_range: [141; 142), 344 source_range: [141; 142),
344 delete: [138; 142), 345 delete: [138; 142),
345 insert: "fn foo() {}", 346 insert: "fn foo() {\n $0\n}",
346 kind: Function, 347 kind: Function,
347 lookup: "foo", 348 lookup: "foo",
348 }, 349 },
@@ -374,7 +375,7 @@ mod tests {
374 label: "fn foo_bar()", 375 label: "fn foo_bar()",
375 source_range: [200; 201), 376 source_range: [200; 201),
376 delete: [197; 201), 377 delete: [197; 201),
377 insert: "fn foo_bar() {}", 378 insert: "fn foo_bar() {\n $0\n}",
378 kind: Function, 379 kind: Function,
379 lookup: "foo_bar", 380 lookup: "foo_bar",
380 }, 381 },
@@ -425,7 +426,7 @@ mod tests {
425 label: "fn foo()", 426 label: "fn foo()",
426 source_range: [144; 145), 427 source_range: [144; 145),
427 delete: [141; 145), 428 delete: [141; 145),
428 insert: "fn foo<T>() {}", 429 insert: "fn foo<T>() {\n $0\n}",
429 kind: Function, 430 kind: Function,
430 lookup: "foo", 431 lookup: "foo",
431 }, 432 },
@@ -454,7 +455,7 @@ mod tests {
454 label: "fn foo()", 455 label: "fn foo()",
455 source_range: [166; 167), 456 source_range: [166; 167),
456 delete: [163; 167), 457 delete: [163; 167),
457 insert: "fn foo<T>()\nwhere T: Into<String> {}", 458 insert: "fn foo<T>()\nwhere T: Into<String> {\n $0\n}",
458 kind: Function, 459 kind: Function,
459 lookup: "foo", 460 lookup: "foo",
460 }, 461 },
diff --git a/crates/ra_ide/src/completion/complete_unqualified_path.rs b/crates/ra_ide/src/completion/complete_unqualified_path.rs
index 2d8e0776c..ad5fdcc4e 100644
--- a/crates/ra_ide/src/completion/complete_unqualified_path.rs
+++ b/crates/ra_ide/src/completion/complete_unqualified_path.rs
@@ -1,6 +1,10 @@
1//! Completion of names from the current scope, e.g. locals and imported items. 1//! Completion of names from the current scope, e.g. locals and imported items.
2 2
3use hir::ScopeDef;
4use test_utils::tested_by;
5
3use crate::completion::{CompletionContext, Completions}; 6use crate::completion::{CompletionContext, Completions};
7use ra_syntax::AstNode;
4 8
5pub(super) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) { 9pub(super) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) {
6 if !ctx.is_trivial_path { 10 if !ctx.is_trivial_path {
@@ -14,12 +18,23 @@ pub(super) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC
14 return; 18 return;
15 } 19 }
16 20
17 ctx.scope().process_all_names(&mut |name, res| acc.add_resolution(ctx, name.to_string(), &res)); 21 ctx.scope().process_all_names(&mut |name, res| {
22 if ctx.use_item_syntax.is_some() {
23 if let (ScopeDef::Unknown, Some(name_ref)) = (&res, &ctx.name_ref_syntax) {
24 if name_ref.syntax().text() == name.to_string().as_str() {
25 tested_by!(self_fulfilling_completion);
26 return;
27 }
28 }
29 }
30 acc.add_resolution(ctx, name.to_string(), &res)
31 });
18} 32}
19 33
20#[cfg(test)] 34#[cfg(test)]
21mod tests { 35mod tests {
22 use insta::assert_debug_snapshot; 36 use insta::assert_debug_snapshot;
37 use test_utils::covers;
23 38
24 use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind}; 39 use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind};
25 40
@@ -28,6 +43,29 @@ mod tests {
28 } 43 }
29 44
30 #[test] 45 #[test]
46 fn self_fulfilling_completion() {
47 covers!(self_fulfilling_completion);
48 assert_debug_snapshot!(
49 do_reference_completion(
50 r#"
51 use foo<|>
52 use std::collections;
53 "#,
54 ),
55 @r###"
56 [
57 CompletionItem {
58 label: "collections",
59 source_range: [21; 24),
60 delete: [21; 24),
61 insert: "collections",
62 },
63 ]
64 "###
65 );
66 }
67
68 #[test]
31 fn bind_pat_and_path_ignore_at() { 69 fn bind_pat_and_path_ignore_at() {
32 assert_debug_snapshot!( 70 assert_debug_snapshot!(
33 do_reference_completion( 71 do_reference_completion(
diff --git a/crates/ra_ide/src/diagnostics.rs b/crates/ra_ide/src/diagnostics.rs
index 901ad104c..e7e201709 100644
--- a/crates/ra_ide/src/diagnostics.rs
+++ b/crates/ra_ide/src/diagnostics.rs
@@ -1,4 +1,8 @@
1//! FIXME: write short doc here 1//! Collects diagnostics & fixits for a single file.
2//!
3//! The tricky bit here is that diagnostics are produced by hir in terms of
4//! macro-expanded files, but we need to present them to the users in terms of
5//! original files. So we need to map the ranges.
2 6
3use std::cell::RefCell; 7use std::cell::RefCell;
4 8
@@ -46,7 +50,7 @@ pub(crate) fn diagnostics(db: &RootDatabase, file_id: FileId) -> Vec<Diagnostic>
46 let mut sink = DiagnosticSink::new(|d| { 50 let mut sink = DiagnosticSink::new(|d| {
47 res.borrow_mut().push(Diagnostic { 51 res.borrow_mut().push(Diagnostic {
48 message: d.message(), 52 message: d.message(),
49 range: d.highlight_range(), 53 range: sema.diagnostics_range(d).range,
50 severity: Severity::Error, 54 severity: Severity::Error,
51 fix: None, 55 fix: None,
52 }) 56 })
@@ -62,7 +66,7 @@ pub(crate) fn diagnostics(db: &RootDatabase, file_id: FileId) -> Vec<Diagnostic>
62 let create_file = FileSystemEdit::CreateFile { source_root, path }; 66 let create_file = FileSystemEdit::CreateFile { source_root, path };
63 let fix = SourceChange::file_system_edit("create module", create_file); 67 let fix = SourceChange::file_system_edit("create module", create_file);
64 res.borrow_mut().push(Diagnostic { 68 res.borrow_mut().push(Diagnostic {
65 range: d.highlight_range(), 69 range: sema.diagnostics_range(d).range,
66 message: d.message(), 70 message: d.message(),
67 severity: Severity::Error, 71 severity: Severity::Error,
68 fix: Some(fix), 72 fix: Some(fix),
@@ -95,7 +99,7 @@ pub(crate) fn diagnostics(db: &RootDatabase, file_id: FileId) -> Vec<Diagnostic>
95 }; 99 };
96 100
97 res.borrow_mut().push(Diagnostic { 101 res.borrow_mut().push(Diagnostic {
98 range: d.highlight_range(), 102 range: sema.diagnostics_range(d).range,
99 message: d.message(), 103 message: d.message(),
100 severity: Severity::Error, 104 severity: Severity::Error,
101 fix, 105 fix,
@@ -103,7 +107,7 @@ pub(crate) fn diagnostics(db: &RootDatabase, file_id: FileId) -> Vec<Diagnostic>
103 }) 107 })
104 .on::<hir::diagnostics::MissingMatchArms, _>(|d| { 108 .on::<hir::diagnostics::MissingMatchArms, _>(|d| {
105 res.borrow_mut().push(Diagnostic { 109 res.borrow_mut().push(Diagnostic {
106 range: d.highlight_range(), 110 range: sema.diagnostics_range(d).range,
107 message: d.message(), 111 message: d.message(),
108 severity: Severity::Error, 112 severity: Severity::Error,
109 fix: None, 113 fix: None,
@@ -115,7 +119,7 @@ pub(crate) fn diagnostics(db: &RootDatabase, file_id: FileId) -> Vec<Diagnostic>
115 let edit = TextEdit::replace(node.syntax().text_range(), replacement); 119 let edit = TextEdit::replace(node.syntax().text_range(), replacement);
116 let fix = SourceChange::source_file_edit_from("wrap with ok", file_id, edit); 120 let fix = SourceChange::source_file_edit_from("wrap with ok", file_id, edit);
117 res.borrow_mut().push(Diagnostic { 121 res.borrow_mut().push(Diagnostic {
118 range: d.highlight_range(), 122 range: sema.diagnostics_range(d).range,
119 message: d.message(), 123 message: d.message(),
120 severity: Severity::Error, 124 severity: Severity::Error,
121 fix: Some(fix), 125 fix: Some(fix),
@@ -622,6 +626,62 @@ mod tests {
622 } 626 }
623 627
624 #[test] 628 #[test]
629 fn range_mapping_out_of_macros() {
630 let (analysis, file_id) = single_file(
631 r"
632 fn some() {}
633 fn items() {}
634 fn here() {}
635
636 macro_rules! id {
637 ($($tt:tt)*) => { $($tt)*};
638 }
639
640 fn main() {
641 let _x = id![Foo { a: 42 }];
642 }
643
644 pub struct Foo {
645 pub a: i32,
646 pub b: i32,
647 }
648 ",
649 );
650 let diagnostics = analysis.diagnostics(file_id).unwrap();
651 assert_debug_snapshot!(diagnostics, @r###"
652 [
653 Diagnostic {
654 message: "Missing structure fields:\n- b",
655 range: [224; 233),
656 fix: Some(
657 SourceChange {
658 label: "fill struct fields",
659 source_file_edits: [
660 SourceFileEdit {
661 file_id: FileId(
662 1,
663 ),
664 edit: TextEdit {
665 atoms: [
666 AtomTextEdit {
667 delete: [3; 9),
668 insert: "{a:42, b: ()}",
669 },
670 ],
671 },
672 },
673 ],
674 file_system_edits: [],
675 cursor_position: None,
676 },
677 ),
678 severity: Error,
679 },
680 ]
681 "###);
682 }
683
684 #[test]
625 fn test_check_unnecessary_braces_in_use_statement() { 685 fn test_check_unnecessary_braces_in_use_statement() {
626 check_not_applicable( 686 check_not_applicable(
627 " 687 "
diff --git a/crates/ra_ide/src/inlay_hints.rs b/crates/ra_ide/src/inlay_hints.rs
index 45b9f7802..0774fa0a1 100644
--- a/crates/ra_ide/src/inlay_hints.rs
+++ b/crates/ra_ide/src/inlay_hints.rs
@@ -237,7 +237,8 @@ fn should_show_param_hint(
237) -> bool { 237) -> bool {
238 if param_name.is_empty() 238 if param_name.is_empty()
239 || is_argument_similar_to_param(argument, param_name) 239 || is_argument_similar_to_param(argument, param_name)
240 || Some(param_name) == fn_signature.name.as_ref().map(String::as_str) 240 || Some(param_name.trim_start_matches('_'))
241 == fn_signature.name.as_ref().map(|s| s.trim_start_matches('_'))
241 { 242 {
242 return false; 243 return false;
243 } 244 }
@@ -255,6 +256,8 @@ fn should_show_param_hint(
255 256
256fn is_argument_similar_to_param(argument: &ast::Expr, param_name: &str) -> bool { 257fn is_argument_similar_to_param(argument: &ast::Expr, param_name: &str) -> bool {
257 let argument_string = remove_ref(argument.clone()).syntax().to_string(); 258 let argument_string = remove_ref(argument.clone()).syntax().to_string();
259 let param_name = param_name.trim_start_matches('_');
260 let argument_string = argument_string.trim_start_matches('_');
258 argument_string.starts_with(&param_name) || argument_string.ends_with(&param_name) 261 argument_string.starts_with(&param_name) || argument_string.ends_with(&param_name)
259} 262}
260 263
@@ -1094,8 +1097,10 @@ struct Param {}
1094 1097
1095fn different_order(param: &Param) {} 1098fn different_order(param: &Param) {}
1096fn different_order_mut(param: &mut Param) {} 1099fn different_order_mut(param: &mut Param) {}
1100fn has_underscore(_param: bool) {}
1097 1101
1098fn twiddle(twiddle: bool) {} 1102fn twiddle(twiddle: bool) {}
1103fn doo(_doo: bool) {}
1099 1104
1100fn main() { 1105fn main() {
1101 let container: TestVarContainer = TestVarContainer { test_var: 42 }; 1106 let container: TestVarContainer = TestVarContainer { test_var: 42 };
@@ -1112,11 +1117,15 @@ fn main() {
1112 test_processed.frob(false); 1117 test_processed.frob(false);
1113 1118
1114 twiddle(true); 1119 twiddle(true);
1120 doo(true);
1115 1121
1116 let param_begin: Param = Param {}; 1122 let param_begin: Param = Param {};
1117 different_order(&param_begin); 1123 different_order(&param_begin);
1118 different_order(&mut param_begin); 1124 different_order(&mut param_begin);
1119 1125
1126 let param: bool = true;
1127 has_underscore(param);
1128
1120 let a: f64 = 7.0; 1129 let a: f64 = 7.0;
1121 let b: f64 = 4.0; 1130 let b: f64 = 4.0;
1122 let _: f64 = a.div_euclid(b); 1131 let _: f64 = a.div_euclid(b);
diff --git a/crates/ra_ide/src/marks.rs b/crates/ra_ide/src/marks.rs
index 5e1f135c5..eee44e886 100644
--- a/crates/ra_ide/src/marks.rs
+++ b/crates/ra_ide/src/marks.rs
@@ -8,4 +8,5 @@ test_utils::marks!(
8 test_resolve_parent_module_on_module_decl 8 test_resolve_parent_module_on_module_decl
9 search_filters_by_range 9 search_filters_by_range
10 dont_insert_macro_call_parens_unncessary 10 dont_insert_macro_call_parens_unncessary
11 self_fulfilling_completion
11); 12);
diff --git a/crates/ra_ide/src/syntax_highlighting.rs b/crates/ra_ide/src/syntax_highlighting.rs
index 83d161f45..7b15b82bd 100644
--- a/crates/ra_ide/src/syntax_highlighting.rs
+++ b/crates/ra_ide/src/syntax_highlighting.rs
@@ -174,7 +174,8 @@ pub(crate) fn highlight(
174 } 174 }
175 175
176 assert_eq!(res.len(), 1, "after DFS traversal, the stack should only contain a single element"); 176 assert_eq!(res.len(), 1, "after DFS traversal, the stack should only contain a single element");
177 let res = res.pop().unwrap(); 177 let mut res = res.pop().unwrap();
178 res.sort_by_key(|range| range.range.start());
178 // Check that ranges are sorted and disjoint 179 // Check that ranges are sorted and disjoint
179 assert!(res 180 assert!(res
180 .iter() 181 .iter()
diff --git a/crates/ra_ide/src/syntax_highlighting/tests.rs b/crates/ra_ide/src/syntax_highlighting/tests.rs
index 110887c2a..73611e23a 100644
--- a/crates/ra_ide/src/syntax_highlighting/tests.rs
+++ b/crates/ra_ide/src/syntax_highlighting/tests.rs
@@ -156,3 +156,15 @@ fn main() {
156 fs::write(dst_file, &actual_html).unwrap(); 156 fs::write(dst_file, &actual_html).unwrap();
157 assert_eq_text!(expected_html, actual_html); 157 assert_eq_text!(expected_html, actual_html);
158} 158}
159
160#[test]
161fn ranges_sorted() {
162 let (analysis, file_id) = single_file(
163 r#"
164#[foo(bar = "bar")]
165macro_rules! test {}
166}"#
167 .trim(),
168 );
169 let _ = analysis.highlight(file_id).unwrap();
170}
diff --git a/crates/ra_proc_macro_srv/Cargo.toml b/crates/ra_proc_macro_srv/Cargo.toml
index 1e0f50339..ac2d156dc 100644
--- a/crates/ra_proc_macro_srv/Cargo.toml
+++ b/crates/ra_proc_macro_srv/Cargo.toml
@@ -14,6 +14,7 @@ ra_mbe = { path = "../ra_mbe" }
14ra_proc_macro = { path = "../ra_proc_macro" } 14ra_proc_macro = { path = "../ra_proc_macro" }
15goblin = "0.2.1" 15goblin = "0.2.1"
16libloading = "0.6.0" 16libloading = "0.6.0"
17memmap = "0.7"
17test_utils = { path = "../test_utils" } 18test_utils = { path = "../test_utils" }
18 19
19[dev-dependencies] 20[dev-dependencies]
diff --git a/crates/ra_proc_macro_srv/src/dylib.rs b/crates/ra_proc_macro_srv/src/dylib.rs
index ec63d587b..16bd7466e 100644
--- a/crates/ra_proc_macro_srv/src/dylib.rs
+++ b/crates/ra_proc_macro_srv/src/dylib.rs
@@ -1,10 +1,12 @@
1//! Handles dynamic library loading for proc macro 1//! Handles dynamic library loading for proc macro
2 2
3use crate::{proc_macro::bridge, rustc_server::TokenStream}; 3use crate::{proc_macro::bridge, rustc_server::TokenStream};
4use std::fs::File;
4use std::path::Path; 5use std::path::Path;
5 6
6use goblin::{mach::Mach, Object}; 7use goblin::{mach::Mach, Object};
7use libloading::Library; 8use libloading::Library;
9use memmap::Mmap;
8use ra_proc_macro::ProcMacroKind; 10use ra_proc_macro::ProcMacroKind;
9 11
10use std::io::Error as IoError; 12use std::io::Error as IoError;
@@ -16,55 +18,54 @@ fn invalid_data_err(e: impl Into<Box<dyn std::error::Error + Send + Sync>>) -> I
16 IoError::new(IoErrorKind::InvalidData, e) 18 IoError::new(IoErrorKind::InvalidData, e)
17} 19}
18 20
19fn get_symbols_from_lib(file: &Path) -> Result<Vec<String>, IoError> { 21fn is_derive_registrar_symbol(symbol: &str) -> bool {
20 let buffer = std::fs::read(file)?; 22 symbol.contains(NEW_REGISTRAR_SYMBOL)
23}
24
25fn find_registrar_symbol(file: &Path) -> Result<Option<String>, IoError> {
26 let file = File::open(file)?;
27 let buffer = unsafe { Mmap::map(&file)? };
21 let object = Object::parse(&buffer).map_err(invalid_data_err)?; 28 let object = Object::parse(&buffer).map_err(invalid_data_err)?;
22 29
23 match object { 30 match object {
24 Object::Elf(elf) => { 31 Object::Elf(elf) => {
25 let symbols = elf.dynstrtab.to_vec().map_err(invalid_data_err)?; 32 let symbols = elf.dynstrtab.to_vec().map_err(invalid_data_err)?;
26 let names = symbols.iter().map(|s| s.to_string()).collect(); 33 let name =
27 Ok(names) 34 symbols.iter().find(|s| is_derive_registrar_symbol(s)).map(|s| s.to_string());
35 Ok(name)
28 } 36 }
29 Object::PE(pe) => { 37 Object::PE(pe) => {
30 let symbol_names = 38 let name = pe
31 pe.exports.iter().flat_map(|s| s.name).map(|n| n.to_string()).collect(); 39 .exports
32 Ok(symbol_names) 40 .iter()
41 .flat_map(|s| s.name)
42 .find(|s| is_derive_registrar_symbol(s))
43 .map(|s| s.to_string());
44 Ok(name)
33 } 45 }
34 Object::Mach(mach) => match mach { 46 Object::Mach(Mach::Binary(binary)) => {
35 Mach::Binary(binary) => { 47 let exports = binary.exports().map_err(invalid_data_err)?;
36 let exports = binary.exports().map_err(invalid_data_err)?; 48 let name = exports
37 let names = exports 49 .iter()
38 .into_iter() 50 .map(|s| {
39 .map(|s| { 51 // In macos doc:
40 // In macos doc: 52 // https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/dlsym.3.html
41 // https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/dlsym.3.html 53 // Unlike other dyld API's, the symbol name passed to dlsym() must NOT be
42 // Unlike other dyld API's, the symbol name passed to dlsym() must NOT be 54 // prepended with an underscore.
43 // prepended with an underscore. 55 if s.name.starts_with("_") {
44 if s.name.starts_with("_") { 56 &s.name[1..]
45 s.name[1..].to_string() 57 } else {
46 } else { 58 &s.name
47 s.name 59 }
48 } 60 })
49 }) 61 .find(|s| is_derive_registrar_symbol(s))
50 .collect(); 62 .map(|s| s.to_string());
51 Ok(names) 63 Ok(name)
52 } 64 }
53 Mach::Fat(_) => Ok(vec![]), 65 _ => Ok(None),
54 },
55 Object::Archive(_) | Object::Unknown(_) => Ok(vec![]),
56 } 66 }
57} 67}
58 68
59fn is_derive_registrar_symbol(symbol: &str) -> bool {
60 symbol.contains(NEW_REGISTRAR_SYMBOL)
61}
62
63fn find_registrar_symbol(file: &Path) -> Result<Option<String>, IoError> {
64 let symbols = get_symbols_from_lib(file)?;
65 Ok(symbols.into_iter().find(|s| is_derive_registrar_symbol(s)))
66}
67
68/// Loads dynamic library in platform dependent manner. 69/// Loads dynamic library in platform dependent manner.
69/// 70///
70/// For unix, you have to use RTLD_DEEPBIND flag to escape problems described 71/// For unix, you have to use RTLD_DEEPBIND flag to escape problems described
diff --git a/crates/rust-analyzer/src/cli/load_cargo.rs b/crates/rust-analyzer/src/cli/load_cargo.rs
index eb9ac32c3..762f776fe 100644
--- a/crates/rust-analyzer/src/cli/load_cargo.rs
+++ b/crates/rust-analyzer/src/cli/load_cargo.rs
@@ -75,9 +75,7 @@ pub(crate) fn load_cargo(
75 let proc_macro_client = if !with_proc_macro { 75 let proc_macro_client = if !with_proc_macro {
76 ProcMacroClient::dummy() 76 ProcMacroClient::dummy()
77 } else { 77 } else {
78 let mut path = std::env::current_exe()?; 78 let path = std::env::current_exe()?;
79 path.pop();
80 path.push("rust-analyzer");
81 ProcMacroClient::extern_process(&path, &["proc-macro"]).unwrap() 79 ProcMacroClient::extern_process(&path, &["proc-macro"]).unwrap()
82 }; 80 };
83 let host = load(&source_roots, ws, &mut vfs, receiver, extern_dirs, &proc_macro_client); 81 let host = load(&source_roots, ws, &mut vfs, receiver, extern_dirs, &proc_macro_client);
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index 2b45f1310..3597a14e3 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -134,9 +134,7 @@ impl Config {
134 134
135 match get::<bool>(value, "/procMacro/enabled") { 135 match get::<bool>(value, "/procMacro/enabled") {
136 Some(true) => { 136 Some(true) => {
137 if let Ok(mut path) = std::env::current_exe() { 137 if let Ok(path) = std::env::current_exe() {
138 path.pop();
139 path.push("rust-analyzer");
140 self.proc_macro_srv = Some((path.to_string_lossy().to_string(), vec!["proc-macro".to_string()])); 138 self.proc_macro_srv = Some((path.to_string_lossy().to_string(), vec!["proc-macro".to_string()]));
141 } 139 }
142 } 140 }
diff --git a/xtask/tests/tidy-tests/main.rs b/xtask/tests/tidy-tests/main.rs
index 101ae19bd..ead642acc 100644
--- a/xtask/tests/tidy-tests/main.rs
+++ b/xtask/tests/tidy-tests/main.rs
@@ -35,7 +35,7 @@ fn check_todo(path: &Path, text: &str) {
35 } 35 }
36 if text.contains("TODO") || text.contains("TOOD") || text.contains("todo!") { 36 if text.contains("TODO") || text.contains("TOOD") || text.contains("todo!") {
37 panic!( 37 panic!(
38 "\nTODO markers should not be committed to the master branch,\n\ 38 "\nTODO markers or todo! macros should not be committed to the master branch,\n\
39 use FIXME instead\n\ 39 use FIXME instead\n\
40 {}\n", 40 {}\n",
41 path.display(), 41 path.display(),
@@ -47,9 +47,9 @@ fn check_trailing_ws(path: &Path, text: &str) {
47 if is_exclude_dir(path, &["test_data"]) { 47 if is_exclude_dir(path, &["test_data"]) {
48 return; 48 return;
49 } 49 }
50 for line in text.lines() { 50 for (line_number, line) in text.lines().enumerate() {
51 if line.chars().last().map(char::is_whitespace) == Some(true) { 51 if line.chars().last().map(char::is_whitespace) == Some(true) {
52 panic!("Trailing whitespace in {}", path.display()) 52 panic!("Trailing whitespace in {} at line {}", path.display(), line_number)
53 } 53 }
54 } 54 }
55} 55}