aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_assists/src/assists/add_missing_impl_members.rs8
-rw-r--r--crates/ra_assists/src/assists/auto_import.rs1
-rw-r--r--crates/ra_assists/src/ast_editor.rs72
-rw-r--r--crates/ra_assists/src/lib.rs1
-rw-r--r--crates/ra_hir/src/code_model.rs14
-rw-r--r--crates/ra_hir/src/marks.rs1
-rw-r--r--crates/ra_hir/src/ty.rs141
-rw-r--r--crates/ra_hir/src/ty/autoderef.rs14
-rw-r--r--crates/ra_hir/src/ty/infer.rs15
-rw-r--r--crates/ra_hir/src/ty/infer/path.rs10
-rw-r--r--crates/ra_hir/src/ty/infer/unify.rs24
-rw-r--r--crates/ra_hir/src/ty/lower.rs20
-rw-r--r--crates/ra_hir/src/ty/method_resolution.rs18
-rw-r--r--crates/ra_hir/src/ty/tests.rs1
-rw-r--r--crates/ra_hir/src/ty/traits/chalk.rs80
-rw-r--r--crates/ra_ide_api/src/line_index.rs1
-rw-r--r--crates/ra_ide_api/src/runnables.rs1
-rw-r--r--crates/ra_lsp_server/src/markdown.rs1
-rw-r--r--crates/ra_parser/src/grammar.rs1
-rw-r--r--crates/ra_syntax/Cargo.toml2
-rw-r--r--crates/ra_syntax/src/ast.rs1
-rw-r--r--crates/ra_syntax/src/ast/edit.rs52
-rw-r--r--crates/ra_syntax/src/ast/make.rs48
23 files changed, 319 insertions, 208 deletions
diff --git a/crates/ra_assists/src/assists/add_missing_impl_members.rs b/crates/ra_assists/src/assists/add_missing_impl_members.rs
index 23da1e65f..682455bce 100644
--- a/crates/ra_assists/src/assists/add_missing_impl_members.rs
+++ b/crates/ra_assists/src/assists/add_missing_impl_members.rs
@@ -100,12 +100,11 @@ fn strip_docstring(item: ast::ImplItem) -> ast::ImplItem {
100} 100}
101 101
102fn add_body(fn_def: ast::FnDef) -> ast::FnDef { 102fn add_body(fn_def: ast::FnDef) -> ast::FnDef {
103 let mut ast_editor = AstEditor::new(fn_def.clone());
104 if fn_def.body().is_none() { 103 if fn_def.body().is_none() {
105 let body = make::block_from_expr(make::expr_unimplemented()); 104 fn_def.with_body(make::block_from_expr(make::expr_unimplemented()))
106 ast_editor.set_body(&body); 105 } else {
106 fn_def
107 } 107 }
108 ast_editor.ast().to_owned()
109} 108}
110 109
111/// Given an `ast::ImplBlock`, resolves the target trait (the one being 110/// Given an `ast::ImplBlock`, resolves the target trait (the one being
@@ -332,5 +331,4 @@ impl Foo for S {
332}", 331}",
333 ) 332 )
334 } 333 }
335
336} 334}
diff --git a/crates/ra_assists/src/assists/auto_import.rs b/crates/ra_assists/src/assists/auto_import.rs
index 43c14ad23..419e93330 100644
--- a/crates/ra_assists/src/assists/auto_import.rs
+++ b/crates/ra_assists/src/assists/auto_import.rs
@@ -448,7 +448,6 @@ fn make_assist_add_in_tree_list(
448 fmt_segments_raw(target, &mut buf); 448 fmt_segments_raw(target, &mut buf);
449 edit.insert(offset, buf); 449 edit.insert(offset, buf);
450 } else { 450 } else {
451
452 } 451 }
453} 452}
454 453
diff --git a/crates/ra_assists/src/ast_editor.rs b/crates/ra_assists/src/ast_editor.rs
index 2a685f26e..72c8c478a 100644
--- a/crates/ra_assists/src/ast_editor.rs
+++ b/crates/ra_assists/src/ast_editor.rs
@@ -6,7 +6,7 @@ use rustc_hash::FxHashMap;
6use ra_fmt::leading_indent; 6use ra_fmt::leading_indent;
7use ra_syntax::{ 7use ra_syntax::{
8 algo, 8 algo,
9 ast::{self, TypeBoundsOwner}, 9 ast::{self, make::tokens, TypeBoundsOwner},
10 AstNode, Direction, InsertPosition, SyntaxElement, 10 AstNode, Direction, InsertPosition, SyntaxElement,
11 SyntaxKind::*, 11 SyntaxKind::*,
12 T, 12 T,
@@ -229,26 +229,6 @@ impl AstEditor<ast::ImplItem> {
229 } 229 }
230} 230}
231 231
232impl AstEditor<ast::FnDef> {
233 pub fn set_body(&mut self, body: &ast::Block) {
234 let mut to_insert: ArrayVec<[SyntaxElement; 2]> = ArrayVec::new();
235 let old_body_or_semi: SyntaxElement = if let Some(old_body) = self.ast().body() {
236 old_body.syntax().clone().into()
237 } else if let Some(semi) = self.ast().semicolon_token() {
238 to_insert.push(tokens::single_space().into());
239 semi.into()
240 } else {
241 to_insert.push(tokens::single_space().into());
242 to_insert.push(body.syntax().clone().into());
243 self.ast = self.insert_children(InsertPosition::Last, to_insert.into_iter());
244 return;
245 };
246 to_insert.push(body.syntax().clone().into());
247 let replace_range = RangeInclusive::new(old_body_or_semi.clone(), old_body_or_semi);
248 self.ast = self.replace_children(replace_range, to_insert.into_iter())
249 }
250}
251
252impl AstEditor<ast::TypeParam> { 232impl AstEditor<ast::TypeParam> {
253 pub fn remove_bounds(&mut self) -> &mut Self { 233 pub fn remove_bounds(&mut self) -> &mut Self {
254 let colon = match self.ast.colon_token() { 234 let colon = match self.ast.colon_token() {
@@ -263,53 +243,3 @@ impl AstEditor<ast::TypeParam> {
263 self 243 self
264 } 244 }
265} 245}
266
267mod tokens {
268 use once_cell::sync::Lazy;
269 use ra_syntax::{AstNode, Parse, SourceFile, SyntaxKind::*, SyntaxToken, T};
270
271 static SOURCE_FILE: Lazy<Parse<SourceFile>> = Lazy::new(|| SourceFile::parse(",\n; ;"));
272
273 pub(crate) fn comma() -> SyntaxToken {
274 SOURCE_FILE
275 .tree()
276 .syntax()
277 .descendants_with_tokens()
278 .filter_map(|it| it.into_token())
279 .find(|it| it.kind() == T![,])
280 .unwrap()
281 }
282
283 pub(crate) fn single_space() -> SyntaxToken {
284 SOURCE_FILE
285 .tree()
286 .syntax()
287 .descendants_with_tokens()
288 .filter_map(|it| it.into_token())
289 .find(|it| it.kind() == WHITESPACE && it.text().as_str() == " ")
290 .unwrap()
291 }
292
293 #[allow(unused)]
294 pub(crate) fn single_newline() -> SyntaxToken {
295 SOURCE_FILE
296 .tree()
297 .syntax()
298 .descendants_with_tokens()
299 .filter_map(|it| it.into_token())
300 .find(|it| it.kind() == WHITESPACE && it.text().as_str() == "\n")
301 .unwrap()
302 }
303
304 pub(crate) struct WsBuilder(SourceFile);
305
306 impl WsBuilder {
307 pub(crate) fn new(text: &str) -> WsBuilder {
308 WsBuilder(SourceFile::parse(text).ok().unwrap())
309 }
310 pub(crate) fn ws(&self) -> SyntaxToken {
311 self.0.syntax().first_child_or_token().unwrap().into_token().unwrap()
312 }
313 }
314
315}
diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs
index 897af2b02..3ca3320f7 100644
--- a/crates/ra_assists/src/lib.rs
+++ b/crates/ra_assists/src/lib.rs
@@ -340,5 +340,4 @@ mod tests {
340 assert_eq!(assists.next().expect("expected assist").0.label, "introduce variable"); 340 assert_eq!(assists.next().expect("expected assist").0.label, "introduce variable");
341 assert_eq!(assists.next().expect("expected assist").0.label, "replace with match"); 341 assert_eq!(assists.next().expect("expected assist").0.label, "replace with match");
342 } 342 }
343
344} 343}
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs
index 20413cb3d..fd7afcbb6 100644
--- a/crates/ra_hir/src/code_model.rs
+++ b/crates/ra_hir/src/code_model.rs
@@ -339,10 +339,14 @@ pub struct Struct {
339} 339}
340 340
341impl Struct { 341impl Struct {
342 pub fn module(self, db: &impl HirDatabase) -> Module { 342 pub fn module(self, db: &impl DefDatabase) -> Module {
343 self.id.module(db) 343 self.id.module(db)
344 } 344 }
345 345
346 pub fn krate(self, db: &impl DefDatabase) -> Option<Crate> {
347 self.module(db).krate(db)
348 }
349
346 pub fn name(self, db: &impl DefDatabase) -> Option<Name> { 350 pub fn name(self, db: &impl DefDatabase) -> Option<Name> {
347 db.struct_data(self).name.clone() 351 db.struct_data(self).name.clone()
348 } 352 }
@@ -423,10 +427,14 @@ pub struct Enum {
423} 427}
424 428
425impl Enum { 429impl Enum {
426 pub fn module(self, db: &impl HirDatabase) -> Module { 430 pub fn module(self, db: &impl DefDatabase) -> Module {
427 self.id.module(db) 431 self.id.module(db)
428 } 432 }
429 433
434 pub fn krate(self, db: &impl DefDatabase) -> Option<Crate> {
435 self.module(db).krate(db)
436 }
437
430 pub fn name(self, db: &impl DefDatabase) -> Option<Name> { 438 pub fn name(self, db: &impl DefDatabase) -> Option<Name> {
431 db.enum_data(self).name.clone() 439 db.enum_data(self).name.clone()
432 } 440 }
@@ -514,7 +522,7 @@ impl Adt {
514 } 522 }
515 } 523 }
516 524
517 pub(crate) fn krate(self, db: &impl HirDatabase) -> Option<Crate> { 525 pub fn krate(self, db: &impl HirDatabase) -> Option<Crate> {
518 match self { 526 match self {
519 Adt::Struct(s) => s.module(db), 527 Adt::Struct(s) => s.module(db),
520 Adt::Union(s) => s.module(db), 528 Adt::Union(s) => s.module(db),
diff --git a/crates/ra_hir/src/marks.rs b/crates/ra_hir/src/marks.rs
index 72f76bb79..0fed46802 100644
--- a/crates/ra_hir/src/marks.rs
+++ b/crates/ra_hir/src/marks.rs
@@ -9,7 +9,6 @@ test_utils::marks!(
9 glob_across_crates 9 glob_across_crates
10 std_prelude 10 std_prelude
11 match_ergonomics_ref 11 match_ergonomics_ref
12 trait_resolution_on_fn_type
13 infer_while_let 12 infer_while_let
14 macro_rules_from_other_crates_are_visible_with_macro_use 13 macro_rules_from_other_crates_are_visible_with_macro_use
15 prelude_is_macro_use 14 prelude_is_macro_use
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs
index fae9c1e22..d161735e8 100644
--- a/crates/ra_hir/src/ty.rs
+++ b/crates/ra_hir/src/ty.rs
@@ -14,11 +14,11 @@ pub(crate) mod display;
14 14
15use std::ops::Deref; 15use std::ops::Deref;
16use std::sync::Arc; 16use std::sync::Arc;
17use std::{fmt, mem}; 17use std::{fmt, iter, mem};
18 18
19use crate::{ 19use crate::{
20 db::HirDatabase, expr::ExprId, type_ref::Mutability, Adt, DefWithBody, GenericParams, Name, 20 db::HirDatabase, expr::ExprId, type_ref::Mutability, Adt, Crate, DefWithBody, GenericParams,
21 Trait, TypeAlias, 21 HasGenericParams, Name, Trait, TypeAlias,
22}; 22};
23use display::{HirDisplay, HirFormatter}; 23use display::{HirDisplay, HirFormatter};
24 24
@@ -111,6 +111,81 @@ pub enum TypeCtor {
111 Closure { def: DefWithBody, expr: ExprId }, 111 Closure { def: DefWithBody, expr: ExprId },
112} 112}
113 113
114impl TypeCtor {
115 pub fn num_ty_params(self, db: &impl HirDatabase) -> usize {
116 match self {
117 TypeCtor::Bool
118 | TypeCtor::Char
119 | TypeCtor::Int(_)
120 | TypeCtor::Float(_)
121 | TypeCtor::Str
122 | TypeCtor::Never => 0,
123 TypeCtor::Slice
124 | TypeCtor::Array
125 | TypeCtor::RawPtr(_)
126 | TypeCtor::Ref(_)
127 | TypeCtor::Closure { .. } // 1 param representing the signature of the closure
128 => 1,
129 TypeCtor::Adt(adt) => {
130 let generic_params = adt.generic_params(db);
131 generic_params.count_params_including_parent()
132 }
133 TypeCtor::FnDef(callable) => {
134 let generic_params = callable.generic_params(db);
135 generic_params.count_params_including_parent()
136 }
137 TypeCtor::AssociatedType(type_alias) => {
138 let generic_params = type_alias.generic_params(db);
139 generic_params.count_params_including_parent()
140 }
141 TypeCtor::FnPtr { num_args } => num_args as usize + 1,
142 TypeCtor::Tuple { cardinality } => cardinality as usize,
143 }
144 }
145
146 pub fn krate(self, db: &impl HirDatabase) -> Option<Crate> {
147 match self {
148 TypeCtor::Bool
149 | TypeCtor::Char
150 | TypeCtor::Int(_)
151 | TypeCtor::Float(_)
152 | TypeCtor::Str
153 | TypeCtor::Never
154 | TypeCtor::Slice
155 | TypeCtor::Array
156 | TypeCtor::RawPtr(_)
157 | TypeCtor::Ref(_)
158 | TypeCtor::FnPtr { .. }
159 | TypeCtor::Tuple { .. } => None,
160 TypeCtor::Closure { def, .. } => def.krate(db),
161 TypeCtor::Adt(adt) => adt.krate(db),
162 TypeCtor::FnDef(callable) => callable.krate(db),
163 TypeCtor::AssociatedType(type_alias) => type_alias.krate(db),
164 }
165 }
166
167 pub fn as_generic_def(self) -> Option<crate::generics::GenericDef> {
168 match self {
169 TypeCtor::Bool
170 | TypeCtor::Char
171 | TypeCtor::Int(_)
172 | TypeCtor::Float(_)
173 | TypeCtor::Str
174 | TypeCtor::Never
175 | TypeCtor::Slice
176 | TypeCtor::Array
177 | TypeCtor::RawPtr(_)
178 | TypeCtor::Ref(_)
179 | TypeCtor::FnPtr { .. }
180 | TypeCtor::Tuple { .. }
181 | TypeCtor::Closure { .. } => None,
182 TypeCtor::Adt(adt) => Some(adt.into()),
183 TypeCtor::FnDef(callable) => Some(callable.into()),
184 TypeCtor::AssociatedType(type_alias) => Some(type_alias.into()),
185 }
186 }
187}
188
114/// A nominal type with (maybe 0) type parameters. This might be a primitive 189/// A nominal type with (maybe 0) type parameters. This might be a primitive
115/// type like `bool`, a struct, tuple, function pointer, reference or 190/// type like `bool`, a struct, tuple, function pointer, reference or
116/// several other things. 191/// several other things.
@@ -271,11 +346,65 @@ impl Substs {
271 .into(), 346 .into(),
272 ) 347 )
273 } 348 }
349
350 pub fn build_for_def(
351 db: &impl HirDatabase,
352 def: impl crate::HasGenericParams,
353 ) -> SubstsBuilder {
354 let params = def.generic_params(db);
355 let param_count = params.count_params_including_parent();
356 Substs::builder(param_count)
357 }
358
359 pub fn build_for_generics(generic_params: &GenericParams) -> SubstsBuilder {
360 Substs::builder(generic_params.count_params_including_parent())
361 }
362
363 pub fn build_for_type_ctor(db: &impl HirDatabase, type_ctor: TypeCtor) -> SubstsBuilder {
364 Substs::builder(type_ctor.num_ty_params(db))
365 }
366
367 fn builder(param_count: usize) -> SubstsBuilder {
368 SubstsBuilder { vec: Vec::with_capacity(param_count), param_count }
369 }
370}
371
372#[derive(Debug, Clone)]
373pub struct SubstsBuilder {
374 vec: Vec<Ty>,
375 param_count: usize,
274} 376}
275 377
276impl From<Vec<Ty>> for Substs { 378impl SubstsBuilder {
277 fn from(v: Vec<Ty>) -> Self { 379 pub fn build(self) -> Substs {
278 Substs(v.into()) 380 assert_eq!(self.vec.len(), self.param_count);
381 Substs(self.vec.into())
382 }
383
384 pub fn push(mut self, ty: Ty) -> Self {
385 self.vec.push(ty);
386 self
387 }
388
389 fn remaining(&self) -> usize {
390 self.param_count - self.vec.len()
391 }
392
393 pub fn fill_with_bound_vars(mut self, starting_from: u32) -> Self {
394 self.vec.extend((starting_from..starting_from + self.remaining() as u32).map(Ty::Bound));
395 self
396 }
397
398 pub fn fill_with_unknown(mut self) -> Self {
399 self.vec.extend(iter::repeat(Ty::Unknown).take(self.remaining()));
400 self
401 }
402
403 pub fn use_parent_substs(mut self, parent_substs: &Substs) -> Self {
404 assert!(self.vec.is_empty());
405 assert!(parent_substs.len() <= self.param_count);
406 self.vec.extend(parent_substs.iter().cloned());
407 self
279 } 408 }
280} 409}
281 410
diff --git a/crates/ra_hir/src/ty/autoderef.rs b/crates/ra_hir/src/ty/autoderef.rs
index 94f8ecdc9..02492ca14 100644
--- a/crates/ra_hir/src/ty/autoderef.rs
+++ b/crates/ra_hir/src/ty/autoderef.rs
@@ -7,7 +7,7 @@ use std::iter::successors;
7 7
8use log::{info, warn}; 8use log::{info, warn};
9 9
10use super::{traits::Solution, Canonical, Ty, TypeWalk}; 10use super::{traits::Solution, Canonical, Substs, Ty, TypeWalk};
11use crate::{db::HirDatabase, name, HasGenericParams, Resolver}; 11use crate::{db::HirDatabase, name, HasGenericParams, Resolver};
12 12
13const AUTODEREF_RECURSION_LIMIT: usize = 10; 13const AUTODEREF_RECURSION_LIMIT: usize = 10;
@@ -44,7 +44,8 @@ fn deref_by_trait(
44 }; 44 };
45 let target = deref_trait.associated_type_by_name(db, &name::TARGET_TYPE)?; 45 let target = deref_trait.associated_type_by_name(db, &name::TARGET_TYPE)?;
46 46
47 if target.generic_params(db).count_params_including_parent() != 1 { 47 let generic_params = target.generic_params(db);
48 if generic_params.count_params_including_parent() != 1 {
48 // the Target type + Deref trait should only have one generic parameter, 49 // the Target type + Deref trait should only have one generic parameter,
49 // namely Deref's Self type 50 // namely Deref's Self type
50 return None; 51 return None;
@@ -54,12 +55,13 @@ fn deref_by_trait(
54 55
55 let env = super::lower::trait_env(db, resolver); 56 let env = super::lower::trait_env(db, resolver);
56 57
58 let parameters = Substs::build_for_generics(&generic_params)
59 .push(ty.value.clone().shift_bound_vars(1))
60 .build();
61
57 let projection = super::traits::ProjectionPredicate { 62 let projection = super::traits::ProjectionPredicate {
58 ty: Ty::Bound(0), 63 ty: Ty::Bound(0),
59 projection_ty: super::ProjectionTy { 64 projection_ty: super::ProjectionTy { associated_ty: target, parameters },
60 associated_ty: target,
61 parameters: vec![ty.value.clone().shift_bound_vars(1)].into(),
62 },
63 }; 65 };
64 66
65 let obligation = super::Obligation::Projection(projection); 67 let obligation = super::Obligation::Projection(projection);
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs
index 8f92468e6..2e4a489a0 100644
--- a/crates/ra_hir/src/ty/infer.rs
+++ b/crates/ra_hir/src/ty/infer.rs
@@ -688,14 +688,13 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
688 }; 688 };
689 let expectations_iter = expectations.iter().chain(repeat(&Ty::Unknown)); 689 let expectations_iter = expectations.iter().chain(repeat(&Ty::Unknown));
690 690
691 let inner_tys: Substs = args 691 let inner_tys = args
692 .iter() 692 .iter()
693 .zip(expectations_iter) 693 .zip(expectations_iter)
694 .map(|(&pat, ty)| self.infer_pat(pat, ty, default_bm)) 694 .map(|(&pat, ty)| self.infer_pat(pat, ty, default_bm))
695 .collect::<Vec<_>>() 695 .collect();
696 .into();
697 696
698 Ty::apply(TypeCtor::Tuple { cardinality: inner_tys.len() as u16 }, inner_tys) 697 Ty::apply(TypeCtor::Tuple { cardinality: args.len() as u16 }, Substs(inner_tys))
699 } 698 }
700 Pat::Ref { pat, mutability } => { 699 Pat::Ref { pat, mutability } => {
701 let expectation = match expected.as_reference() { 700 let expectation = match expected.as_reference() {
@@ -1229,7 +1228,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
1229 ty: pat_ty.clone(), 1228 ty: pat_ty.clone(),
1230 projection_ty: ProjectionTy { 1229 projection_ty: ProjectionTy {
1231 associated_ty: into_iter_item_alias, 1230 associated_ty: into_iter_item_alias,
1232 parameters: vec![iterable_ty].into(), 1231 parameters: Substs::single(iterable_ty),
1233 }, 1232 },
1234 }; 1233 };
1235 self.obligations.push(Obligation::Projection(projection)); 1234 self.obligations.push(Obligation::Projection(projection));
@@ -1262,7 +1261,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
1262 sig_tys.push(ret_ty.clone()); 1261 sig_tys.push(ret_ty.clone());
1263 let sig_ty = Ty::apply( 1262 let sig_ty = Ty::apply(
1264 TypeCtor::FnPtr { num_args: sig_tys.len() as u16 - 1 }, 1263 TypeCtor::FnPtr { num_args: sig_tys.len() as u16 - 1 },
1265 sig_tys.into(), 1264 Substs(sig_tys.into()),
1266 ); 1265 );
1267 let closure_ty = Ty::apply_one( 1266 let closure_ty = Ty::apply_one(
1268 TypeCtor::Closure { def: self.body.owner(), expr: tgt_expr }, 1267 TypeCtor::Closure { def: self.body.owner(), expr: tgt_expr },
@@ -1399,7 +1398,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
1399 ty: ty.clone(), 1398 ty: ty.clone(),
1400 projection_ty: ProjectionTy { 1399 projection_ty: ProjectionTy {
1401 associated_ty: future_future_output_alias, 1400 associated_ty: future_future_output_alias,
1402 parameters: vec![inner_ty].into(), 1401 parameters: Substs::single(inner_ty),
1403 }, 1402 },
1404 }; 1403 };
1405 self.obligations.push(Obligation::Projection(projection)); 1404 self.obligations.push(Obligation::Projection(projection));
@@ -1418,7 +1417,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
1418 ty: ty.clone(), 1417 ty: ty.clone(),
1419 projection_ty: ProjectionTy { 1418 projection_ty: ProjectionTy {
1420 associated_ty: ops_try_ok_alias, 1419 associated_ty: ops_try_ok_alias,
1421 parameters: vec![inner_ty].into(), 1420 parameters: Substs::single(inner_ty),
1422 }, 1421 },
1423 }; 1422 };
1424 self.obligations.push(Obligation::Projection(projection)); 1423 self.obligations.push(Obligation::Projection(projection));
diff --git a/crates/ra_hir/src/ty/infer/path.rs b/crates/ra_hir/src/ty/infer/path.rs
index feb7481b2..db979353a 100644
--- a/crates/ra_hir/src/ty/infer/path.rs
+++ b/crates/ra_hir/src/ty/infer/path.rs
@@ -158,13 +158,13 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
158 AssocItem::Const(c) => ValueNs::Const(c), 158 AssocItem::Const(c) => ValueNs::Const(c),
159 AssocItem::TypeAlias(_) => unreachable!(), 159 AssocItem::TypeAlias(_) => unreachable!(),
160 }; 160 };
161 let generics = item.generic_params(self.db); 161 let substs = Substs::build_for_def(self.db, item)
162 let mut substs = Vec::with_capacity(generics.count_params_including_parent()); 162 .use_parent_substs(&trait_ref.substs)
163 substs.extend(trait_ref.substs.iter().cloned()); 163 .fill_with_unknown()
164 substs.extend(std::iter::repeat(Ty::Unknown).take(generics.params.len())); 164 .build();
165 165
166 self.write_assoc_resolution(id, item); 166 self.write_assoc_resolution(id, item);
167 Some((def, Some(substs.into()))) 167 Some((def, Some(substs)))
168 } 168 }
169 169
170 fn resolve_ty_assoc_item( 170 fn resolve_ty_assoc_item(
diff --git a/crates/ra_hir/src/ty/infer/unify.rs b/crates/ra_hir/src/ty/infer/unify.rs
index b6ebee3b1..d161aa6b3 100644
--- a/crates/ra_hir/src/ty/infer/unify.rs
+++ b/crates/ra_hir/src/ty/infer/unify.rs
@@ -3,7 +3,8 @@
3use super::{InferenceContext, Obligation}; 3use super::{InferenceContext, Obligation};
4use crate::db::HirDatabase; 4use crate::db::HirDatabase;
5use crate::ty::{ 5use crate::ty::{
6 Canonical, InEnvironment, InferTy, ProjectionPredicate, ProjectionTy, TraitRef, Ty, TypeWalk, 6 Canonical, InEnvironment, InferTy, ProjectionPredicate, ProjectionTy, Substs, TraitRef, Ty,
7 TypeWalk,
7}; 8};
8 9
9impl<'a, D: HirDatabase> InferenceContext<'a, D> { 10impl<'a, D: HirDatabase> InferenceContext<'a, D> {
@@ -74,12 +75,9 @@ where
74 } 75 }
75 76
76 fn do_canonicalize_trait_ref(&mut self, trait_ref: TraitRef) -> TraitRef { 77 fn do_canonicalize_trait_ref(&mut self, trait_ref: TraitRef) -> TraitRef {
77 let substs = trait_ref 78 let substs =
78 .substs 79 trait_ref.substs.iter().map(|ty| self.do_canonicalize_ty(ty.clone())).collect();
79 .iter() 80 TraitRef { trait_: trait_ref.trait_, substs: Substs(substs) }
80 .map(|ty| self.do_canonicalize_ty(ty.clone()))
81 .collect::<Vec<_>>();
82 TraitRef { trait_: trait_ref.trait_, substs: substs.into() }
83 } 81 }
84 82
85 fn into_canonicalized<T>(self, result: T) -> Canonicalized<T> { 83 fn into_canonicalized<T>(self, result: T) -> Canonicalized<T> {
@@ -90,12 +88,9 @@ where
90 } 88 }
91 89
92 fn do_canonicalize_projection_ty(&mut self, projection_ty: ProjectionTy) -> ProjectionTy { 90 fn do_canonicalize_projection_ty(&mut self, projection_ty: ProjectionTy) -> ProjectionTy {
93 let params = projection_ty 91 let params =
94 .parameters 92 projection_ty.parameters.iter().map(|ty| self.do_canonicalize_ty(ty.clone())).collect();
95 .iter() 93 ProjectionTy { associated_ty: projection_ty.associated_ty, parameters: Substs(params) }
96 .map(|ty| self.do_canonicalize_ty(ty.clone()))
97 .collect::<Vec<_>>();
98 ProjectionTy { associated_ty: projection_ty.associated_ty, parameters: params.into() }
99 } 94 }
100 95
101 fn do_canonicalize_projection_predicate( 96 fn do_canonicalize_projection_predicate(
@@ -153,8 +148,7 @@ impl<T> Canonicalized<T> {
153 solution: Canonical<Vec<Ty>>, 148 solution: Canonical<Vec<Ty>>,
154 ) { 149 ) {
155 // the solution may contain new variables, which we need to convert to new inference vars 150 // the solution may contain new variables, which we need to convert to new inference vars
156 let new_vars = 151 let new_vars = Substs((0..solution.num_vars).map(|_| ctx.new_type_var()).collect());
157 (0..solution.num_vars).map(|_| ctx.new_type_var()).collect::<Vec<_>>().into();
158 for (i, ty) in solution.value.into_iter().enumerate() { 152 for (i, ty) in solution.value.into_iter().enumerate() {
159 let var = self.free_vars[i]; 153 let var = self.free_vars[i];
160 ctx.unify(&Ty::Infer(var), &ty.subst_bound_vars(&new_vars)); 154 ctx.unify(&Ty::Infer(var), &ty.subst_bound_vars(&new_vars));
diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs
index dd503d771..4b67c82e7 100644
--- a/crates/ra_hir/src/ty/lower.rs
+++ b/crates/ra_hir/src/ty/lower.rs
@@ -239,14 +239,10 @@ impl Ty {
239 let traits = traits_from_env.flat_map(|t| t.all_super_traits(db)); 239 let traits = traits_from_env.flat_map(|t| t.all_super_traits(db));
240 for t in traits { 240 for t in traits {
241 if let Some(associated_ty) = t.associated_type_by_name(db, &segment.name) { 241 if let Some(associated_ty) = t.associated_type_by_name(db, &segment.name) {
242 let generics = t.generic_params(db); 242 let substs =
243 let mut substs = Vec::new(); 243 Substs::build_for_def(db, t).push(self_ty.clone()).fill_with_unknown().build();
244 substs.push(self_ty.clone());
245 substs.extend(
246 iter::repeat(Ty::Unknown).take(generics.count_params_including_parent() - 1),
247 );
248 // FIXME handle type parameters on the segment 244 // FIXME handle type parameters on the segment
249 return Ty::Projection(ProjectionTy { associated_ty, parameters: substs.into() }); 245 return Ty::Projection(ProjectionTy { associated_ty, parameters: substs });
250 } 246 }
251 } 247 }
252 Ty::Unknown 248 Ty::Unknown
@@ -766,6 +762,16 @@ pub enum CallableDef {
766} 762}
767impl_froms!(CallableDef: Function, Struct, EnumVariant); 763impl_froms!(CallableDef: Function, Struct, EnumVariant);
768 764
765impl CallableDef {
766 pub fn krate(self, db: &impl HirDatabase) -> Option<crate::Crate> {
767 match self {
768 CallableDef::Function(f) => f.krate(db),
769 CallableDef::Struct(s) => s.krate(db),
770 CallableDef::EnumVariant(e) => e.parent_enum(db).krate(db),
771 }
772 }
773}
774
769impl From<CallableDef> for GenericDef { 775impl From<CallableDef> for GenericDef {
770 fn from(def: CallableDef) -> GenericDef { 776 fn from(def: CallableDef) -> GenericDef {
771 match def { 777 match def {
diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs
index 4b71b376f..ad2ab560d 100644
--- a/crates/ra_hir/src/ty/method_resolution.rs
+++ b/crates/ra_hir/src/ty/method_resolution.rs
@@ -10,7 +10,6 @@ use rustc_hash::FxHashMap;
10use super::{autoderef, lower, Canonical, InEnvironment, TraitEnvironment, TraitRef}; 10use super::{autoderef, lower, Canonical, InEnvironment, TraitEnvironment, TraitRef};
11use crate::{ 11use crate::{
12 db::HirDatabase, 12 db::HirDatabase,
13 generics::HasGenericParams,
14 impl_block::{ImplBlock, ImplId}, 13 impl_block::{ImplBlock, ImplId},
15 nameres::CrateModuleId, 14 nameres::CrateModuleId,
16 resolve::Resolver, 15 resolve::Resolver,
@@ -331,20 +330,13 @@ fn generic_implements_goal(
331 trait_: Trait, 330 trait_: Trait,
332 self_ty: Canonical<Ty>, 331 self_ty: Canonical<Ty>,
333) -> Canonical<InEnvironment<super::Obligation>> { 332) -> Canonical<InEnvironment<super::Obligation>> {
334 let mut substs = Vec::new();
335 let generics = trait_.generic_params(db);
336 let num_vars = self_ty.num_vars; 333 let num_vars = self_ty.num_vars;
337 substs.push(self_ty.value); 334 let substs = super::Substs::build_for_def(db, trait_)
338 substs.extend( 335 .push(self_ty.value)
339 generics 336 .fill_with_bound_vars(num_vars as u32)
340 .params_including_parent() 337 .build();
341 .into_iter()
342 .skip(1)
343 .enumerate()
344 .map(|(i, _p)| Ty::Bound((i + num_vars) as u32)),
345 );
346 let num_vars = substs.len() - 1 + self_ty.num_vars; 338 let num_vars = substs.len() - 1 + self_ty.num_vars;
347 let trait_ref = TraitRef { trait_, substs: substs.into() }; 339 let trait_ref = TraitRef { trait_, substs };
348 let obligation = super::Obligation::Trait(trait_ref); 340 let obligation = super::Obligation::Trait(trait_ref);
349 Canonical { num_vars, value: InEnvironment::new(env, obligation) } 341 Canonical { num_vars, value: InEnvironment::new(env, obligation) }
350} 342}
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index bd2b07755..4df39c191 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -3354,7 +3354,6 @@ fn test() { S2.into()<|>; }
3354 3354
3355#[test] 3355#[test]
3356fn method_resolution_encountering_fn_type() { 3356fn method_resolution_encountering_fn_type() {
3357 covers!(trait_resolution_on_fn_type);
3358 type_at( 3357 type_at(
3359 r#" 3358 r#"
3360//- /main.rs 3359//- /main.rs
diff --git a/crates/ra_hir/src/ty/traits/chalk.rs b/crates/ra_hir/src/ty/traits/chalk.rs
index 538b4d3ec..2642a54bf 100644
--- a/crates/ra_hir/src/ty/traits/chalk.rs
+++ b/crates/ra_hir/src/ty/traits/chalk.rs
@@ -10,17 +10,13 @@ use chalk_ir::{
10use chalk_rust_ir::{AssociatedTyDatum, ImplDatum, StructDatum, TraitDatum}; 10use chalk_rust_ir::{AssociatedTyDatum, ImplDatum, StructDatum, TraitDatum};
11 11
12use ra_db::salsa::{InternId, InternKey}; 12use ra_db::salsa::{InternId, InternKey};
13use test_utils::tested_by;
14 13
15use super::{Canonical, ChalkContext, Impl, Obligation}; 14use super::{Canonical, ChalkContext, Impl, Obligation};
16use crate::{ 15use crate::{
17 db::HirDatabase, 16 db::HirDatabase,
18 generics::GenericDef, 17 generics::GenericDef,
19 ty::display::HirDisplay, 18 ty::display::HirDisplay,
20 ty::{ 19 ty::{ApplicationTy, GenericPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor, TypeWalk},
21 ApplicationTy, CallableDef, GenericPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor,
22 TypeWalk,
23 },
24 AssocItem, Crate, HasGenericParams, ImplBlock, Trait, TypeAlias, 20 AssocItem, Crate, HasGenericParams, ImplBlock, Trait, TypeAlias,
25}; 21};
26 22
@@ -124,14 +120,15 @@ impl ToChalk for Substs {
124 } 120 }
125 121
126 fn from_chalk(db: &impl HirDatabase, parameters: Vec<chalk_ir::Parameter>) -> Substs { 122 fn from_chalk(db: &impl HirDatabase, parameters: Vec<chalk_ir::Parameter>) -> Substs {
127 parameters 123 let tys = parameters
128 .into_iter() 124 .into_iter()
129 .map(|p| match p { 125 .map(|p| match p {
130 chalk_ir::Parameter(chalk_ir::ParameterKind::Ty(ty)) => from_chalk(db, ty), 126 chalk_ir::Parameter(chalk_ir::ParameterKind::Ty(ty)) => from_chalk(db, ty),
131 chalk_ir::Parameter(chalk_ir::ParameterKind::Lifetime(_)) => unimplemented!(), 127 chalk_ir::Parameter(chalk_ir::ParameterKind::Lifetime(_)) => unimplemented!(),
132 }) 128 })
133 .collect::<Vec<_>>() 129 .collect::<Vec<_>>()
134 .into() 130 .into();
131 Substs(tys)
135 } 132 }
136} 133}
137 134
@@ -539,60 +536,18 @@ pub(crate) fn struct_datum_query(
539 struct_id: chalk_ir::StructId, 536 struct_id: chalk_ir::StructId,
540) -> Arc<StructDatum> { 537) -> Arc<StructDatum> {
541 debug!("struct_datum {:?}", struct_id); 538 debug!("struct_datum {:?}", struct_id);
542 let type_ctor = from_chalk(db, struct_id); 539 let type_ctor: TypeCtor = from_chalk(db, struct_id);
543 debug!("struct {:?} = {:?}", struct_id, type_ctor); 540 debug!("struct {:?} = {:?}", struct_id, type_ctor);
544 // FIXME might be nicer if we can create a fake GenericParams for the TypeCtor 541 let num_params = type_ctor.num_ty_params(db);
545 // FIXME extract this to a method on Ty 542 let upstream = type_ctor.krate(db) != Some(krate);
546 let (num_params, where_clauses, upstream) = match type_ctor { 543 let where_clauses = type_ctor
547 TypeCtor::Bool 544 .as_generic_def()
548 | TypeCtor::Char 545 .map(|generic_def| {
549 | TypeCtor::Int(_)
550 | TypeCtor::Float(_)
551 | TypeCtor::Never
552 | TypeCtor::Str => (0, vec![], true),
553 TypeCtor::Slice | TypeCtor::Array | TypeCtor::RawPtr(_) | TypeCtor::Ref(_) => {
554 (1, vec![], true)
555 }
556 TypeCtor::FnPtr { num_args } => (num_args as usize + 1, vec![], true),
557 TypeCtor::Tuple { cardinality } => (cardinality as usize, vec![], true),
558 TypeCtor::FnDef(callable) => {
559 tested_by!(trait_resolution_on_fn_type);
560 let upstream = match callable {
561 CallableDef::Function(f) => f.module(db).krate(db),
562 CallableDef::Struct(s) => s.module(db).krate(db),
563 CallableDef::EnumVariant(v) => v.parent_enum(db).module(db).krate(db),
564 } != Some(krate);
565 let generic_def: GenericDef = callable.into();
566 let generic_params = generic_def.generic_params(db); 546 let generic_params = generic_def.generic_params(db);
567 let bound_vars = Substs::bound_vars(&generic_params); 547 let bound_vars = Substs::bound_vars(&generic_params);
568 let where_clauses = convert_where_clauses(db, generic_def, &bound_vars); 548 convert_where_clauses(db, generic_def, &bound_vars)
569 (generic_params.count_params_including_parent(), where_clauses, upstream) 549 })
570 } 550 .unwrap_or_else(Vec::new);
571 TypeCtor::Adt(adt) => {
572 let generic_params = adt.generic_params(db);
573 let bound_vars = Substs::bound_vars(&generic_params);
574 let where_clauses = convert_where_clauses(db, adt.into(), &bound_vars);
575 (
576 generic_params.count_params_including_parent(),
577 where_clauses,
578 adt.krate(db) != Some(krate),
579 )
580 }
581 TypeCtor::AssociatedType(type_alias) => {
582 let generic_params = type_alias.generic_params(db);
583 let bound_vars = Substs::bound_vars(&generic_params);
584 let where_clauses = convert_where_clauses(db, type_alias.into(), &bound_vars);
585 (
586 generic_params.count_params_including_parent(),
587 where_clauses,
588 type_alias.krate(db) != Some(krate),
589 )
590 }
591 TypeCtor::Closure { def, .. } => {
592 let upstream = def.krate(db) != Some(krate);
593 (1, vec![], upstream)
594 }
595 };
596 let flags = chalk_rust_ir::StructFlags { 551 let flags = chalk_rust_ir::StructFlags {
597 upstream, 552 upstream,
598 // FIXME set fundamental flag correctly 553 // FIXME set fundamental flag correctly
@@ -729,17 +684,20 @@ fn closure_fn_trait_impl_datum(
729 684
730 let arg_ty = Ty::apply( 685 let arg_ty = Ty::apply(
731 TypeCtor::Tuple { cardinality: num_args }, 686 TypeCtor::Tuple { cardinality: num_args },
732 (0..num_args).map(|i| Ty::Bound(i.into())).collect::<Vec<_>>().into(), 687 Substs::builder(num_args as usize).fill_with_bound_vars(0).build(),
733 ); 688 );
734 let output_ty = Ty::Bound(num_args.into()); 689 let output_ty = Ty::Bound(num_args.into());
735 let sig_ty = Ty::apply( 690 let sig_ty = Ty::apply(
736 TypeCtor::FnPtr { num_args }, 691 TypeCtor::FnPtr { num_args },
737 (0..num_args + 1).map(|i| Ty::Bound(i.into())).collect::<Vec<_>>().into(), 692 Substs::builder(num_args as usize + 1).fill_with_bound_vars(0).build(),
738 ); 693 );
739 694
740 let self_ty = Ty::apply_one(TypeCtor::Closure { def: data.def, expr: data.expr }, sig_ty); 695 let self_ty = Ty::apply_one(TypeCtor::Closure { def: data.def, expr: data.expr }, sig_ty);
741 696
742 let trait_ref = TraitRef { trait_, substs: vec![self_ty, arg_ty].into() }; 697 let trait_ref = TraitRef {
698 trait_,
699 substs: Substs::build_for_def(db, trait_).push(self_ty).push(arg_ty).build(),
700 };
743 701
744 let output_ty_id = fn_once_trait.associated_type_by_name(db, &crate::name::OUTPUT_TYPE)?; 702 let output_ty_id = fn_once_trait.associated_type_by_name(db, &crate::name::OUTPUT_TYPE)?;
745 703
diff --git a/crates/ra_ide_api/src/line_index.rs b/crates/ra_ide_api/src/line_index.rs
index 71de8a928..5fedad696 100644
--- a/crates/ra_ide_api/src/line_index.rs
+++ b/crates/ra_ide_api/src/line_index.rs
@@ -278,5 +278,4 @@ const C: char = \"メ メ\";
278 278
279 assert_eq!(col_index.utf16_to_utf8_col(2, 15), TextUnit::from_usize(15)); 279 assert_eq!(col_index.utf16_to_utf8_col(2, 15), TextUnit::from_usize(15));
280 } 280 }
281
282} 281}
diff --git a/crates/ra_ide_api/src/runnables.rs b/crates/ra_ide_api/src/runnables.rs
index 095ca56c4..8cf58fe79 100644
--- a/crates/ra_ide_api/src/runnables.rs
+++ b/crates/ra_ide_api/src/runnables.rs
@@ -229,5 +229,4 @@ mod tests {
229 let runnables = analysis.runnables(pos.file_id).unwrap(); 229 let runnables = analysis.runnables(pos.file_id).unwrap();
230 assert!(runnables.is_empty()) 230 assert!(runnables.is_empty())
231 } 231 }
232
233} 232}
diff --git a/crates/ra_lsp_server/src/markdown.rs b/crates/ra_lsp_server/src/markdown.rs
index c1eb0236a..3659edf8e 100644
--- a/crates/ra_lsp_server/src/markdown.rs
+++ b/crates/ra_lsp_server/src/markdown.rs
@@ -70,5 +70,4 @@ let a = 1;
70 "```rust\nfn main(){}\n```\nSome comment.\n```rust\nlet a = 1;\n```" 70 "```rust\nfn main(){}\n```\nSome comment.\n```rust\nlet a = 1;\n```"
71 ); 71 );
72 } 72 }
73
74} 73}
diff --git a/crates/ra_parser/src/grammar.rs b/crates/ra_parser/src/grammar.rs
index e2355aff9..6e9e212b7 100644
--- a/crates/ra_parser/src/grammar.rs
+++ b/crates/ra_parser/src/grammar.rs
@@ -135,7 +135,6 @@ pub(crate) mod fragments {
135 135
136 m.complete(p, MACRO_STMTS); 136 m.complete(p, MACRO_STMTS);
137 } 137 }
138
139} 138}
140 139
141pub(crate) fn reparser( 140pub(crate) fn reparser(
diff --git a/crates/ra_syntax/Cargo.toml b/crates/ra_syntax/Cargo.toml
index 724c38e17..9bc85404a 100644
--- a/crates/ra_syntax/Cargo.toml
+++ b/crates/ra_syntax/Cargo.toml
@@ -12,6 +12,8 @@ itertools = "0.8.0"
12rowan = "0.6.1" 12rowan = "0.6.1"
13rustc_lexer = "0.1.0" 13rustc_lexer = "0.1.0"
14rustc-hash = "1.0.1" 14rustc-hash = "1.0.1"
15arrayvec = "0.4.10"
16once_cell = "1.2.0"
15 17
16# ideally, `serde` should be enabled by `ra_lsp_server`, but we enable it here 18# ideally, `serde` should be enabled by `ra_lsp_server`, but we enable it here
17# to reduce number of compilations 19# to reduce number of compilations
diff --git a/crates/ra_syntax/src/ast.rs b/crates/ra_syntax/src/ast.rs
index f464d6534..fdffd8cb1 100644
--- a/crates/ra_syntax/src/ast.rs
+++ b/crates/ra_syntax/src/ast.rs
@@ -5,6 +5,7 @@ mod traits;
5mod tokens; 5mod tokens;
6mod extensions; 6mod extensions;
7mod expr_extensions; 7mod expr_extensions;
8mod edit;
8pub mod make; 9pub mod make;
9 10
10use std::marker::PhantomData; 11use std::marker::PhantomData;
diff --git a/crates/ra_syntax/src/ast/edit.rs b/crates/ra_syntax/src/ast/edit.rs
new file mode 100644
index 000000000..c65899812
--- /dev/null
+++ b/crates/ra_syntax/src/ast/edit.rs
@@ -0,0 +1,52 @@
1//! This module contains functions for editing syntax trees. As the trees are
2//! immutable, all function here return a fresh copy of the tree, instead of
3//! doing an in-place modification.
4
5use arrayvec::ArrayVec;
6use std::ops::RangeInclusive;
7
8use crate::{
9 algo,
10 ast::{self, make, AstNode},
11 InsertPosition, SyntaxElement,
12};
13
14impl ast::FnDef {
15 #[must_use]
16 pub fn with_body(&self, body: ast::Block) -> ast::FnDef {
17 let mut to_insert: ArrayVec<[SyntaxElement; 2]> = ArrayVec::new();
18 let old_body_or_semi: SyntaxElement = if let Some(old_body) = self.body() {
19 old_body.syntax().clone().into()
20 } else if let Some(semi) = self.semicolon_token() {
21 to_insert.push(make::tokens::single_space().into());
22 semi.into()
23 } else {
24 to_insert.push(make::tokens::single_space().into());
25 to_insert.push(body.syntax().clone().into());
26 return insert_children(self, InsertPosition::Last, to_insert.into_iter());
27 };
28 to_insert.push(body.syntax().clone().into());
29 let replace_range = RangeInclusive::new(old_body_or_semi.clone(), old_body_or_semi);
30 replace_children(self, replace_range, to_insert.into_iter())
31 }
32}
33
34#[must_use]
35fn insert_children<N: AstNode>(
36 parent: &N,
37 position: InsertPosition<SyntaxElement>,
38 mut to_insert: impl Iterator<Item = SyntaxElement>,
39) -> N {
40 let new_syntax = algo::insert_children(parent.syntax(), position, &mut to_insert);
41 N::cast(new_syntax).unwrap()
42}
43
44#[must_use]
45fn replace_children<N: AstNode>(
46 parent: &N,
47 to_replace: RangeInclusive<SyntaxElement>,
48 mut to_insert: impl Iterator<Item = SyntaxElement>,
49) -> N {
50 let new_syntax = algo::replace_children(parent.syntax(), to_replace, &mut to_insert);
51 N::cast(new_syntax).unwrap()
52}
diff --git a/crates/ra_syntax/src/ast/make.rs b/crates/ra_syntax/src/ast/make.rs
index c06c62b3b..287a40bee 100644
--- a/crates/ra_syntax/src/ast/make.rs
+++ b/crates/ra_syntax/src/ast/make.rs
@@ -133,3 +133,51 @@ fn ast_from_text<N: AstNode>(text: &str) -> N {
133 let res = parse.tree().syntax().descendants().find_map(N::cast).unwrap(); 133 let res = parse.tree().syntax().descendants().find_map(N::cast).unwrap();
134 res 134 res
135} 135}
136
137pub mod tokens {
138 use crate::{AstNode, Parse, SourceFile, SyntaxKind::*, SyntaxToken, T};
139 use once_cell::sync::Lazy;
140
141 static SOURCE_FILE: Lazy<Parse<SourceFile>> = Lazy::new(|| SourceFile::parse(",\n; ;"));
142
143 pub fn comma() -> SyntaxToken {
144 SOURCE_FILE
145 .tree()
146 .syntax()
147 .descendants_with_tokens()
148 .filter_map(|it| it.into_token())
149 .find(|it| it.kind() == T![,])
150 .unwrap()
151 }
152
153 pub fn single_space() -> SyntaxToken {
154 SOURCE_FILE
155 .tree()
156 .syntax()
157 .descendants_with_tokens()
158 .filter_map(|it| it.into_token())
159 .find(|it| it.kind() == WHITESPACE && it.text().as_str() == " ")
160 .unwrap()
161 }
162
163 pub fn single_newline() -> SyntaxToken {
164 SOURCE_FILE
165 .tree()
166 .syntax()
167 .descendants_with_tokens()
168 .filter_map(|it| it.into_token())
169 .find(|it| it.kind() == WHITESPACE && it.text().as_str() == "\n")
170 .unwrap()
171 }
172
173 pub struct WsBuilder(SourceFile);
174
175 impl WsBuilder {
176 pub fn new(text: &str) -> WsBuilder {
177 WsBuilder(SourceFile::parse(text).ok().unwrap())
178 }
179 pub fn ws(&self) -> SyntaxToken {
180 self.0.syntax().first_child_or_token().unwrap().into_token().unwrap()
181 }
182 }
183}