diff options
Diffstat (limited to 'crates')
-rw-r--r-- | crates/assists/src/utils.rs | 110 | ||||
-rw-r--r-- | crates/hir/src/code_model.rs | 37 | ||||
-rw-r--r-- | crates/hir/src/lib.rs | 2 | ||||
-rw-r--r-- | crates/hir_expand/src/name.rs | 1 | ||||
-rw-r--r-- | crates/ide/src/inlay_hints.rs | 201 | ||||
-rw-r--r-- | crates/mbe/src/subtree_source.rs | 30 | ||||
-rw-r--r-- | crates/rust-analyzer/src/lsp_utils.rs | 11 | ||||
-rw-r--r-- | crates/rust-analyzer/src/main_loop.rs | 2 | ||||
-rw-r--r-- | crates/syntax/src/parsing/lexer.rs | 23 | ||||
-rw-r--r-- | crates/syntax/src/validation.rs | 45 | ||||
-rw-r--r-- | crates/syntax/test_data/parser/err/0046_ambiguous_trait_object.rast | 192 | ||||
-rw-r--r-- | crates/syntax/test_data/parser/err/0046_ambiguous_trait_object.rs | 6 | ||||
-rw-r--r-- | crates/syntax/test_data/parser/ok/0069_multi_trait_object.rast | 200 | ||||
-rw-r--r-- | crates/syntax/test_data/parser/ok/0069_multi_trait_object.rs | 6 |
14 files changed, 793 insertions, 73 deletions
diff --git a/crates/assists/src/utils.rs b/crates/assists/src/utils.rs index eb69c49a4..c1847f601 100644 --- a/crates/assists/src/utils.rs +++ b/crates/assists/src/utils.rs | |||
@@ -3,7 +3,7 @@ pub(crate) mod insert_use; | |||
3 | 3 | ||
4 | use std::{iter, ops}; | 4 | use std::{iter, ops}; |
5 | 5 | ||
6 | use hir::{Adt, Crate, Enum, ScopeDef, Semantics, Trait, Type}; | 6 | use hir::{Adt, Crate, Enum, Module, ScopeDef, Semantics, Trait, Type}; |
7 | use ide_db::RootDatabase; | 7 | use ide_db::RootDatabase; |
8 | use itertools::Itertools; | 8 | use itertools::Itertools; |
9 | use rustc_hash::FxHashSet; | 9 | use rustc_hash::FxHashSet; |
@@ -274,15 +274,79 @@ impl TryEnum { | |||
274 | /// somewhat similar to the known paths infra inside hir, but it different; We | 274 | /// somewhat similar to the known paths infra inside hir, but it different; We |
275 | /// want to make sure that IDE specific paths don't become interesting inside | 275 | /// want to make sure that IDE specific paths don't become interesting inside |
276 | /// the compiler itself as well. | 276 | /// the compiler itself as well. |
277 | pub(crate) struct FamousDefs<'a, 'b>(pub(crate) &'a Semantics<'b, RootDatabase>, pub(crate) Crate); | 277 | pub struct FamousDefs<'a, 'b>(pub &'a Semantics<'b, RootDatabase>, pub Crate); |
278 | 278 | ||
279 | #[allow(non_snake_case)] | 279 | #[allow(non_snake_case)] |
280 | impl FamousDefs<'_, '_> { | 280 | impl FamousDefs<'_, '_> { |
281 | #[cfg(test)] | 281 | pub const FIXTURE: &'static str = r#"//- /libcore.rs crate:core |
282 | pub(crate) const FIXTURE: &'static str = r#"//- /libcore.rs crate:core | ||
283 | pub mod convert { | 282 | pub mod convert { |
284 | pub trait From<T> { | 283 | pub trait From<T> { |
285 | fn from(T) -> Self; | 284 | fn from(t: T) -> Self; |
285 | } | ||
286 | } | ||
287 | |||
288 | pub mod iter { | ||
289 | pub use self::traits::{collect::IntoIterator, iterator::Iterator}; | ||
290 | mod traits { | ||
291 | pub(crate) mod iterator { | ||
292 | use crate::option::Option; | ||
293 | pub trait Iterator { | ||
294 | type Item; | ||
295 | fn next(&mut self) -> Option<Self::Item>; | ||
296 | fn by_ref(&mut self) -> &mut Self { | ||
297 | self | ||
298 | } | ||
299 | fn take(self, n: usize) -> crate::iter::Take<Self> { | ||
300 | crate::iter::Take { inner: self } | ||
301 | } | ||
302 | } | ||
303 | |||
304 | impl<I: Iterator> Iterator for &mut I { | ||
305 | type Item = I::Item; | ||
306 | fn next(&mut self) -> Option<I::Item> { | ||
307 | (**self).next() | ||
308 | } | ||
309 | } | ||
310 | } | ||
311 | pub(crate) mod collect { | ||
312 | pub trait IntoIterator { | ||
313 | type Item; | ||
314 | } | ||
315 | } | ||
316 | } | ||
317 | |||
318 | pub use self::sources::*; | ||
319 | pub(crate) mod sources { | ||
320 | use super::Iterator; | ||
321 | use crate::option::Option::{self, *}; | ||
322 | pub struct Repeat<A> { | ||
323 | element: A, | ||
324 | } | ||
325 | |||
326 | pub fn repeat<T>(elt: T) -> Repeat<T> { | ||
327 | Repeat { element: elt } | ||
328 | } | ||
329 | |||
330 | impl<A> Iterator for Repeat<A> { | ||
331 | type Item = A; | ||
332 | |||
333 | fn next(&mut self) -> Option<A> { | ||
334 | None | ||
335 | } | ||
336 | } | ||
337 | } | ||
338 | |||
339 | pub use self::adapters::*; | ||
340 | pub(crate) mod adapters { | ||
341 | use super::Iterator; | ||
342 | use crate::option::Option::{self, *}; | ||
343 | pub struct Take<I> { pub(crate) inner: I } | ||
344 | impl<I> Iterator for Take<I> where I: Iterator { | ||
345 | type Item = <I as Iterator>::Item; | ||
346 | fn next(&mut self) -> Option<<I as Iterator>::Item> { | ||
347 | None | ||
348 | } | ||
349 | } | ||
286 | } | 350 | } |
287 | } | 351 | } |
288 | 352 | ||
@@ -291,7 +355,7 @@ pub mod option { | |||
291 | } | 355 | } |
292 | 356 | ||
293 | pub mod prelude { | 357 | pub mod prelude { |
294 | pub use crate::{convert::From, option::Option::{self, *}}; | 358 | pub use crate::{convert::From, iter::{IntoIterator, Iterator}, option::Option::{self, *}}; |
295 | } | 359 | } |
296 | #[prelude_import] | 360 | #[prelude_import] |
297 | pub use prelude::*; | 361 | pub use prelude::*; |
@@ -305,6 +369,14 @@ pub use prelude::*; | |||
305 | self.find_enum("core:option:Option") | 369 | self.find_enum("core:option:Option") |
306 | } | 370 | } |
307 | 371 | ||
372 | pub fn core_iter_Iterator(&self) -> Option<Trait> { | ||
373 | self.find_trait("core:iter:traits:iterator:Iterator") | ||
374 | } | ||
375 | |||
376 | pub fn core_iter(&self) -> Option<Module> { | ||
377 | self.find_module("core:iter") | ||
378 | } | ||
379 | |||
308 | fn find_trait(&self, path: &str) -> Option<Trait> { | 380 | fn find_trait(&self, path: &str) -> Option<Trait> { |
309 | match self.find_def(path)? { | 381 | match self.find_def(path)? { |
310 | hir::ScopeDef::ModuleDef(hir::ModuleDef::Trait(it)) => Some(it), | 382 | hir::ScopeDef::ModuleDef(hir::ModuleDef::Trait(it)) => Some(it), |
@@ -319,23 +391,33 @@ pub use prelude::*; | |||
319 | } | 391 | } |
320 | } | 392 | } |
321 | 393 | ||
394 | fn find_module(&self, path: &str) -> Option<Module> { | ||
395 | match self.find_def(path)? { | ||
396 | hir::ScopeDef::ModuleDef(hir::ModuleDef::Module(it)) => Some(it), | ||
397 | _ => None, | ||
398 | } | ||
399 | } | ||
400 | |||
322 | fn find_def(&self, path: &str) -> Option<ScopeDef> { | 401 | fn find_def(&self, path: &str) -> Option<ScopeDef> { |
323 | let db = self.0.db; | 402 | let db = self.0.db; |
324 | let mut path = path.split(':'); | 403 | let mut path = path.split(':'); |
325 | let trait_ = path.next_back()?; | 404 | let trait_ = path.next_back()?; |
326 | let std_crate = path.next()?; | 405 | let std_crate = path.next()?; |
327 | let std_crate = self | 406 | let std_crate = if self |
328 | .1 | 407 | .1 |
329 | .dependencies(db) | 408 | .declaration_name(db) |
330 | .into_iter() | 409 | .map(|name| name.to_string() == std_crate) |
331 | .find(|dep| &dep.name.to_string() == std_crate)? | 410 | .unwrap_or(false) |
332 | .krate; | 411 | { |
333 | 412 | self.1 | |
413 | } else { | ||
414 | self.1.dependencies(db).into_iter().find(|dep| dep.name.to_string() == std_crate)?.krate | ||
415 | }; | ||
334 | let mut module = std_crate.root_module(db); | 416 | let mut module = std_crate.root_module(db); |
335 | for segment in path { | 417 | for segment in path { |
336 | module = module.children(db).find_map(|child| { | 418 | module = module.children(db).find_map(|child| { |
337 | let name = child.name(db)?; | 419 | let name = child.name(db)?; |
338 | if &name.to_string() == segment { | 420 | if name.to_string() == segment { |
339 | Some(child) | 421 | Some(child) |
340 | } else { | 422 | } else { |
341 | None | 423 | None |
@@ -343,7 +425,7 @@ pub use prelude::*; | |||
343 | })?; | 425 | })?; |
344 | } | 426 | } |
345 | let def = | 427 | let def = |
346 | module.scope(db, None).into_iter().find(|(name, _def)| &name.to_string() == trait_)?.1; | 428 | module.scope(db, None).into_iter().find(|(name, _def)| name.to_string() == trait_)?.1; |
347 | Some(def) | 429 | Some(def) |
348 | } | 430 | } |
349 | } | 431 | } |
diff --git a/crates/hir/src/code_model.rs b/crates/hir/src/code_model.rs index c75d46bff..031c91ccf 100644 --- a/crates/hir/src/code_model.rs +++ b/crates/hir/src/code_model.rs | |||
@@ -30,8 +30,12 @@ use hir_expand::{ | |||
30 | use hir_ty::{ | 30 | use hir_ty::{ |
31 | autoderef, | 31 | autoderef, |
32 | display::{HirDisplayError, HirFormatter}, | 32 | display::{HirDisplayError, HirFormatter}, |
33 | method_resolution, ApplicationTy, CallableDefId, Canonical, FnSig, GenericPredicate, | 33 | method_resolution, |
34 | InEnvironment, Substs, TraitEnvironment, Ty, TyDefId, TypeCtor, | 34 | traits::Solution, |
35 | traits::SolutionVariables, | ||
36 | ApplicationTy, BoundVar, CallableDefId, Canonical, DebruijnIndex, FnSig, GenericPredicate, | ||
37 | InEnvironment, Obligation, ProjectionPredicate, ProjectionTy, Substs, TraitEnvironment, Ty, | ||
38 | TyDefId, TyKind, TypeCtor, | ||
35 | }; | 39 | }; |
36 | use rustc_hash::FxHashSet; | 40 | use rustc_hash::FxHashSet; |
37 | use stdx::impl_from; | 41 | use stdx::impl_from; |
@@ -1362,6 +1366,35 @@ impl Type { | |||
1362 | db.trait_solve(self.krate, goal).is_some() | 1366 | db.trait_solve(self.krate, goal).is_some() |
1363 | } | 1367 | } |
1364 | 1368 | ||
1369 | pub fn normalize_trait_assoc_type( | ||
1370 | &self, | ||
1371 | db: &dyn HirDatabase, | ||
1372 | r#trait: Trait, | ||
1373 | args: &[Type], | ||
1374 | alias: TypeAlias, | ||
1375 | ) -> Option<Ty> { | ||
1376 | let subst = Substs::build_for_def(db, r#trait.id) | ||
1377 | .push(self.ty.value.clone()) | ||
1378 | .fill(args.iter().map(|t| t.ty.value.clone())) | ||
1379 | .build(); | ||
1380 | let predicate = ProjectionPredicate { | ||
1381 | projection_ty: ProjectionTy { associated_ty: alias.id, parameters: subst }, | ||
1382 | ty: Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, 0)), | ||
1383 | }; | ||
1384 | let goal = Canonical { | ||
1385 | value: InEnvironment::new( | ||
1386 | self.ty.environment.clone(), | ||
1387 | Obligation::Projection(predicate), | ||
1388 | ), | ||
1389 | kinds: Arc::new([TyKind::General]), | ||
1390 | }; | ||
1391 | |||
1392 | match db.trait_solve(self.krate, goal)? { | ||
1393 | Solution::Unique(SolutionVariables(subst)) => subst.value.first().cloned(), | ||
1394 | Solution::Ambig(_) => None, | ||
1395 | } | ||
1396 | } | ||
1397 | |||
1365 | pub fn is_copy(&self, db: &dyn HirDatabase) -> bool { | 1398 | pub fn is_copy(&self, db: &dyn HirDatabase) -> bool { |
1366 | let lang_item = db.lang_item(self.krate, SmolStr::new("copy")); | 1399 | let lang_item = db.lang_item(self.krate, SmolStr::new("copy")); |
1367 | let copy_trait = match lang_item { | 1400 | let copy_trait = match lang_item { |
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 171118d98..4094a76cb 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs | |||
@@ -55,7 +55,7 @@ pub use hir_def::{ | |||
55 | type_ref::{Mutability, TypeRef}, | 55 | type_ref::{Mutability, TypeRef}, |
56 | }; | 56 | }; |
57 | pub use hir_expand::{ | 57 | pub use hir_expand::{ |
58 | name::AsName, name::Name, HirFileId, InFile, MacroCallId, MacroCallLoc, | 58 | name::known, name::AsName, name::Name, HirFileId, InFile, MacroCallId, MacroCallLoc, |
59 | /* FIXME */ MacroDefId, MacroFile, Origin, | 59 | /* FIXME */ MacroDefId, MacroFile, Origin, |
60 | }; | 60 | }; |
61 | pub use hir_ty::display::HirDisplay; | 61 | pub use hir_ty::display::HirDisplay; |
diff --git a/crates/hir_expand/src/name.rs b/crates/hir_expand/src/name.rs index a5750d829..63f828707 100644 --- a/crates/hir_expand/src/name.rs +++ b/crates/hir_expand/src/name.rs | |||
@@ -164,6 +164,7 @@ pub mod known { | |||
164 | result, | 164 | result, |
165 | boxed, | 165 | boxed, |
166 | // Components of known path (type name) | 166 | // Components of known path (type name) |
167 | Iterator, | ||
167 | IntoIterator, | 168 | IntoIterator, |
168 | Item, | 169 | Item, |
169 | Try, | 170 | Try, |
diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs index 3a4dc6a84..7d716577e 100644 --- a/crates/ide/src/inlay_hints.rs +++ b/crates/ide/src/inlay_hints.rs | |||
@@ -1,4 +1,5 @@ | |||
1 | use hir::{Adt, Callable, HirDisplay, Semantics, Type}; | 1 | use assists::utils::FamousDefs; |
2 | use hir::{known, HirDisplay, Semantics}; | ||
2 | use ide_db::RootDatabase; | 3 | use ide_db::RootDatabase; |
3 | use stdx::to_lower_snake_case; | 4 | use stdx::to_lower_snake_case; |
4 | use syntax::{ | 5 | use syntax::{ |
@@ -119,17 +120,18 @@ fn get_chaining_hints( | |||
119 | return None; | 120 | return None; |
120 | } | 121 | } |
121 | if matches!(expr, ast::Expr::PathExpr(_)) { | 122 | if matches!(expr, ast::Expr::PathExpr(_)) { |
122 | if let Some(Adt::Struct(st)) = ty.as_adt() { | 123 | if let Some(hir::Adt::Struct(st)) = ty.as_adt() { |
123 | if st.fields(sema.db).is_empty() { | 124 | if st.fields(sema.db).is_empty() { |
124 | return None; | 125 | return None; |
125 | } | 126 | } |
126 | } | 127 | } |
127 | } | 128 | } |
128 | let label = ty.display_truncated(sema.db, config.max_length).to_string(); | ||
129 | acc.push(InlayHint { | 129 | acc.push(InlayHint { |
130 | range: expr.syntax().text_range(), | 130 | range: expr.syntax().text_range(), |
131 | kind: InlayKind::ChainingHint, | 131 | kind: InlayKind::ChainingHint, |
132 | label: label.into(), | 132 | label: hint_iterator(sema, config, &ty).unwrap_or_else(|| { |
133 | ty.display_truncated(sema.db, config.max_length).to_string().into() | ||
134 | }), | ||
133 | }); | 135 | }); |
134 | } | 136 | } |
135 | Some(()) | 137 | Some(()) |
@@ -192,17 +194,58 @@ fn get_bind_pat_hints( | |||
192 | if should_not_display_type_hint(sema, &pat, &ty) { | 194 | if should_not_display_type_hint(sema, &pat, &ty) { |
193 | return None; | 195 | return None; |
194 | } | 196 | } |
195 | |||
196 | acc.push(InlayHint { | 197 | acc.push(InlayHint { |
197 | range: pat.syntax().text_range(), | 198 | range: pat.syntax().text_range(), |
198 | kind: InlayKind::TypeHint, | 199 | kind: InlayKind::TypeHint, |
199 | label: ty.display_truncated(sema.db, config.max_length).to_string().into(), | 200 | label: hint_iterator(sema, config, &ty) |
201 | .unwrap_or_else(|| ty.display_truncated(sema.db, config.max_length).to_string().into()), | ||
200 | }); | 202 | }); |
203 | |||
201 | Some(()) | 204 | Some(()) |
202 | } | 205 | } |
203 | 206 | ||
204 | fn pat_is_enum_variant(db: &RootDatabase, bind_pat: &ast::IdentPat, pat_ty: &Type) -> bool { | 207 | /// Checks if the type is an Iterator from std::iter and replaces its hint with an `impl Iterator<Item = Ty>`. |
205 | if let Some(Adt::Enum(enum_data)) = pat_ty.as_adt() { | 208 | fn hint_iterator( |
209 | sema: &Semantics<RootDatabase>, | ||
210 | config: &InlayHintsConfig, | ||
211 | ty: &hir::Type, | ||
212 | ) -> Option<SmolStr> { | ||
213 | let db = sema.db; | ||
214 | let strukt = std::iter::successors(Some(ty.clone()), |ty| ty.remove_ref()) | ||
215 | .last() | ||
216 | .and_then(|strukt| strukt.as_adt())?; | ||
217 | let krate = strukt.krate(db)?; | ||
218 | if krate.declaration_name(db).as_deref() != Some("core") { | ||
219 | return None; | ||
220 | } | ||
221 | let iter_trait = FamousDefs(sema, krate).core_iter_Iterator()?; | ||
222 | let iter_mod = FamousDefs(sema, krate).core_iter()?; | ||
223 | // assert this type comes from `core::iter` | ||
224 | iter_mod.visibility_of(db, &iter_trait.into()).filter(|&vis| vis == hir::Visibility::Public)?; | ||
225 | if ty.impls_trait(db, iter_trait, &[]) { | ||
226 | let assoc_type_item = iter_trait.items(db).into_iter().find_map(|item| match item { | ||
227 | hir::AssocItem::TypeAlias(alias) if alias.name(db) == known::Item => Some(alias), | ||
228 | _ => None, | ||
229 | })?; | ||
230 | if let Some(ty) = ty.normalize_trait_assoc_type(db, iter_trait, &[], assoc_type_item) { | ||
231 | const LABEL_START: &str = "impl Iterator<Item = "; | ||
232 | const LABEL_END: &str = ">"; | ||
233 | |||
234 | let ty_display = ty.display_truncated( | ||
235 | db, | ||
236 | config | ||
237 | .max_length | ||
238 | .map(|len| len.saturating_sub(LABEL_START.len() + LABEL_END.len())), | ||
239 | ); | ||
240 | return Some(format!("{}{}{}", LABEL_START, ty_display, LABEL_END).into()); | ||
241 | } | ||
242 | } | ||
243 | |||
244 | None | ||
245 | } | ||
246 | |||
247 | fn pat_is_enum_variant(db: &RootDatabase, bind_pat: &ast::IdentPat, pat_ty: &hir::Type) -> bool { | ||
248 | if let Some(hir::Adt::Enum(enum_data)) = pat_ty.as_adt() { | ||
206 | let pat_text = bind_pat.to_string(); | 249 | let pat_text = bind_pat.to_string(); |
207 | enum_data | 250 | enum_data |
208 | .variants(db) | 251 | .variants(db) |
@@ -217,7 +260,7 @@ fn pat_is_enum_variant(db: &RootDatabase, bind_pat: &ast::IdentPat, pat_ty: &Typ | |||
217 | fn should_not_display_type_hint( | 260 | fn should_not_display_type_hint( |
218 | sema: &Semantics<RootDatabase>, | 261 | sema: &Semantics<RootDatabase>, |
219 | bind_pat: &ast::IdentPat, | 262 | bind_pat: &ast::IdentPat, |
220 | pat_ty: &Type, | 263 | pat_ty: &hir::Type, |
221 | ) -> bool { | 264 | ) -> bool { |
222 | let db = sema.db; | 265 | let db = sema.db; |
223 | 266 | ||
@@ -225,7 +268,7 @@ fn should_not_display_type_hint( | |||
225 | return true; | 268 | return true; |
226 | } | 269 | } |
227 | 270 | ||
228 | if let Some(Adt::Struct(s)) = pat_ty.as_adt() { | 271 | if let Some(hir::Adt::Struct(s)) = pat_ty.as_adt() { |
229 | if s.fields(db).is_empty() && s.name(db).to_string() == bind_pat.to_string() { | 272 | if s.fields(db).is_empty() && s.name(db).to_string() == bind_pat.to_string() { |
230 | return true; | 273 | return true; |
231 | } | 274 | } |
@@ -269,7 +312,7 @@ fn should_not_display_type_hint( | |||
269 | 312 | ||
270 | fn should_show_param_name_hint( | 313 | fn should_show_param_name_hint( |
271 | sema: &Semantics<RootDatabase>, | 314 | sema: &Semantics<RootDatabase>, |
272 | callable: &Callable, | 315 | callable: &hir::Callable, |
273 | param_name: &str, | 316 | param_name: &str, |
274 | argument: &ast::Expr, | 317 | argument: &ast::Expr, |
275 | ) -> bool { | 318 | ) -> bool { |
@@ -316,7 +359,7 @@ fn is_enum_name_similar_to_param_name( | |||
316 | param_name: &str, | 359 | param_name: &str, |
317 | ) -> bool { | 360 | ) -> bool { |
318 | match sema.type_of_expr(argument).and_then(|t| t.as_adt()) { | 361 | match sema.type_of_expr(argument).and_then(|t| t.as_adt()) { |
319 | Some(Adt::Enum(e)) => to_lower_snake_case(&e.name(sema.db).to_string()) == param_name, | 362 | Some(hir::Adt::Enum(e)) => to_lower_snake_case(&e.name(sema.db).to_string()) == param_name, |
320 | _ => false, | 363 | _ => false, |
321 | } | 364 | } |
322 | } | 365 | } |
@@ -337,7 +380,7 @@ fn is_obvious_param(param_name: &str) -> bool { | |||
337 | param_name.len() == 1 || is_obvious_param_name | 380 | param_name.len() == 1 || is_obvious_param_name |
338 | } | 381 | } |
339 | 382 | ||
340 | fn get_callable(sema: &Semantics<RootDatabase>, expr: &ast::Expr) -> Option<Callable> { | 383 | fn get_callable(sema: &Semantics<RootDatabase>, expr: &ast::Expr) -> Option<hir::Callable> { |
341 | match expr { | 384 | match expr { |
342 | ast::Expr::CallExpr(expr) => sema.type_of_expr(&expr.expr()?)?.as_callable(sema.db), | 385 | ast::Expr::CallExpr(expr) => sema.type_of_expr(&expr.expr()?)?.as_callable(sema.db), |
343 | ast::Expr::MethodCallExpr(expr) => sema.resolve_method_call_as_callable(expr), | 386 | ast::Expr::MethodCallExpr(expr) => sema.resolve_method_call_as_callable(expr), |
@@ -347,6 +390,7 @@ fn get_callable(sema: &Semantics<RootDatabase>, expr: &ast::Expr) -> Option<Call | |||
347 | 390 | ||
348 | #[cfg(test)] | 391 | #[cfg(test)] |
349 | mod tests { | 392 | mod tests { |
393 | use assists::utils::FamousDefs; | ||
350 | use expect_test::{expect, Expect}; | 394 | use expect_test::{expect, Expect}; |
351 | use test_utils::extract_annotations; | 395 | use test_utils::extract_annotations; |
352 | 396 | ||
@@ -357,7 +401,9 @@ mod tests { | |||
357 | } | 401 | } |
358 | 402 | ||
359 | fn check_with_config(config: InlayHintsConfig, ra_fixture: &str) { | 403 | fn check_with_config(config: InlayHintsConfig, ra_fixture: &str) { |
360 | let (analysis, file_id) = fixture::file(ra_fixture); | 404 | let ra_fixture = |
405 | format!("//- /main.rs crate:main deps:core\n{}\n{}", ra_fixture, FamousDefs::FIXTURE); | ||
406 | let (analysis, file_id) = fixture::file(&ra_fixture); | ||
361 | let expected = extract_annotations(&*analysis.file_text(file_id).unwrap()); | 407 | let expected = extract_annotations(&*analysis.file_text(file_id).unwrap()); |
362 | let inlay_hints = analysis.inlay_hints(file_id, &config).unwrap(); | 408 | let inlay_hints = analysis.inlay_hints(file_id, &config).unwrap(); |
363 | let actual = | 409 | let actual = |
@@ -366,7 +412,9 @@ mod tests { | |||
366 | } | 412 | } |
367 | 413 | ||
368 | fn check_expect(config: InlayHintsConfig, ra_fixture: &str, expect: Expect) { | 414 | fn check_expect(config: InlayHintsConfig, ra_fixture: &str, expect: Expect) { |
369 | let (analysis, file_id) = fixture::file(ra_fixture); | 415 | let ra_fixture = |
416 | format!("//- /main.rs crate:main deps:core\n{}\n{}", ra_fixture, FamousDefs::FIXTURE); | ||
417 | let (analysis, file_id) = fixture::file(&ra_fixture); | ||
370 | let inlay_hints = analysis.inlay_hints(file_id, &config).unwrap(); | 418 | let inlay_hints = analysis.inlay_hints(file_id, &config).unwrap(); |
371 | expect.assert_debug_eq(&inlay_hints) | 419 | expect.assert_debug_eq(&inlay_hints) |
372 | } | 420 | } |
@@ -798,12 +846,12 @@ fn main() { | |||
798 | expect![[r#" | 846 | expect![[r#" |
799 | [ | 847 | [ |
800 | InlayHint { | 848 | InlayHint { |
801 | range: 147..172, | 849 | range: 148..173, |
802 | kind: ChainingHint, | 850 | kind: ChainingHint, |
803 | label: "B", | 851 | label: "B", |
804 | }, | 852 | }, |
805 | InlayHint { | 853 | InlayHint { |
806 | range: 147..154, | 854 | range: 148..155, |
807 | kind: ChainingHint, | 855 | kind: ChainingHint, |
808 | label: "A", | 856 | label: "A", |
809 | }, | 857 | }, |
@@ -864,12 +912,12 @@ fn main() { | |||
864 | expect![[r#" | 912 | expect![[r#" |
865 | [ | 913 | [ |
866 | InlayHint { | 914 | InlayHint { |
867 | range: 143..190, | 915 | range: 144..191, |
868 | kind: ChainingHint, | 916 | kind: ChainingHint, |
869 | label: "C", | 917 | label: "C", |
870 | }, | 918 | }, |
871 | InlayHint { | 919 | InlayHint { |
872 | range: 143..179, | 920 | range: 144..180, |
873 | kind: ChainingHint, | 921 | kind: ChainingHint, |
874 | label: "B", | 922 | label: "B", |
875 | }, | 923 | }, |
@@ -909,12 +957,12 @@ fn main() { | |||
909 | expect![[r#" | 957 | expect![[r#" |
910 | [ | 958 | [ |
911 | InlayHint { | 959 | InlayHint { |
912 | range: 246..283, | 960 | range: 247..284, |
913 | kind: ChainingHint, | 961 | kind: ChainingHint, |
914 | label: "B<X<i32, bool>>", | 962 | label: "B<X<i32, bool>>", |
915 | }, | 963 | }, |
916 | InlayHint { | 964 | InlayHint { |
917 | range: 246..265, | 965 | range: 247..266, |
918 | kind: ChainingHint, | 966 | kind: ChainingHint, |
919 | label: "A<X<i32, bool>>", | 967 | label: "A<X<i32, bool>>", |
920 | }, | 968 | }, |
@@ -935,7 +983,6 @@ fn main() { | |||
935 | ); | 983 | ); |
936 | check( | 984 | check( |
937 | r#" | 985 | r#" |
938 | //- /main.rs crate:main deps:core | ||
939 | pub struct Vec<T> {} | 986 | pub struct Vec<T> {} |
940 | 987 | ||
941 | impl<T> Vec<T> { | 988 | impl<T> Vec<T> { |
@@ -956,13 +1003,6 @@ fn main() { | |||
956 | println!("Unit expr"); | 1003 | println!("Unit expr"); |
957 | } | 1004 | } |
958 | 1005 | ||
959 | //- /core.rs crate:core | ||
960 | #[prelude_import] use iter::*; | ||
961 | mod iter { | ||
962 | trait IntoIterator { | ||
963 | type Item; | ||
964 | } | ||
965 | } | ||
966 | //- /alloc.rs crate:alloc deps:core | 1006 | //- /alloc.rs crate:alloc deps:core |
967 | mod collections { | 1007 | mod collections { |
968 | struct Vec<T> {} | 1008 | struct Vec<T> {} |
@@ -982,7 +1022,6 @@ mod collections { | |||
982 | fn complete_for_hint() { | 1022 | fn complete_for_hint() { |
983 | check( | 1023 | check( |
984 | r#" | 1024 | r#" |
985 | //- /main.rs crate:main deps:core | ||
986 | pub struct Vec<T> {} | 1025 | pub struct Vec<T> {} |
987 | 1026 | ||
988 | impl<T> Vec<T> { | 1027 | impl<T> Vec<T> { |
@@ -1004,14 +1043,6 @@ fn main() { | |||
1004 | //^ &str | 1043 | //^ &str |
1005 | } | 1044 | } |
1006 | } | 1045 | } |
1007 | |||
1008 | //- /core.rs crate:core | ||
1009 | #[prelude_import] use iter::*; | ||
1010 | mod iter { | ||
1011 | trait IntoIterator { | ||
1012 | type Item; | ||
1013 | } | ||
1014 | } | ||
1015 | //- /alloc.rs crate:alloc deps:core | 1046 | //- /alloc.rs crate:alloc deps:core |
1016 | mod collections { | 1047 | mod collections { |
1017 | struct Vec<T> {} | 1048 | struct Vec<T> {} |
@@ -1037,7 +1068,6 @@ mod collections { | |||
1037 | max_length: None, | 1068 | max_length: None, |
1038 | }, | 1069 | }, |
1039 | r#" | 1070 | r#" |
1040 | //- /main.rs crate:main | ||
1041 | pub struct Vec<T> {} | 1071 | pub struct Vec<T> {} |
1042 | 1072 | ||
1043 | impl<T> Vec<T> { | 1073 | impl<T> Vec<T> { |
@@ -1060,4 +1090,97 @@ fn main() { | |||
1060 | "#, | 1090 | "#, |
1061 | ); | 1091 | ); |
1062 | } | 1092 | } |
1093 | |||
1094 | #[test] | ||
1095 | fn shorten_iterator_hints() { | ||
1096 | check_with_config( | ||
1097 | InlayHintsConfig { | ||
1098 | parameter_hints: false, | ||
1099 | type_hints: true, | ||
1100 | chaining_hints: false, | ||
1101 | max_length: None, | ||
1102 | }, | ||
1103 | r#" | ||
1104 | use core::iter; | ||
1105 | |||
1106 | struct MyIter; | ||
1107 | |||
1108 | impl Iterator for MyIter { | ||
1109 | type Item = (); | ||
1110 | fn next(&mut self) -> Option<Self::Item> { | ||
1111 | None | ||
1112 | } | ||
1113 | } | ||
1114 | |||
1115 | fn main() { | ||
1116 | let _x = MyIter; | ||
1117 | //^^ MyIter | ||
1118 | let _x = iter::repeat(0); | ||
1119 | //^^ impl Iterator<Item = i32> | ||
1120 | fn generic<T: Clone>(t: T) { | ||
1121 | let _x = iter::repeat(t); | ||
1122 | //^^ impl Iterator<Item = T> | ||
1123 | let _chained = iter::repeat(t).take(10); | ||
1124 | //^^^^^^^^ impl Iterator<Item = T> | ||
1125 | } | ||
1126 | } | ||
1127 | "#, | ||
1128 | ); | ||
1129 | } | ||
1130 | |||
1131 | #[test] | ||
1132 | fn shorten_iterator_chaining_hints() { | ||
1133 | check_expect( | ||
1134 | InlayHintsConfig { | ||
1135 | parameter_hints: false, | ||
1136 | type_hints: false, | ||
1137 | chaining_hints: true, | ||
1138 | max_length: None, | ||
1139 | }, | ||
1140 | r#" | ||
1141 | use core::iter; | ||
1142 | |||
1143 | struct MyIter; | ||
1144 | |||
1145 | impl Iterator for MyIter { | ||
1146 | type Item = (); | ||
1147 | fn next(&mut self) -> Option<Self::Item> { | ||
1148 | None | ||
1149 | } | ||
1150 | } | ||
1151 | |||
1152 | fn main() { | ||
1153 | let _x = MyIter.by_ref() | ||
1154 | .take(5) | ||
1155 | .by_ref() | ||
1156 | .take(5) | ||
1157 | .by_ref(); | ||
1158 | } | ||
1159 | "#, | ||
1160 | expect![[r#" | ||
1161 | [ | ||
1162 | InlayHint { | ||
1163 | range: 175..242, | ||
1164 | kind: ChainingHint, | ||
1165 | label: "impl Iterator<Item = ()>", | ||
1166 | }, | ||
1167 | InlayHint { | ||
1168 | range: 175..225, | ||
1169 | kind: ChainingHint, | ||
1170 | label: "impl Iterator<Item = ()>", | ||
1171 | }, | ||
1172 | InlayHint { | ||
1173 | range: 175..207, | ||
1174 | kind: ChainingHint, | ||
1175 | label: "impl Iterator<Item = ()>", | ||
1176 | }, | ||
1177 | InlayHint { | ||
1178 | range: 175..190, | ||
1179 | kind: ChainingHint, | ||
1180 | label: "&mut MyIter", | ||
1181 | }, | ||
1182 | ] | ||
1183 | "#]], | ||
1184 | ); | ||
1185 | } | ||
1063 | } | 1186 | } |
diff --git a/crates/mbe/src/subtree_source.rs b/crates/mbe/src/subtree_source.rs index 41461b315..396ce8b16 100644 --- a/crates/mbe/src/subtree_source.rs +++ b/crates/mbe/src/subtree_source.rs | |||
@@ -155,9 +155,14 @@ fn convert_delim(d: Option<tt::DelimiterKind>, closing: bool) -> TtToken { | |||
155 | } | 155 | } |
156 | 156 | ||
157 | fn convert_literal(l: &tt::Literal) -> TtToken { | 157 | fn convert_literal(l: &tt::Literal) -> TtToken { |
158 | let kind = lex_single_syntax_kind(&l.text) | 158 | let is_negated = l.text.starts_with('-'); |
159 | let inner_text = &l.text[if is_negated { 1 } else { 0 }..]; | ||
160 | |||
161 | let kind = lex_single_syntax_kind(inner_text) | ||
159 | .map(|(kind, _error)| kind) | 162 | .map(|(kind, _error)| kind) |
160 | .filter(|kind| kind.is_literal()) | 163 | .filter(|kind| { |
164 | kind.is_literal() && (!is_negated || matches!(kind, FLOAT_NUMBER | INT_NUMBER)) | ||
165 | }) | ||
161 | .unwrap_or_else(|| panic!("Fail to convert given literal {:#?}", &l)); | 166 | .unwrap_or_else(|| panic!("Fail to convert given literal {:#?}", &l)); |
162 | 167 | ||
163 | TtToken { kind, is_joint_to_next: false, text: l.text.clone() } | 168 | TtToken { kind, is_joint_to_next: false, text: l.text.clone() } |
@@ -195,3 +200,24 @@ fn convert_leaf(leaf: &tt::Leaf) -> TtToken { | |||
195 | tt::Leaf::Punct(punct) => convert_punct(*punct), | 200 | tt::Leaf::Punct(punct) => convert_punct(*punct), |
196 | } | 201 | } |
197 | } | 202 | } |
203 | |||
204 | #[cfg(test)] | ||
205 | mod tests { | ||
206 | use super::{convert_literal, TtToken}; | ||
207 | use syntax::{SmolStr, SyntaxKind}; | ||
208 | |||
209 | #[test] | ||
210 | fn test_negative_literal() { | ||
211 | assert_eq!( | ||
212 | convert_literal(&tt::Literal { | ||
213 | id: tt::TokenId::unspecified(), | ||
214 | text: SmolStr::new("-42.0") | ||
215 | }), | ||
216 | TtToken { | ||
217 | kind: SyntaxKind::FLOAT_NUMBER, | ||
218 | is_joint_to_next: false, | ||
219 | text: SmolStr::new("-42.0") | ||
220 | } | ||
221 | ); | ||
222 | } | ||
223 | } | ||
diff --git a/crates/rust-analyzer/src/lsp_utils.rs b/crates/rust-analyzer/src/lsp_utils.rs index 85c661571..bd888f634 100644 --- a/crates/rust-analyzer/src/lsp_utils.rs +++ b/crates/rust-analyzer/src/lsp_utils.rs | |||
@@ -25,8 +25,9 @@ pub(crate) enum Progress { | |||
25 | } | 25 | } |
26 | 26 | ||
27 | impl Progress { | 27 | impl Progress { |
28 | pub(crate) fn percentage(done: usize, total: usize) -> f64 { | 28 | pub(crate) fn fraction(done: usize, total: usize) -> f64 { |
29 | (done as f64 / total.max(1) as f64) * 100.0 | 29 | assert!(done <= total); |
30 | done as f64 / total.max(1) as f64 | ||
30 | } | 31 | } |
31 | } | 32 | } |
32 | 33 | ||
@@ -43,11 +44,15 @@ impl GlobalState { | |||
43 | title: &str, | 44 | title: &str, |
44 | state: Progress, | 45 | state: Progress, |
45 | message: Option<String>, | 46 | message: Option<String>, |
46 | percentage: Option<f64>, | 47 | fraction: Option<f64>, |
47 | ) { | 48 | ) { |
48 | if !self.config.client_caps.work_done_progress { | 49 | if !self.config.client_caps.work_done_progress { |
49 | return; | 50 | return; |
50 | } | 51 | } |
52 | let percentage = fraction.map(|f| { | ||
53 | assert!(0.0 <= f && f <= 1.0); | ||
54 | f * 100.0 | ||
55 | }); | ||
51 | let token = lsp_types::ProgressToken::String(format!("rustAnalyzer/{}", title)); | 56 | let token = lsp_types::ProgressToken::String(format!("rustAnalyzer/{}", title)); |
52 | let work_done_progress = match state { | 57 | let work_done_progress = match state { |
53 | Progress::Begin => { | 58 | Progress::Begin => { |
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index c2d0ac791..4b7ac8224 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs | |||
@@ -230,7 +230,7 @@ impl GlobalState { | |||
230 | "roots scanned", | 230 | "roots scanned", |
231 | state, | 231 | state, |
232 | Some(format!("{}/{}", n_done, n_total)), | 232 | Some(format!("{}/{}", n_done, n_total)), |
233 | Some(Progress::percentage(n_done, n_total)), | 233 | Some(Progress::fraction(n_done, n_total)), |
234 | ) | 234 | ) |
235 | } | 235 | } |
236 | } | 236 | } |
diff --git a/crates/syntax/src/parsing/lexer.rs b/crates/syntax/src/parsing/lexer.rs index f1202113b..7e38c32cc 100644 --- a/crates/syntax/src/parsing/lexer.rs +++ b/crates/syntax/src/parsing/lexer.rs | |||
@@ -1,10 +1,10 @@ | |||
1 | //! Lexer analyzes raw input string and produces lexemes (tokens). | 1 | //! Lexer analyzes raw input string and produces lexemes (tokens). |
2 | //! It is just a bridge to `rustc_lexer`. | 2 | //! It is just a bridge to `rustc_lexer`. |
3 | 3 | ||
4 | use rustc_lexer::{LiteralKind as LK, RawStrError}; | ||
5 | |||
6 | use std::convert::TryInto; | 4 | use std::convert::TryInto; |
7 | 5 | ||
6 | use rustc_lexer::{LiteralKind as LK, RawStrError}; | ||
7 | |||
8 | use crate::{ | 8 | use crate::{ |
9 | SyntaxError, | 9 | SyntaxError, |
10 | SyntaxKind::{self, *}, | 10 | SyntaxKind::{self, *}, |
@@ -61,17 +61,18 @@ pub fn tokenize(text: &str) -> (Vec<Token>, Vec<SyntaxError>) { | |||
61 | (tokens, errors) | 61 | (tokens, errors) |
62 | } | 62 | } |
63 | 63 | ||
64 | /// Returns `SyntaxKind` and `Option<SyntaxError>` of the first token | 64 | /// Returns `SyntaxKind` and `Option<SyntaxError>` if `text` parses as a single token. |
65 | /// encountered at the beginning of the string. | ||
66 | /// | 65 | /// |
67 | /// Returns `None` if the string contains zero *or two or more* tokens. | 66 | /// Returns `None` if the string contains zero *or two or more* tokens. |
68 | /// The token is malformed if the returned error is not `None`. | 67 | /// The token is malformed if the returned error is not `None`. |
69 | /// | 68 | /// |
70 | /// Beware that unescape errors are not checked at tokenization time. | 69 | /// Beware that unescape errors are not checked at tokenization time. |
71 | pub fn lex_single_syntax_kind(text: &str) -> Option<(SyntaxKind, Option<SyntaxError>)> { | 70 | pub fn lex_single_syntax_kind(text: &str) -> Option<(SyntaxKind, Option<SyntaxError>)> { |
72 | lex_first_token(text) | 71 | let (first_token, err) = lex_first_token(text)?; |
73 | .filter(|(token, _)| token.len == TextSize::of(text)) | 72 | if first_token.len != TextSize::of(text) { |
74 | .map(|(token, error)| (token.kind, error)) | 73 | return None; |
74 | } | ||
75 | Some((first_token.kind, err)) | ||
75 | } | 76 | } |
76 | 77 | ||
77 | /// The same as `lex_single_syntax_kind()` but returns only `SyntaxKind` and | 78 | /// The same as `lex_single_syntax_kind()` but returns only `SyntaxKind` and |
@@ -79,9 +80,11 @@ pub fn lex_single_syntax_kind(text: &str) -> Option<(SyntaxKind, Option<SyntaxEr | |||
79 | /// | 80 | /// |
80 | /// Beware that unescape errors are not checked at tokenization time. | 81 | /// Beware that unescape errors are not checked at tokenization time. |
81 | pub fn lex_single_valid_syntax_kind(text: &str) -> Option<SyntaxKind> { | 82 | pub fn lex_single_valid_syntax_kind(text: &str) -> Option<SyntaxKind> { |
82 | lex_first_token(text) | 83 | let (single_token, err) = lex_single_syntax_kind(text)?; |
83 | .filter(|(token, error)| !error.is_some() && token.len == TextSize::of(text)) | 84 | if err.is_some() { |
84 | .map(|(token, _error)| token.kind) | 85 | return None; |
86 | } | ||
87 | Some(single_token) | ||
85 | } | 88 | } |
86 | 89 | ||
87 | /// Returns `SyntaxKind` and `Option<SyntaxError>` of the first token | 90 | /// Returns `SyntaxKind` and `Option<SyntaxError>` of the first token |
diff --git a/crates/syntax/src/validation.rs b/crates/syntax/src/validation.rs index 2dddaf09a..0f9a5e8ae 100644 --- a/crates/syntax/src/validation.rs +++ b/crates/syntax/src/validation.rs | |||
@@ -3,10 +3,11 @@ | |||
3 | mod block; | 3 | mod block; |
4 | 4 | ||
5 | use crate::{ | 5 | use crate::{ |
6 | ast, match_ast, AstNode, SyntaxError, | 6 | algo, ast, match_ast, AstNode, SyntaxError, |
7 | SyntaxKind::{BYTE, BYTE_STRING, CHAR, CONST, FN, INT_NUMBER, STRING, TYPE_ALIAS}, | 7 | SyntaxKind::{BYTE, BYTE_STRING, CHAR, CONST, FN, INT_NUMBER, STRING, TYPE_ALIAS}, |
8 | SyntaxNode, SyntaxToken, TextSize, T, | 8 | SyntaxNode, SyntaxToken, TextSize, T, |
9 | }; | 9 | }; |
10 | use rowan::Direction; | ||
10 | use rustc_lexer::unescape::{ | 11 | use rustc_lexer::unescape::{ |
11 | self, unescape_byte, unescape_byte_literal, unescape_char, unescape_literal, Mode, | 12 | self, unescape_byte, unescape_byte_literal, unescape_char, unescape_literal, Mode, |
12 | }; | 13 | }; |
@@ -95,6 +96,9 @@ pub(crate) fn validate(root: &SyntaxNode) -> Vec<SyntaxError> { | |||
95 | ast::Visibility(it) => validate_visibility(it, &mut errors), | 96 | ast::Visibility(it) => validate_visibility(it, &mut errors), |
96 | ast::RangeExpr(it) => validate_range_expr(it, &mut errors), | 97 | ast::RangeExpr(it) => validate_range_expr(it, &mut errors), |
97 | ast::PathSegment(it) => validate_path_keywords(it, &mut errors), | 98 | ast::PathSegment(it) => validate_path_keywords(it, &mut errors), |
99 | ast::RefType(it) => validate_trait_object_ref_ty(it, &mut errors), | ||
100 | ast::PtrType(it) => validate_trait_object_ptr_ty(it, &mut errors), | ||
101 | ast::FnPtrType(it) => validate_trait_object_fn_ptr_ret_ty(it, &mut errors), | ||
98 | _ => (), | 102 | _ => (), |
99 | } | 103 | } |
100 | } | 104 | } |
@@ -301,3 +305,42 @@ fn validate_path_keywords(segment: ast::PathSegment, errors: &mut Vec<SyntaxErro | |||
301 | return true; | 305 | return true; |
302 | } | 306 | } |
303 | } | 307 | } |
308 | |||
309 | fn validate_trait_object_ref_ty(ty: ast::RefType, errors: &mut Vec<SyntaxError>) { | ||
310 | if let Some(ast::Type::DynTraitType(ty)) = ty.ty() { | ||
311 | if let Some(err) = validate_trait_object_ty(ty) { | ||
312 | errors.push(err); | ||
313 | } | ||
314 | } | ||
315 | } | ||
316 | |||
317 | fn validate_trait_object_ptr_ty(ty: ast::PtrType, errors: &mut Vec<SyntaxError>) { | ||
318 | if let Some(ast::Type::DynTraitType(ty)) = ty.ty() { | ||
319 | if let Some(err) = validate_trait_object_ty(ty) { | ||
320 | errors.push(err); | ||
321 | } | ||
322 | } | ||
323 | } | ||
324 | |||
325 | fn validate_trait_object_fn_ptr_ret_ty(ty: ast::FnPtrType, errors: &mut Vec<SyntaxError>) { | ||
326 | if let Some(ast::Type::DynTraitType(ty)) = ty.ret_type().and_then(|ty| ty.ty()) { | ||
327 | if let Some(err) = validate_trait_object_ty(ty) { | ||
328 | errors.push(err); | ||
329 | } | ||
330 | } | ||
331 | } | ||
332 | |||
333 | fn validate_trait_object_ty(ty: ast::DynTraitType) -> Option<SyntaxError> { | ||
334 | let tbl = ty.type_bound_list()?; | ||
335 | |||
336 | if tbl.bounds().count() > 1 { | ||
337 | let dyn_token = ty.dyn_token()?; | ||
338 | let potential_parentheses = | ||
339 | algo::skip_trivia_token(dyn_token.prev_token()?, Direction::Prev)?; | ||
340 | let kind = potential_parentheses.kind(); | ||
341 | if !matches!(kind, T!['('] | T![<] | T![=]) { | ||
342 | return Some(SyntaxError::new("ambiguous `+` in a type", ty.syntax().text_range())); | ||
343 | } | ||
344 | } | ||
345 | None | ||
346 | } | ||
diff --git a/crates/syntax/test_data/parser/err/0046_ambiguous_trait_object.rast b/crates/syntax/test_data/parser/err/0046_ambiguous_trait_object.rast new file mode 100644 index 000000000..592741cdb --- /dev/null +++ b/crates/syntax/test_data/parser/err/0046_ambiguous_trait_object.rast | |||
@@ -0,0 +1,192 @@ | |||
1 | [email protected] | ||
2 | [email protected] | ||
3 | [email protected] "type" | ||
4 | [email protected] " " | ||
5 | [email protected] | ||
6 | [email protected] "Foo" | ||
7 | [email protected] | ||
8 | [email protected] "<" | ||
9 | [email protected] | ||
10 | [email protected] "\'a" | ||
11 | [email protected] ">" | ||
12 | [email protected] " " | ||
13 | [email protected] "=" | ||
14 | [email protected] " " | ||
15 | [email protected] | ||
16 | [email protected] "&" | ||
17 | [email protected] "\'a" | ||
18 | [email protected] " " | ||
19 | [email protected] | ||
20 | [email protected] "dyn" | ||
21 | [email protected] " " | ||
22 | [email protected] | ||
23 | [email protected] | ||
24 | [email protected] | ||
25 | [email protected] | ||
26 | [email protected] | ||
27 | [email protected] | ||
28 | [email protected] "Send" | ||
29 | [email protected] " " | ||
30 | [email protected] "+" | ||
31 | [email protected] " " | ||
32 | [email protected] | ||
33 | [email protected] | ||
34 | [email protected] | ||
35 | [email protected] | ||
36 | [email protected] | ||
37 | [email protected] "Sync" | ||
38 | [email protected] ";" | ||
39 | [email protected] "\n" | ||
40 | [email protected] | ||
41 | [email protected] "type" | ||
42 | [email protected] " " | ||
43 | [email protected] | ||
44 | [email protected] "Foo" | ||
45 | [email protected] " " | ||
46 | [email protected] "=" | ||
47 | [email protected] " " | ||
48 | [email protected] | ||
49 | [email protected] "*" | ||
50 | [email protected] "const" | ||
51 | [email protected] " " | ||
52 | [email protected] | ||
53 | [email protected] "dyn" | ||
54 | [email protected] " " | ||
55 | [email protected] | ||
56 | [email protected] | ||
57 | [email protected] | ||
58 | [email protected] | ||
59 | [email protected] | ||
60 | [email protected] | ||
61 | [email protected] "Send" | ||
62 | [email protected] " " | ||
63 | [email protected] "+" | ||
64 | [email protected] " " | ||
65 | [email protected] | ||
66 | [email protected] | ||
67 | [email protected] | ||
68 | [email protected] | ||
69 | [email protected] | ||
70 | [email protected] "Sync" | ||
71 | [email protected] ";" | ||
72 | [email protected] "\n" | ||
73 | [email protected] | ||
74 | [email protected] "type" | ||
75 | [email protected] " " | ||
76 | [email protected] | ||
77 | [email protected] "Foo" | ||
78 | [email protected] " " | ||
79 | [email protected] "=" | ||
80 | [email protected] " " | ||
81 | [email protected] | ||
82 | [email protected] "fn" | ||
83 | [email protected] | ||
84 | [email protected] "(" | ||
85 | [email protected] ")" | ||
86 | [email protected] " " | ||
87 | [email protected] | ||
88 | [email protected] "->" | ||
89 | [email protected] " " | ||
90 | [email protected] | ||
91 | [email protected] "dyn" | ||
92 | [email protected] " " | ||
93 | [email protected] | ||
94 | [email protected] | ||
95 | [email protected] | ||
96 | [email protected] | ||
97 | [email protected] | ||
98 | [email protected] | ||
99 | [email protected] "Send" | ||
100 | [email protected] " " | ||
101 | [email protected] "+" | ||
102 | [email protected] " " | ||
103 | [email protected] | ||
104 | [email protected] "\'static" | ||
105 | [email protected] ";" | ||
106 | [email protected] "\n" | ||
107 | [email protected] | ||
108 | [email protected] "fn" | ||
109 | [email protected] " " | ||
110 | [email protected] | ||
111 | [email protected] "main" | ||
112 | [email protected] | ||
113 | [email protected] "(" | ||
114 | [email protected] ")" | ||
115 | [email protected] " " | ||
116 | [email protected] | ||
117 | [email protected] "{" | ||
118 | [email protected] "\n " | ||
119 | [email protected] | ||
120 | [email protected] "let" | ||
121 | [email protected] " " | ||
122 | [email protected] | ||
123 | [email protected] | ||
124 | [email protected] "b" | ||
125 | [email protected] " " | ||
126 | [email protected] "=" | ||
127 | [email protected] " " | ||
128 | [email protected] | ||
129 | [email protected] | ||
130 | [email protected] "(" | ||
131 | [email protected] | ||
132 | [email protected] "&" | ||
133 | [email protected] | ||
134 | [email protected] | ||
135 | [email protected] | ||
136 | [email protected] | ||
137 | [email protected] "a" | ||
138 | [email protected] ")" | ||
139 | [email protected] " " | ||
140 | [email protected] "as" | ||
141 | [email protected] " " | ||
142 | [email protected] | ||
143 | [email protected] "&" | ||
144 | [email protected] | ||
145 | [email protected] "dyn" | ||
146 | [email protected] " " | ||
147 | [email protected] | ||
148 | [email protected] | ||
149 | [email protected] | ||
150 | [email protected] | ||
151 | [email protected] | ||
152 | [email protected] | ||
153 | [email protected] "Add" | ||
154 | [email protected] | ||
155 | [email protected] "<" | ||
156 | [email protected] | ||
157 | [email protected] | ||
158 | [email protected] | ||
159 | [email protected] | ||
160 | [email protected] | ||
161 | [email protected] "Other" | ||
162 | [email protected] "," | ||
163 | [email protected] " " | ||
164 | [email protected] | ||
165 | [email protected] | ||
166 | [email protected] "Output" | ||
167 | [email protected] " " | ||
168 | [email protected] "=" | ||
169 | [email protected] " " | ||
170 | [email protected] | ||
171 | [email protected] | ||
172 | [email protected] | ||
173 | [email protected] | ||
174 | [email protected] "Addable" | ||
175 | [email protected] ">" | ||
176 | [email protected] " " | ||
177 | [email protected] "+" | ||
178 | [email protected] " " | ||
179 | [email protected] | ||
180 | [email protected] | ||
181 | [email protected] | ||
182 | [email protected] | ||
183 | [email protected] | ||
184 | [email protected] "Other" | ||
185 | [email protected] ";" | ||
186 | [email protected] "\n" | ||
187 | [email protected] "}" | ||
188 | [email protected] "\n" | ||
189 | error 19..34: ambiguous `+` in a type | ||
190 | error 54..69: ambiguous `+` in a type | ||
191 | error 90..108: ambiguous `+` in a type | ||
192 | error 143..183: ambiguous `+` in a type | ||
diff --git a/crates/syntax/test_data/parser/err/0046_ambiguous_trait_object.rs b/crates/syntax/test_data/parser/err/0046_ambiguous_trait_object.rs new file mode 100644 index 000000000..3a73d81bb --- /dev/null +++ b/crates/syntax/test_data/parser/err/0046_ambiguous_trait_object.rs | |||
@@ -0,0 +1,6 @@ | |||
1 | type Foo<'a> = &'a dyn Send + Sync; | ||
2 | type Foo = *const dyn Send + Sync; | ||
3 | type Foo = fn() -> dyn Send + 'static; | ||
4 | fn main() { | ||
5 | let b = (&a) as &dyn Add<Other, Output = Addable> + Other; | ||
6 | } | ||
diff --git a/crates/syntax/test_data/parser/ok/0069_multi_trait_object.rast b/crates/syntax/test_data/parser/ok/0069_multi_trait_object.rast new file mode 100644 index 000000000..0cd868a83 --- /dev/null +++ b/crates/syntax/test_data/parser/ok/0069_multi_trait_object.rast | |||
@@ -0,0 +1,200 @@ | |||
1 | [email protected] | ||
2 | [email protected] | ||
3 | [email protected] "type" | ||
4 | [email protected] " " | ||
5 | [email protected] | ||
6 | [email protected] "Foo" | ||
7 | [email protected] | ||
8 | [email protected] "<" | ||
9 | [email protected] | ||
10 | [email protected] "\'a" | ||
11 | [email protected] ">" | ||
12 | [email protected] " " | ||
13 | [email protected] "=" | ||
14 | [email protected] " " | ||
15 | [email protected] | ||
16 | [email protected] "&" | ||
17 | [email protected] "\'a" | ||
18 | [email protected] " " | ||
19 | [email protected] | ||
20 | [email protected] "(" | ||
21 | [email protected] | ||
22 | [email protected] "dyn" | ||
23 | [email protected] " " | ||
24 | [email protected] | ||
25 | [email protected] | ||
26 | [email protected] | ||
27 | [email protected] | ||
28 | [email protected] | ||
29 | [email protected] | ||
30 | [email protected] "Send" | ||
31 | [email protected] " " | ||
32 | [email protected] "+" | ||
33 | [email protected] " " | ||
34 | [email protected] | ||
35 | [email protected] | ||
36 | [email protected] | ||
37 | [email protected] | ||
38 | [email protected] | ||
39 | [email protected] "Sync" | ||
40 | [email protected] ")" | ||
41 | [email protected] ";" | ||
42 | [email protected] "\n" | ||
43 | [email protected] | ||
44 | [email protected] "type" | ||
45 | [email protected] " " | ||
46 | [email protected] | ||
47 | [email protected] "Foo" | ||
48 | [email protected] " " | ||
49 | [email protected] "=" | ||
50 | [email protected] " " | ||
51 | [email protected] | ||
52 | [email protected] "*" | ||
53 | [email protected] "const" | ||
54 | [email protected] " " | ||
55 | [email protected] | ||
56 | [email protected] "(" | ||
57 | [email protected] | ||
58 | [email protected] "dyn" | ||
59 | [email protected] " " | ||
60 | [email protected] | ||
61 | [email protected] | ||
62 | [email protected] | ||
63 | [email protected] | ||
64 | [email protected] | ||
65 | [email protected] | ||
66 | [email protected] "Send" | ||
67 | [email protected] " " | ||
68 | [email protected] "+" | ||
69 | [email protected] " " | ||
70 | [email protected] | ||
71 | [email protected] | ||
72 | [email protected] | ||
73 | [email protected] | ||
74 | [email protected] | ||
75 | [email protected] "Sync" | ||
76 | [email protected] ")" | ||
77 | [email protected] ";" | ||
78 | [email protected] "\n" | ||
79 | [email protected] | ||
80 | [email protected] "type" | ||
81 | [email protected] " " | ||
82 | [email protected] | ||
83 | [email protected] "Foo" | ||
84 | [email protected] " " | ||
85 | [email protected] "=" | ||
86 | [email protected] " " | ||
87 | [email protected] | ||
88 | [email protected] "fn" | ||
89 | [email protected] | ||
90 | [email protected] "(" | ||
91 | [email protected] ")" | ||
92 | [email protected] " " | ||
93 | [email protected] | ||
94 | [email protected] "->" | ||
95 | [email protected] " " | ||
96 | [email protected] | ||
97 | [email protected] "(" | ||
98 | [email protected] | ||
99 | [email protected] "dyn" | ||
100 | [email protected] " " | ||
101 | [email protected] | ||
102 | [email protected] | ||
103 | [email protected] | ||
104 | [email protected] | ||
105 | [email protected] | ||
106 | [email protected] | ||
107 | [email protected] "Send" | ||
108 | [email protected] " " | ||
109 | [email protected] "+" | ||
110 | [email protected] " " | ||
111 | [email protected] | ||
112 | [email protected] "\'static" | ||
113 | [email protected] ")" | ||
114 | [email protected] ";" | ||
115 | [email protected] "\n" | ||
116 | [email protected] | ||
117 | [email protected] "fn" | ||
118 | [email protected] " " | ||
119 | [email protected] | ||
120 | [email protected] "main" | ||
121 | [email protected] | ||
122 | [email protected] "(" | ||
123 | [email protected] ")" | ||
124 | [email protected] " " | ||
125 | [email protected] | ||
126 | [email protected] "{" | ||
127 | [email protected] "\n " | ||
128 | [email protected] | ||
129 | [email protected] "let" | ||
130 | [email protected] " " | ||
131 | [email protected] | ||
132 | [email protected] | ||
133 | [email protected] "b" | ||
134 | [email protected] " " | ||
135 | [email protected] "=" | ||
136 | [email protected] " " | ||
137 | [email protected] | ||
138 | [email protected] | ||
139 | [email protected] "(" | ||
140 | [email protected] | ||
141 | [email protected] "&" | ||
142 | [email protected] | ||
143 | [email protected] | ||
144 | [email protected] | ||
145 | [email protected] | ||
146 | [email protected] "a" | ||
147 | [email protected] ")" | ||
148 | [email protected] " " | ||
149 | [email protected] "as" | ||
150 | [email protected] " " | ||
151 | [email protected] | ||
152 | [email protected] "&" | ||
153 | [email protected] | ||
154 | [email protected] "(" | ||
155 | [email protected] | ||
156 | [email protected] "dyn" | ||
157 | [email protected] " " | ||
158 | [email protected] | ||
159 | [email protected] | ||
160 | [email protected] | ||
161 | [email protected] | ||
162 | [email protected] | ||
163 | [email protected] | ||
164 | [email protected] "Add" | ||
165 | [email protected] | ||
166 | [email protected] "<" | ||
167 | [email protected] | ||
168 | [email protected] | ||
169 | [email protected] | ||
170 | [email protected] | ||
171 | [email protected] | ||
172 | [email protected] "Other" | ||
173 | [email protected] "," | ||
174 | [email protected] " " | ||
175 | [email protected] | ||
176 | [email protected] | ||
177 | [email protected] "Output" | ||
178 | [email protected] " " | ||
179 | [email protected] "=" | ||
180 | [email protected] " " | ||
181 | [email protected] | ||
182 | [email protected] | ||
183 | [email protected] | ||
184 | [email protected] | ||
185 | [email protected] "Addable" | ||
186 | [email protected] ">" | ||
187 | [email protected] " " | ||
188 | [email protected] "+" | ||
189 | [email protected] " " | ||
190 | [email protected] | ||
191 | [email protected] | ||
192 | [email protected] | ||
193 | [email protected] | ||
194 | [email protected] | ||
195 | [email protected] "Other" | ||
196 | [email protected] ")" | ||
197 | [email protected] ";" | ||
198 | [email protected] "\n" | ||
199 | [email protected] "}" | ||
200 | [email protected] "\n" | ||
diff --git a/crates/syntax/test_data/parser/ok/0069_multi_trait_object.rs b/crates/syntax/test_data/parser/ok/0069_multi_trait_object.rs new file mode 100644 index 000000000..97eb79c48 --- /dev/null +++ b/crates/syntax/test_data/parser/ok/0069_multi_trait_object.rs | |||
@@ -0,0 +1,6 @@ | |||
1 | type Foo<'a> = &'a (dyn Send + Sync); | ||
2 | type Foo = *const (dyn Send + Sync); | ||
3 | type Foo = fn() -> (dyn Send + 'static); | ||
4 | fn main() { | ||
5 | let b = (&a) as &(dyn Add<Other, Output = Addable> + Other); | ||
6 | } | ||