diff options
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ra_hir_def/src/item_scope.rs | 33 | ||||
-rw-r--r-- | crates/ra_hir_def/src/nameres/path_resolution.rs | 63 | ||||
-rw-r--r-- | crates/ra_hir_def/src/resolver.rs | 13 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/infer.rs | 7 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/infer/coerce.rs | 205 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/infer/unify.rs | 99 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/lib.rs | 48 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/lower.rs | 5 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/tests/coercion.rs | 138 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/traits.rs | 12 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/traits/builtin.rs | 191 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/traits/chalk.rs | 4 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/utils.rs | 32 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/complete_path.rs | 13 | ||||
-rw-r--r-- | crates/ra_ide/src/marks.rs | 1 | ||||
-rw-r--r-- | crates/ra_mbe/src/subtree_source.rs | 5 | ||||
-rw-r--r-- | crates/ra_mbe/src/tests.rs | 22 | ||||
-rw-r--r-- | crates/ra_parser/src/parser.rs | 2 |
18 files changed, 559 insertions, 334 deletions
diff --git a/crates/ra_hir_def/src/item_scope.rs b/crates/ra_hir_def/src/item_scope.rs index 6e958ca75..5e943b780 100644 --- a/crates/ra_hir_def/src/item_scope.rs +++ b/crates/ra_hir_def/src/item_scope.rs | |||
@@ -30,7 +30,7 @@ pub struct ItemScope { | |||
30 | legacy_macros: FxHashMap<Name, MacroDefId>, | 30 | legacy_macros: FxHashMap<Name, MacroDefId>, |
31 | } | 31 | } |
32 | 32 | ||
33 | static BUILTIN_SCOPE: Lazy<FxHashMap<Name, PerNs>> = Lazy::new(|| { | 33 | pub(crate) static BUILTIN_SCOPE: Lazy<FxHashMap<Name, PerNs>> = Lazy::new(|| { |
34 | BuiltinType::ALL | 34 | BuiltinType::ALL |
35 | .iter() | 35 | .iter() |
36 | .map(|(name, ty)| (name.clone(), PerNs::types(ty.clone().into(), Visibility::Public))) | 36 | .map(|(name, ty)| (name.clone(), PerNs::types(ty.clone().into(), Visibility::Public))) |
@@ -40,9 +40,9 @@ static BUILTIN_SCOPE: Lazy<FxHashMap<Name, PerNs>> = Lazy::new(|| { | |||
40 | /// Shadow mode for builtin type which can be shadowed by module. | 40 | /// Shadow mode for builtin type which can be shadowed by module. |
41 | #[derive(Debug, Copy, Clone, PartialEq, Eq)] | 41 | #[derive(Debug, Copy, Clone, PartialEq, Eq)] |
42 | pub(crate) enum BuiltinShadowMode { | 42 | pub(crate) enum BuiltinShadowMode { |
43 | // Prefer Module | 43 | /// Prefer user-defined modules (or other types) over builtins. |
44 | Module, | 44 | Module, |
45 | // Prefer Other Types | 45 | /// Prefer builtins over user-defined modules (but not other types). |
46 | Other, | 46 | Other, |
47 | } | 47 | } |
48 | 48 | ||
@@ -51,7 +51,7 @@ pub(crate) enum BuiltinShadowMode { | |||
51 | impl ItemScope { | 51 | impl ItemScope { |
52 | pub fn entries<'a>(&'a self) -> impl Iterator<Item = (&'a Name, PerNs)> + 'a { | 52 | pub fn entries<'a>(&'a self) -> impl Iterator<Item = (&'a Name, PerNs)> + 'a { |
53 | //FIXME: shadowing | 53 | //FIXME: shadowing |
54 | self.visible.iter().chain(BUILTIN_SCOPE.iter()).map(|(n, def)| (n, *def)) | 54 | self.visible.iter().map(|(n, def)| (n, *def)) |
55 | } | 55 | } |
56 | 56 | ||
57 | pub fn entries_without_primitives<'a>( | 57 | pub fn entries_without_primitives<'a>( |
@@ -79,29 +79,8 @@ impl ItemScope { | |||
79 | } | 79 | } |
80 | 80 | ||
81 | /// Get a name from current module scope, legacy macros are not included | 81 | /// Get a name from current module scope, legacy macros are not included |
82 | pub(crate) fn get(&self, name: &Name, shadow: BuiltinShadowMode) -> PerNs { | 82 | pub(crate) fn get(&self, name: &Name) -> PerNs { |
83 | match shadow { | 83 | self.visible.get(name).copied().unwrap_or_else(PerNs::none) |
84 | BuiltinShadowMode::Module => self | ||
85 | .visible | ||
86 | .get(name) | ||
87 | .or_else(|| BUILTIN_SCOPE.get(name)) | ||
88 | .copied() | ||
89 | .unwrap_or_else(PerNs::none), | ||
90 | BuiltinShadowMode::Other => { | ||
91 | let item = self.visible.get(name).copied(); | ||
92 | if let Some(def) = item { | ||
93 | if let Some(ModuleDefId::ModuleId(_)) = def.take_types() { | ||
94 | return BUILTIN_SCOPE | ||
95 | .get(name) | ||
96 | .copied() | ||
97 | .or(item) | ||
98 | .unwrap_or_else(PerNs::none); | ||
99 | } | ||
100 | } | ||
101 | |||
102 | item.or_else(|| BUILTIN_SCOPE.get(name).copied()).unwrap_or_else(PerNs::none) | ||
103 | } | ||
104 | } | ||
105 | } | 84 | } |
106 | 85 | ||
107 | pub(crate) fn name_of(&self, item: ItemInNs) -> Option<(&Name, Visibility)> { | 86 | pub(crate) fn name_of(&self, item: ItemInNs) -> Option<(&Name, Visibility)> { |
diff --git a/crates/ra_hir_def/src/nameres/path_resolution.rs b/crates/ra_hir_def/src/nameres/path_resolution.rs index fd6422d60..c058e70aa 100644 --- a/crates/ra_hir_def/src/nameres/path_resolution.rs +++ b/crates/ra_hir_def/src/nameres/path_resolution.rs | |||
@@ -18,6 +18,7 @@ use test_utils::tested_by; | |||
18 | 18 | ||
19 | use crate::{ | 19 | use crate::{ |
20 | db::DefDatabase, | 20 | db::DefDatabase, |
21 | item_scope::BUILTIN_SCOPE, | ||
21 | nameres::{BuiltinShadowMode, CrateDefMap}, | 22 | nameres::{BuiltinShadowMode, CrateDefMap}, |
22 | path::{ModPath, PathKind}, | 23 | path::{ModPath, PathKind}, |
23 | per_ns::PerNs, | 24 | per_ns::PerNs, |
@@ -103,15 +104,6 @@ impl CrateDefMap { | |||
103 | path: &ModPath, | 104 | path: &ModPath, |
104 | shadow: BuiltinShadowMode, | 105 | shadow: BuiltinShadowMode, |
105 | ) -> ResolvePathResult { | 106 | ) -> ResolvePathResult { |
106 | // if it is not the last segment, we prefer the module to the builtin | ||
107 | let prefer_module = |index| { | ||
108 | if index == path.segments.len() - 1 { | ||
109 | shadow | ||
110 | } else { | ||
111 | BuiltinShadowMode::Module | ||
112 | } | ||
113 | }; | ||
114 | |||
115 | let mut segments = path.segments.iter().enumerate(); | 107 | let mut segments = path.segments.iter().enumerate(); |
116 | let mut curr_per_ns: PerNs = match path.kind { | 108 | let mut curr_per_ns: PerNs = match path.kind { |
117 | PathKind::DollarCrate(krate) => { | 109 | PathKind::DollarCrate(krate) => { |
@@ -140,20 +132,29 @@ impl CrateDefMap { | |||
140 | if self.edition == Edition::Edition2015 | 132 | if self.edition == Edition::Edition2015 |
141 | && (path.kind == PathKind::Abs || mode == ResolveMode::Import) => | 133 | && (path.kind == PathKind::Abs || mode == ResolveMode::Import) => |
142 | { | 134 | { |
143 | let (idx, segment) = match segments.next() { | 135 | let (_, segment) = match segments.next() { |
144 | Some((idx, segment)) => (idx, segment), | 136 | Some((idx, segment)) => (idx, segment), |
145 | None => return ResolvePathResult::empty(ReachedFixedPoint::Yes), | 137 | None => return ResolvePathResult::empty(ReachedFixedPoint::Yes), |
146 | }; | 138 | }; |
147 | log::debug!("resolving {:?} in crate root (+ extern prelude)", segment); | 139 | log::debug!("resolving {:?} in crate root (+ extern prelude)", segment); |
148 | self.resolve_name_in_crate_root_or_extern_prelude(&segment, prefer_module(idx)) | 140 | self.resolve_name_in_crate_root_or_extern_prelude(&segment) |
149 | } | 141 | } |
150 | PathKind::Plain => { | 142 | PathKind::Plain => { |
151 | let (idx, segment) = match segments.next() { | 143 | let (_, segment) = match segments.next() { |
152 | Some((idx, segment)) => (idx, segment), | 144 | Some((idx, segment)) => (idx, segment), |
153 | None => return ResolvePathResult::empty(ReachedFixedPoint::Yes), | 145 | None => return ResolvePathResult::empty(ReachedFixedPoint::Yes), |
154 | }; | 146 | }; |
147 | // The first segment may be a builtin type. If the path has more | ||
148 | // than one segment, we first try resolving it as a module | ||
149 | // anyway. | ||
150 | // FIXME: If the next segment doesn't resolve in the module and | ||
151 | // BuiltinShadowMode wasn't Module, then we need to try | ||
152 | // resolving it as a builtin. | ||
153 | let prefer_module = | ||
154 | if path.segments.len() == 1 { shadow } else { BuiltinShadowMode::Module }; | ||
155 | |||
155 | log::debug!("resolving {:?} in module", segment); | 156 | log::debug!("resolving {:?} in module", segment); |
156 | self.resolve_name_in_module(db, original_module, &segment, prefer_module(idx)) | 157 | self.resolve_name_in_module(db, original_module, &segment, prefer_module) |
157 | } | 158 | } |
158 | PathKind::Super(lvl) => { | 159 | PathKind::Super(lvl) => { |
159 | let m = successors(Some(original_module), |m| self.modules[*m].parent) | 160 | let m = successors(Some(original_module), |m| self.modules[*m].parent) |
@@ -216,7 +217,7 @@ impl CrateDefMap { | |||
216 | } | 217 | } |
217 | 218 | ||
218 | // Since it is a qualified path here, it should not contains legacy macros | 219 | // Since it is a qualified path here, it should not contains legacy macros |
219 | self[module.local_id].scope.get(&segment, prefer_module(i)) | 220 | self[module.local_id].scope.get(&segment) |
220 | } | 221 | } |
221 | ModuleDefId::AdtId(AdtId::EnumId(e)) => { | 222 | ModuleDefId::AdtId(AdtId::EnumId(e)) => { |
222 | // enum variant | 223 | // enum variant |
@@ -275,33 +276,35 @@ impl CrateDefMap { | |||
275 | .scope | 276 | .scope |
276 | .get_legacy_macro(name) | 277 | .get_legacy_macro(name) |
277 | .map_or_else(PerNs::none, |m| PerNs::macros(m, Visibility::Public)); | 278 | .map_or_else(PerNs::none, |m| PerNs::macros(m, Visibility::Public)); |
278 | let from_scope = self[module].scope.get(name, shadow); | 279 | let from_scope = self[module].scope.get(name); |
280 | let from_builtin = BUILTIN_SCOPE.get(name).copied().unwrap_or_else(PerNs::none); | ||
281 | let from_scope_or_builtin = match shadow { | ||
282 | BuiltinShadowMode::Module => from_scope.or(from_builtin), | ||
283 | BuiltinShadowMode::Other => { | ||
284 | if let Some(ModuleDefId::ModuleId(_)) = from_scope.take_types() { | ||
285 | from_builtin.or(from_scope) | ||
286 | } else { | ||
287 | from_scope.or(from_builtin) | ||
288 | } | ||
289 | } | ||
290 | }; | ||
279 | let from_extern_prelude = self | 291 | let from_extern_prelude = self |
280 | .extern_prelude | 292 | .extern_prelude |
281 | .get(name) | 293 | .get(name) |
282 | .map_or(PerNs::none(), |&it| PerNs::types(it, Visibility::Public)); | 294 | .map_or(PerNs::none(), |&it| PerNs::types(it, Visibility::Public)); |
283 | let from_prelude = self.resolve_in_prelude(db, name, shadow); | 295 | let from_prelude = self.resolve_in_prelude(db, name); |
284 | 296 | ||
285 | from_legacy_macro.or(from_scope).or(from_extern_prelude).or(from_prelude) | 297 | from_legacy_macro.or(from_scope_or_builtin).or(from_extern_prelude).or(from_prelude) |
286 | } | 298 | } |
287 | 299 | ||
288 | fn resolve_name_in_crate_root_or_extern_prelude( | 300 | fn resolve_name_in_crate_root_or_extern_prelude(&self, name: &Name) -> PerNs { |
289 | &self, | 301 | let from_crate_root = self[self.root].scope.get(name); |
290 | name: &Name, | ||
291 | shadow: BuiltinShadowMode, | ||
292 | ) -> PerNs { | ||
293 | let from_crate_root = self[self.root].scope.get(name, shadow); | ||
294 | let from_extern_prelude = self.resolve_name_in_extern_prelude(name); | 302 | let from_extern_prelude = self.resolve_name_in_extern_prelude(name); |
295 | 303 | ||
296 | from_crate_root.or(from_extern_prelude) | 304 | from_crate_root.or(from_extern_prelude) |
297 | } | 305 | } |
298 | 306 | ||
299 | fn resolve_in_prelude( | 307 | fn resolve_in_prelude(&self, db: &impl DefDatabase, name: &Name) -> PerNs { |
300 | &self, | ||
301 | db: &impl DefDatabase, | ||
302 | name: &Name, | ||
303 | shadow: BuiltinShadowMode, | ||
304 | ) -> PerNs { | ||
305 | if let Some(prelude) = self.prelude { | 308 | if let Some(prelude) = self.prelude { |
306 | let keep; | 309 | let keep; |
307 | let def_map = if prelude.krate == self.krate { | 310 | let def_map = if prelude.krate == self.krate { |
@@ -311,7 +314,7 @@ impl CrateDefMap { | |||
311 | keep = db.crate_def_map(prelude.krate); | 314 | keep = db.crate_def_map(prelude.krate); |
312 | &keep | 315 | &keep |
313 | }; | 316 | }; |
314 | def_map[prelude.local_id].scope.get(name, shadow) | 317 | def_map[prelude.local_id].scope.get(name) |
315 | } else { | 318 | } else { |
316 | PerNs::none() | 319 | PerNs::none() |
317 | } | 320 | } |
diff --git a/crates/ra_hir_def/src/resolver.rs b/crates/ra_hir_def/src/resolver.rs index 5365b80e2..9dd4fa555 100644 --- a/crates/ra_hir_def/src/resolver.rs +++ b/crates/ra_hir_def/src/resolver.rs | |||
@@ -15,7 +15,7 @@ use crate::{ | |||
15 | db::DefDatabase, | 15 | db::DefDatabase, |
16 | expr::{ExprId, PatId}, | 16 | expr::{ExprId, PatId}, |
17 | generics::GenericParams, | 17 | generics::GenericParams, |
18 | item_scope::BuiltinShadowMode, | 18 | item_scope::{BuiltinShadowMode, BUILTIN_SCOPE}, |
19 | nameres::CrateDefMap, | 19 | nameres::CrateDefMap, |
20 | path::{ModPath, PathKind}, | 20 | path::{ModPath, PathKind}, |
21 | per_ns::PerNs, | 21 | per_ns::PerNs, |
@@ -193,7 +193,7 @@ impl Resolver { | |||
193 | return Some((res, idx)); | 193 | return Some((res, idx)); |
194 | } | 194 | } |
195 | Scope::LocalItemsScope(body) => { | 195 | Scope::LocalItemsScope(body) => { |
196 | let def = body.item_scope.get(first_name, BuiltinShadowMode::Other); | 196 | let def = body.item_scope.get(first_name); |
197 | if let Some(res) = to_type_ns(def) { | 197 | if let Some(res) = to_type_ns(def) { |
198 | return Some((res, None)); | 198 | return Some((res, None)); |
199 | } | 199 | } |
@@ -335,8 +335,10 @@ impl Resolver { | |||
335 | }; | 335 | }; |
336 | } | 336 | } |
337 | Scope::LocalItemsScope(body) => { | 337 | Scope::LocalItemsScope(body) => { |
338 | let def = body.item_scope.get(first_name, BuiltinShadowMode::Other); | 338 | // we don't bother looking in the builtin scope here because there are no builtin values |
339 | if let Some(res) = to_value_ns(def) { | 339 | let def = to_value_ns(body.item_scope.get(first_name)); |
340 | |||
341 | if let Some(res) = def { | ||
340 | return Some(ResolveValueResult::ValueNs(res)); | 342 | return Some(ResolveValueResult::ValueNs(res)); |
341 | } | 343 | } |
342 | } | 344 | } |
@@ -476,6 +478,9 @@ impl Scope { | |||
476 | m.crate_def_map.extern_prelude.iter().for_each(|(name, &def)| { | 478 | m.crate_def_map.extern_prelude.iter().for_each(|(name, &def)| { |
477 | f(name.clone(), ScopeDef::PerNs(PerNs::types(def, Visibility::Public))); | 479 | f(name.clone(), ScopeDef::PerNs(PerNs::types(def, Visibility::Public))); |
478 | }); | 480 | }); |
481 | BUILTIN_SCOPE.iter().for_each(|(name, &def)| { | ||
482 | f(name.clone(), ScopeDef::PerNs(def)); | ||
483 | }); | ||
479 | if let Some(prelude) = m.crate_def_map.prelude { | 484 | if let Some(prelude) = m.crate_def_map.prelude { |
480 | let prelude_def_map = db.crate_def_map(prelude.krate); | 485 | let prelude_def_map = db.crate_def_map(prelude.krate); |
481 | prelude_def_map[prelude.local_id].scope.entries().for_each(|(name, def)| { | 486 | prelude_def_map[prelude.local_id].scope.entries().for_each(|(name, def)| { |
diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs index 76069eb9c..6e1d268de 100644 --- a/crates/ra_hir_ty/src/infer.rs +++ b/crates/ra_hir_ty/src/infer.rs | |||
@@ -206,12 +206,6 @@ struct InferenceContext<'a, D: HirDatabase> { | |||
206 | /// closures, but currently this is the only field that will change there, | 206 | /// closures, but currently this is the only field that will change there, |
207 | /// so it doesn't make sense. | 207 | /// so it doesn't make sense. |
208 | return_ty: Ty, | 208 | return_ty: Ty, |
209 | |||
210 | /// Impls of `CoerceUnsized` used in coercion. | ||
211 | /// (from_ty_ctor, to_ty_ctor) => coerce_generic_index | ||
212 | // FIXME: Use trait solver for this. | ||
213 | // Chalk seems unable to work well with builtin impl of `Unsize` now. | ||
214 | coerce_unsized_map: FxHashMap<(TypeCtor, TypeCtor), usize>, | ||
215 | } | 209 | } |
216 | 210 | ||
217 | impl<'a, D: HirDatabase> InferenceContext<'a, D> { | 211 | impl<'a, D: HirDatabase> InferenceContext<'a, D> { |
@@ -222,7 +216,6 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
222 | obligations: Vec::default(), | 216 | obligations: Vec::default(), |
223 | return_ty: Ty::Unknown, // set in collect_fn_signature | 217 | return_ty: Ty::Unknown, // set in collect_fn_signature |
224 | trait_env: TraitEnvironment::lower(db, &resolver), | 218 | trait_env: TraitEnvironment::lower(db, &resolver), |
225 | coerce_unsized_map: Self::init_coerce_unsized_map(db, &resolver), | ||
226 | db, | 219 | db, |
227 | owner, | 220 | owner, |
228 | body: db.body(owner), | 221 | body: db.body(owner), |
diff --git a/crates/ra_hir_ty/src/infer/coerce.rs b/crates/ra_hir_ty/src/infer/coerce.rs index fb6a51b12..95ac3c713 100644 --- a/crates/ra_hir_ty/src/infer/coerce.rs +++ b/crates/ra_hir_ty/src/infer/coerce.rs | |||
@@ -4,11 +4,12 @@ | |||
4 | //! | 4 | //! |
5 | //! See: https://doc.rust-lang.org/nomicon/coercions.html | 5 | //! See: https://doc.rust-lang.org/nomicon/coercions.html |
6 | 6 | ||
7 | use hir_def::{lang_item::LangItemTarget, resolver::Resolver, type_ref::Mutability, AdtId}; | 7 | use hir_def::{lang_item::LangItemTarget, type_ref::Mutability}; |
8 | use rustc_hash::FxHashMap; | ||
9 | use test_utils::tested_by; | 8 | use test_utils::tested_by; |
10 | 9 | ||
11 | use crate::{autoderef, db::HirDatabase, Substs, Ty, TypeCtor, TypeWalk}; | 10 | use crate::{ |
11 | autoderef, db::HirDatabase, traits::Solution, Obligation, Substs, TraitRef, Ty, TypeCtor, | ||
12 | }; | ||
12 | 13 | ||
13 | use super::{unify::TypeVarValue, InEnvironment, InferTy, InferenceContext}; | 14 | use super::{unify::TypeVarValue, InEnvironment, InferTy, InferenceContext}; |
14 | 15 | ||
@@ -39,44 +40,6 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
39 | } | 40 | } |
40 | } | 41 | } |
41 | 42 | ||
42 | pub(super) fn init_coerce_unsized_map( | ||
43 | db: &'a D, | ||
44 | resolver: &Resolver, | ||
45 | ) -> FxHashMap<(TypeCtor, TypeCtor), usize> { | ||
46 | let krate = resolver.krate().unwrap(); | ||
47 | let impls = match db.lang_item(krate, "coerce_unsized".into()) { | ||
48 | Some(LangItemTarget::TraitId(trait_)) => db.impls_for_trait(krate, trait_), | ||
49 | _ => return FxHashMap::default(), | ||
50 | }; | ||
51 | |||
52 | impls | ||
53 | .iter() | ||
54 | .filter_map(|&impl_id| { | ||
55 | let trait_ref = db.impl_trait(impl_id)?; | ||
56 | |||
57 | // `CoerseUnsized` has one generic parameter for the target type. | ||
58 | let cur_from_ty = trait_ref.value.substs.0.get(0)?; | ||
59 | let cur_to_ty = trait_ref.value.substs.0.get(1)?; | ||
60 | |||
61 | match (&cur_from_ty, cur_to_ty) { | ||
62 | (ty_app!(ctor1, st1), ty_app!(ctor2, st2)) => { | ||
63 | // FIXME: We return the first non-equal bound as the type parameter to coerce to unsized type. | ||
64 | // This works for smart-pointer-like coercion, which covers all impls from std. | ||
65 | st1.iter().zip(st2.iter()).enumerate().find_map(|(i, (ty1, ty2))| { | ||
66 | match (ty1, ty2) { | ||
67 | (Ty::Bound(idx1), Ty::Bound(idx2)) if idx1 != idx2 => { | ||
68 | Some(((*ctor1, *ctor2), i)) | ||
69 | } | ||
70 | _ => None, | ||
71 | } | ||
72 | }) | ||
73 | } | ||
74 | _ => None, | ||
75 | } | ||
76 | }) | ||
77 | .collect() | ||
78 | } | ||
79 | |||
80 | fn coerce_inner(&mut self, mut from_ty: Ty, to_ty: &Ty) -> bool { | 43 | fn coerce_inner(&mut self, mut from_ty: Ty, to_ty: &Ty) -> bool { |
81 | match (&from_ty, to_ty) { | 44 | match (&from_ty, to_ty) { |
82 | // Never type will make type variable to fallback to Never Type instead of Unknown. | 45 | // Never type will make type variable to fallback to Never Type instead of Unknown. |
@@ -157,154 +120,38 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
157 | /// | 120 | /// |
158 | /// See: https://doc.rust-lang.org/nightly/std/marker/trait.CoerceUnsized.html | 121 | /// See: https://doc.rust-lang.org/nightly/std/marker/trait.CoerceUnsized.html |
159 | fn try_coerce_unsized(&mut self, from_ty: &Ty, to_ty: &Ty) -> Option<bool> { | 122 | fn try_coerce_unsized(&mut self, from_ty: &Ty, to_ty: &Ty) -> Option<bool> { |
160 | let (ctor1, st1, ctor2, st2) = match (from_ty, to_ty) { | 123 | let krate = self.resolver.krate().unwrap(); |
161 | (ty_app!(ctor1, st1), ty_app!(ctor2, st2)) => (ctor1, st1, ctor2, st2), | 124 | let coerce_unsized_trait = match self.db.lang_item(krate, "coerce_unsized".into()) { |
125 | Some(LangItemTarget::TraitId(trait_)) => trait_, | ||
162 | _ => return None, | 126 | _ => return None, |
163 | }; | 127 | }; |
164 | 128 | ||
165 | let coerce_generic_index = *self.coerce_unsized_map.get(&(*ctor1, *ctor2))?; | 129 | let generic_params = crate::utils::generics(self.db, coerce_unsized_trait.into()); |
166 | 130 | if generic_params.len() != 2 { | |
167 | // Check `Unsize` first | 131 | // The CoerceUnsized trait should have two generic params: Self and T. |
168 | match self.check_unsize_and_coerce( | 132 | return None; |
169 | st1.0.get(coerce_generic_index)?, | ||
170 | st2.0.get(coerce_generic_index)?, | ||
171 | 0, | ||
172 | ) { | ||
173 | Some(true) => {} | ||
174 | ret => return ret, | ||
175 | } | 133 | } |
176 | 134 | ||
177 | let ret = st1 | 135 | let substs = Substs::build_for_generics(&generic_params) |
178 | .iter() | 136 | .push(from_ty.clone()) |
179 | .zip(st2.iter()) | 137 | .push(to_ty.clone()) |
180 | .enumerate() | 138 | .build(); |
181 | .filter(|&(idx, _)| idx != coerce_generic_index) | 139 | let trait_ref = TraitRef { trait_: coerce_unsized_trait, substs }; |
182 | .all(|(_, (ty1, ty2))| self.unify(ty1, ty2)); | 140 | let goal = InEnvironment::new(self.trait_env.clone(), Obligation::Trait(trait_ref)); |
183 | 141 | ||
184 | Some(ret) | 142 | let canonicalizer = self.canonicalizer(); |
185 | } | 143 | let canonicalized = canonicalizer.canonicalize_obligation(goal); |
186 | 144 | ||
187 | /// Check if `from_ty: Unsize<to_ty>`, and coerce to `to_ty` if it holds. | 145 | let solution = self.db.trait_solve(krate, canonicalized.value.clone())?; |
188 | /// | ||
189 | /// It should not be directly called. It is only used by `try_coerce_unsized`. | ||
190 | /// | ||
191 | /// See: https://doc.rust-lang.org/nightly/std/marker/trait.Unsize.html | ||
192 | fn check_unsize_and_coerce(&mut self, from_ty: &Ty, to_ty: &Ty, depth: usize) -> Option<bool> { | ||
193 | if depth > 1000 { | ||
194 | panic!("Infinite recursion in coercion"); | ||
195 | } | ||
196 | |||
197 | match (&from_ty, &to_ty) { | ||
198 | // `[T; N]` -> `[T]` | ||
199 | (ty_app!(TypeCtor::Array, st1), ty_app!(TypeCtor::Slice, st2)) => { | ||
200 | Some(self.unify(&st1[0], &st2[0])) | ||
201 | } | ||
202 | 146 | ||
203 | // `T` -> `dyn Trait` when `T: Trait` | 147 | match solution { |
204 | (_, Ty::Dyn(_)) => { | 148 | Solution::Unique(v) => { |
205 | // FIXME: Check predicates | 149 | canonicalized.apply_solution(self, v.0); |
206 | Some(true) | ||
207 | } | ||
208 | |||
209 | // `(..., T)` -> `(..., U)` when `T: Unsize<U>` | ||
210 | ( | ||
211 | ty_app!(TypeCtor::Tuple { cardinality: len1 }, st1), | ||
212 | ty_app!(TypeCtor::Tuple { cardinality: len2 }, st2), | ||
213 | ) => { | ||
214 | if len1 != len2 || *len1 == 0 { | ||
215 | return None; | ||
216 | } | ||
217 | |||
218 | match self.check_unsize_and_coerce( | ||
219 | st1.last().unwrap(), | ||
220 | st2.last().unwrap(), | ||
221 | depth + 1, | ||
222 | ) { | ||
223 | Some(true) => {} | ||
224 | ret => return ret, | ||
225 | } | ||
226 | |||
227 | let ret = st1[..st1.len() - 1] | ||
228 | .iter() | ||
229 | .zip(&st2[..st2.len() - 1]) | ||
230 | .all(|(ty1, ty2)| self.unify(ty1, ty2)); | ||
231 | |||
232 | Some(ret) | ||
233 | } | ||
234 | |||
235 | // Foo<..., T, ...> is Unsize<Foo<..., U, ...>> if: | ||
236 | // - T: Unsize<U> | ||
237 | // - Foo is a struct | ||
238 | // - Only the last field of Foo has a type involving T | ||
239 | // - T is not part of the type of any other fields | ||
240 | // - Bar<T>: Unsize<Bar<U>>, if the last field of Foo has type Bar<T> | ||
241 | ( | ||
242 | ty_app!(TypeCtor::Adt(AdtId::StructId(struct1)), st1), | ||
243 | ty_app!(TypeCtor::Adt(AdtId::StructId(struct2)), st2), | ||
244 | ) if struct1 == struct2 => { | ||
245 | let field_tys = self.db.field_types((*struct1).into()); | ||
246 | let struct_data = self.db.struct_data(*struct1); | ||
247 | |||
248 | let mut fields = struct_data.variant_data.fields().iter(); | ||
249 | let (last_field_id, _data) = fields.next_back()?; | ||
250 | |||
251 | // Get the generic parameter involved in the last field. | ||
252 | let unsize_generic_index = { | ||
253 | let mut index = None; | ||
254 | let mut multiple_param = false; | ||
255 | field_tys[last_field_id].value.walk(&mut |ty| { | ||
256 | if let &Ty::Bound(idx) = ty { | ||
257 | if index.is_none() { | ||
258 | index = Some(idx); | ||
259 | } else if Some(idx) != index { | ||
260 | multiple_param = true; | ||
261 | } | ||
262 | } | ||
263 | }); | ||
264 | |||
265 | if multiple_param { | ||
266 | return None; | ||
267 | } | ||
268 | index? | ||
269 | }; | ||
270 | |||
271 | // Check other fields do not involve it. | ||
272 | let mut multiple_used = false; | ||
273 | fields.for_each(|(field_id, _data)| { | ||
274 | field_tys[field_id].value.walk(&mut |ty| match ty { | ||
275 | &Ty::Bound(idx) if idx == unsize_generic_index => multiple_used = true, | ||
276 | _ => {} | ||
277 | }) | ||
278 | }); | ||
279 | if multiple_used { | ||
280 | return None; | ||
281 | } | ||
282 | |||
283 | let unsize_generic_index = unsize_generic_index as usize; | ||
284 | |||
285 | // Check `Unsize` first | ||
286 | match self.check_unsize_and_coerce( | ||
287 | st1.get(unsize_generic_index)?, | ||
288 | st2.get(unsize_generic_index)?, | ||
289 | depth + 1, | ||
290 | ) { | ||
291 | Some(true) => {} | ||
292 | ret => return ret, | ||
293 | } | ||
294 | |||
295 | // Then unify other parameters | ||
296 | let ret = st1 | ||
297 | .iter() | ||
298 | .zip(st2.iter()) | ||
299 | .enumerate() | ||
300 | .filter(|&(idx, _)| idx != unsize_generic_index) | ||
301 | .all(|(_, (ty1, ty2))| self.unify(ty1, ty2)); | ||
302 | |||
303 | Some(ret) | ||
304 | } | 150 | } |
151 | _ => return None, | ||
152 | }; | ||
305 | 153 | ||
306 | _ => None, | 154 | Some(true) |
307 | } | ||
308 | } | 155 | } |
309 | 156 | ||
310 | /// Unify `from_ty` to `to_ty` with optional auto Deref | 157 | /// Unify `from_ty` to `to_ty` with optional auto Deref |
diff --git a/crates/ra_hir_ty/src/infer/unify.rs b/crates/ra_hir_ty/src/infer/unify.rs index 2d03c5c33..aed527fe5 100644 --- a/crates/ra_hir_ty/src/infer/unify.rs +++ b/crates/ra_hir_ty/src/infer/unify.rs | |||
@@ -7,10 +7,7 @@ use ena::unify::{InPlaceUnificationTable, NoError, UnifyKey, UnifyValue}; | |||
7 | use test_utils::tested_by; | 7 | use test_utils::tested_by; |
8 | 8 | ||
9 | use super::{InferenceContext, Obligation}; | 9 | use super::{InferenceContext, Obligation}; |
10 | use crate::{ | 10 | use crate::{db::HirDatabase, Canonical, InEnvironment, InferTy, Substs, Ty, TypeCtor, TypeWalk}; |
11 | db::HirDatabase, utils::make_mut_slice, Canonical, InEnvironment, InferTy, ProjectionPredicate, | ||
12 | ProjectionTy, Substs, TraitRef, Ty, TypeCtor, TypeWalk, | ||
13 | }; | ||
14 | 11 | ||
15 | impl<'a, D: HirDatabase> InferenceContext<'a, D> { | 12 | impl<'a, D: HirDatabase> InferenceContext<'a, D> { |
16 | pub(super) fn canonicalizer<'b>(&'b mut self) -> Canonicalizer<'a, 'b, D> | 13 | pub(super) fn canonicalizer<'b>(&'b mut self) -> Canonicalizer<'a, 'b, D> |
@@ -50,42 +47,38 @@ where | |||
50 | }) | 47 | }) |
51 | } | 48 | } |
52 | 49 | ||
53 | fn do_canonicalize_ty(&mut self, ty: Ty) -> Ty { | 50 | fn do_canonicalize<T: TypeWalk>(&mut self, t: T, binders: usize) -> T { |
54 | ty.fold(&mut |ty| match ty { | 51 | t.fold_binders( |
55 | Ty::Infer(tv) => { | 52 | &mut |ty, binders| match ty { |
56 | let inner = tv.to_inner(); | 53 | Ty::Infer(tv) => { |
57 | if self.var_stack.contains(&inner) { | 54 | let inner = tv.to_inner(); |
58 | // recursive type | 55 | if self.var_stack.contains(&inner) { |
59 | return tv.fallback_value(); | 56 | // recursive type |
60 | } | 57 | return tv.fallback_value(); |
61 | if let Some(known_ty) = | 58 | } |
62 | self.ctx.table.var_unification_table.inlined_probe_value(inner).known() | 59 | if let Some(known_ty) = |
63 | { | 60 | self.ctx.table.var_unification_table.inlined_probe_value(inner).known() |
64 | self.var_stack.push(inner); | 61 | { |
65 | let result = self.do_canonicalize_ty(known_ty.clone()); | 62 | self.var_stack.push(inner); |
66 | self.var_stack.pop(); | 63 | let result = self.do_canonicalize(known_ty.clone(), binders); |
67 | result | 64 | self.var_stack.pop(); |
68 | } else { | 65 | result |
69 | let root = self.ctx.table.var_unification_table.find(inner); | 66 | } else { |
70 | let free_var = match tv { | 67 | let root = self.ctx.table.var_unification_table.find(inner); |
71 | InferTy::TypeVar(_) => InferTy::TypeVar(root), | 68 | let free_var = match tv { |
72 | InferTy::IntVar(_) => InferTy::IntVar(root), | 69 | InferTy::TypeVar(_) => InferTy::TypeVar(root), |
73 | InferTy::FloatVar(_) => InferTy::FloatVar(root), | 70 | InferTy::IntVar(_) => InferTy::IntVar(root), |
74 | InferTy::MaybeNeverTypeVar(_) => InferTy::MaybeNeverTypeVar(root), | 71 | InferTy::FloatVar(_) => InferTy::FloatVar(root), |
75 | }; | 72 | InferTy::MaybeNeverTypeVar(_) => InferTy::MaybeNeverTypeVar(root), |
76 | let position = self.add(free_var); | 73 | }; |
77 | Ty::Bound(position as u32) | 74 | let position = self.add(free_var); |
75 | Ty::Bound((position + binders) as u32) | ||
76 | } | ||
78 | } | 77 | } |
79 | } | 78 | _ => ty, |
80 | _ => ty, | 79 | }, |
81 | }) | 80 | binders, |
82 | } | 81 | ) |
83 | |||
84 | fn do_canonicalize_trait_ref(&mut self, mut trait_ref: TraitRef) -> TraitRef { | ||
85 | for ty in make_mut_slice(&mut trait_ref.substs.0) { | ||
86 | *ty = self.do_canonicalize_ty(ty.clone()); | ||
87 | } | ||
88 | trait_ref | ||
89 | } | 82 | } |
90 | 83 | ||
91 | fn into_canonicalized<T>(self, result: T) -> Canonicalized<T> { | 84 | fn into_canonicalized<T>(self, result: T) -> Canonicalized<T> { |
@@ -95,28 +88,8 @@ where | |||
95 | } | 88 | } |
96 | } | 89 | } |
97 | 90 | ||
98 | fn do_canonicalize_projection_ty(&mut self, mut projection_ty: ProjectionTy) -> ProjectionTy { | ||
99 | for ty in make_mut_slice(&mut projection_ty.parameters.0) { | ||
100 | *ty = self.do_canonicalize_ty(ty.clone()); | ||
101 | } | ||
102 | projection_ty | ||
103 | } | ||
104 | |||
105 | fn do_canonicalize_projection_predicate( | ||
106 | &mut self, | ||
107 | projection: ProjectionPredicate, | ||
108 | ) -> ProjectionPredicate { | ||
109 | let ty = self.do_canonicalize_ty(projection.ty); | ||
110 | let projection_ty = self.do_canonicalize_projection_ty(projection.projection_ty); | ||
111 | |||
112 | ProjectionPredicate { ty, projection_ty } | ||
113 | } | ||
114 | |||
115 | // FIXME: add some point, we need to introduce a `Fold` trait that abstracts | ||
116 | // over all the things that can be canonicalized (like Chalk and rustc have) | ||
117 | |||
118 | pub(crate) fn canonicalize_ty(mut self, ty: Ty) -> Canonicalized<Ty> { | 91 | pub(crate) fn canonicalize_ty(mut self, ty: Ty) -> Canonicalized<Ty> { |
119 | let result = self.do_canonicalize_ty(ty); | 92 | let result = self.do_canonicalize(ty, 0); |
120 | self.into_canonicalized(result) | 93 | self.into_canonicalized(result) |
121 | } | 94 | } |
122 | 95 | ||
@@ -125,10 +98,8 @@ where | |||
125 | obligation: InEnvironment<Obligation>, | 98 | obligation: InEnvironment<Obligation>, |
126 | ) -> Canonicalized<InEnvironment<Obligation>> { | 99 | ) -> Canonicalized<InEnvironment<Obligation>> { |
127 | let result = match obligation.value { | 100 | let result = match obligation.value { |
128 | Obligation::Trait(tr) => Obligation::Trait(self.do_canonicalize_trait_ref(tr)), | 101 | Obligation::Trait(tr) => Obligation::Trait(self.do_canonicalize(tr, 0)), |
129 | Obligation::Projection(pr) => { | 102 | Obligation::Projection(pr) => Obligation::Projection(self.do_canonicalize(pr, 0)), |
130 | Obligation::Projection(self.do_canonicalize_projection_predicate(pr)) | ||
131 | } | ||
132 | }; | 103 | }; |
133 | self.into_canonicalized(InEnvironment { | 104 | self.into_canonicalized(InEnvironment { |
134 | value: result, | 105 | value: result, |
diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs index 13c5e6c6b..0009c426c 100644 --- a/crates/ra_hir_ty/src/lib.rs +++ b/crates/ra_hir_ty/src/lib.rs | |||
@@ -461,6 +461,12 @@ impl<T> Binders<T> { | |||
461 | } | 461 | } |
462 | } | 462 | } |
463 | 463 | ||
464 | impl<T: Clone> Binders<&T> { | ||
465 | pub fn cloned(&self) -> Binders<T> { | ||
466 | Binders { num_binders: self.num_binders, value: self.value.clone() } | ||
467 | } | ||
468 | } | ||
469 | |||
464 | impl<T: TypeWalk> Binders<T> { | 470 | impl<T: TypeWalk> Binders<T> { |
465 | /// Substitutes all variables. | 471 | /// Substitutes all variables. |
466 | pub fn subst(self, subst: &Substs) -> T { | 472 | pub fn subst(self, subst: &Substs) -> T { |
@@ -661,6 +667,17 @@ impl Ty { | |||
661 | } | 667 | } |
662 | } | 668 | } |
663 | 669 | ||
670 | /// If this is a `dyn Trait` type, this returns the `Trait` part. | ||
671 | pub fn dyn_trait_ref(&self) -> Option<&TraitRef> { | ||
672 | match self { | ||
673 | Ty::Dyn(bounds) => bounds.get(0).and_then(|b| match b { | ||
674 | GenericPredicate::Implemented(trait_ref) => Some(trait_ref), | ||
675 | _ => None, | ||
676 | }), | ||
677 | _ => None, | ||
678 | } | ||
679 | } | ||
680 | |||
664 | fn builtin_deref(&self) -> Option<Ty> { | 681 | fn builtin_deref(&self) -> Option<Ty> { |
665 | match self { | 682 | match self { |
666 | Ty::Apply(a_ty) => match a_ty.ctor { | 683 | Ty::Apply(a_ty) => match a_ty.ctor { |
@@ -746,6 +763,20 @@ pub trait TypeWalk { | |||
746 | /// variable for the self type. | 763 | /// variable for the self type. |
747 | fn walk_mut_binders(&mut self, f: &mut impl FnMut(&mut Ty, usize), binders: usize); | 764 | fn walk_mut_binders(&mut self, f: &mut impl FnMut(&mut Ty, usize), binders: usize); |
748 | 765 | ||
766 | fn fold_binders(mut self, f: &mut impl FnMut(Ty, usize) -> Ty, binders: usize) -> Self | ||
767 | where | ||
768 | Self: Sized, | ||
769 | { | ||
770 | self.walk_mut_binders( | ||
771 | &mut |ty_mut, binders| { | ||
772 | let ty = mem::replace(ty_mut, Ty::Unknown); | ||
773 | *ty_mut = f(ty, binders); | ||
774 | }, | ||
775 | binders, | ||
776 | ); | ||
777 | self | ||
778 | } | ||
779 | |||
749 | fn fold(mut self, f: &mut impl FnMut(Ty) -> Ty) -> Self | 780 | fn fold(mut self, f: &mut impl FnMut(Ty) -> Ty) -> Self |
750 | where | 781 | where |
751 | Self: Sized, | 782 | Self: Sized, |
@@ -783,13 +814,16 @@ pub trait TypeWalk { | |||
783 | where | 814 | where |
784 | Self: Sized, | 815 | Self: Sized, |
785 | { | 816 | { |
786 | self.fold(&mut |ty| match ty { | 817 | self.fold_binders( |
787 | Ty::Bound(idx) => { | 818 | &mut |ty, binders| match ty { |
788 | assert!(idx as i32 >= -n); | 819 | Ty::Bound(idx) if idx as usize >= binders => { |
789 | Ty::Bound((idx as i32 + n) as u32) | 820 | assert!(idx as i32 >= -n); |
790 | } | 821 | Ty::Bound((idx as i32 + n) as u32) |
791 | ty => ty, | 822 | } |
792 | }) | 823 | ty => ty, |
824 | }, | ||
825 | 0, | ||
826 | ) | ||
793 | } | 827 | } |
794 | } | 828 | } |
795 | 829 | ||
diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs index 52da34574..092977e93 100644 --- a/crates/ra_hir_ty/src/lower.rs +++ b/crates/ra_hir_ty/src/lower.rs | |||
@@ -239,7 +239,10 @@ impl Ty { | |||
239 | ) -> Ty { | 239 | ) -> Ty { |
240 | let ty = match resolution { | 240 | let ty = match resolution { |
241 | TypeNs::TraitId(trait_) => { | 241 | TypeNs::TraitId(trait_) => { |
242 | let trait_ref = TraitRef::from_resolved_path(ctx, trait_, resolved_segment, None); | 242 | // if this is a bare dyn Trait, we'll directly put the required ^0 for the self type in there |
243 | let self_ty = if remaining_segments.len() == 0 { Some(Ty::Bound(0)) } else { None }; | ||
244 | let trait_ref = | ||
245 | TraitRef::from_resolved_path(ctx, trait_, resolved_segment, self_ty); | ||
243 | return if remaining_segments.len() == 1 { | 246 | return if remaining_segments.len() == 1 { |
244 | let segment = remaining_segments.first().unwrap(); | 247 | let segment = remaining_segments.first().unwrap(); |
245 | let associated_ty = associated_type_by_name_including_super_traits( | 248 | let associated_ty = associated_type_by_name_including_super_traits( |
diff --git a/crates/ra_hir_ty/src/tests/coercion.rs b/crates/ra_hir_ty/src/tests/coercion.rs index 42330b269..60ad6e9be 100644 --- a/crates/ra_hir_ty/src/tests/coercion.rs +++ b/crates/ra_hir_ty/src/tests/coercion.rs | |||
@@ -548,3 +548,141 @@ impl<TT> S<TT> { | |||
548 | "### | 548 | "### |
549 | ); | 549 | ); |
550 | } | 550 | } |
551 | |||
552 | #[test] | ||
553 | fn coerce_unsize_array() { | ||
554 | assert_snapshot!( | ||
555 | infer_with_mismatches(r#" | ||
556 | #[lang = "unsize"] | ||
557 | pub trait Unsize<T> {} | ||
558 | #[lang = "coerce_unsized"] | ||
559 | pub trait CoerceUnsized<T> {} | ||
560 | |||
561 | impl<T: Unsize<U>, U> CoerceUnsized<&U> for &T {} | ||
562 | |||
563 | fn test() { | ||
564 | let f: &[usize] = &[1, 2, 3]; | ||
565 | } | ||
566 | "#, true), | ||
567 | @r###" | ||
568 | [162; 199) '{ ... 3]; }': () | ||
569 | [172; 173) 'f': &[usize] | ||
570 | [186; 196) '&[1, 2, 3]': &[usize; _] | ||
571 | [187; 196) '[1, 2, 3]': [usize; _] | ||
572 | [188; 189) '1': usize | ||
573 | [191; 192) '2': usize | ||
574 | [194; 195) '3': usize | ||
575 | "### | ||
576 | ); | ||
577 | } | ||
578 | |||
579 | #[test] | ||
580 | fn coerce_unsize_trait_object() { | ||
581 | assert_snapshot!( | ||
582 | infer_with_mismatches(r#" | ||
583 | #[lang = "unsize"] | ||
584 | pub trait Unsize<T> {} | ||
585 | #[lang = "coerce_unsized"] | ||
586 | pub trait CoerceUnsized<T> {} | ||
587 | |||
588 | impl<T: Unsize<U>, U> CoerceUnsized<&U> for &T {} | ||
589 | |||
590 | trait Foo<T, U> {} | ||
591 | trait Bar<U, T, X>: Foo<T, U> {} | ||
592 | trait Baz<T, X>: Bar<usize, T, X> {} | ||
593 | |||
594 | struct S<T, X>; | ||
595 | impl<T, X> Foo<T, usize> for S<T, X> {} | ||
596 | impl<T, X> Bar<usize, T, X> for S<T, X> {} | ||
597 | impl<T, X> Baz<T, X> for S<T, X> {} | ||
598 | |||
599 | fn test() { | ||
600 | let obj: &dyn Baz<i8, i16> = &S; | ||
601 | let obj: &dyn Bar<_, _, _> = obj; | ||
602 | let obj: &dyn Foo<_, _> = obj; | ||
603 | let obj2: &dyn Baz<i8, i16> = &S; | ||
604 | let _: &dyn Foo<_, _> = obj2; | ||
605 | } | ||
606 | "#, true), | ||
607 | @r###" | ||
608 | [388; 573) '{ ...bj2; }': () | ||
609 | [398; 401) 'obj': &dyn Baz<i8, i16> | ||
610 | [423; 425) '&S': &S<i8, i16> | ||
611 | [424; 425) 'S': S<i8, i16> | ||
612 | [435; 438) 'obj': &dyn Bar<usize, i8, i16> | ||
613 | [460; 463) 'obj': &dyn Baz<i8, i16> | ||
614 | [473; 476) 'obj': &dyn Foo<i8, usize> | ||
615 | [495; 498) 'obj': &dyn Bar<usize, i8, i16> | ||
616 | [508; 512) 'obj2': &dyn Baz<i8, i16> | ||
617 | [534; 536) '&S': &S<i8, i16> | ||
618 | [535; 536) 'S': S<i8, i16> | ||
619 | [546; 547) '_': &dyn Foo<i8, usize> | ||
620 | [566; 570) 'obj2': &dyn Baz<i8, i16> | ||
621 | "### | ||
622 | ); | ||
623 | } | ||
624 | |||
625 | #[test] | ||
626 | fn coerce_unsize_super_trait_cycle() { | ||
627 | assert_snapshot!( | ||
628 | infer_with_mismatches(r#" | ||
629 | #[lang = "unsize"] | ||
630 | pub trait Unsize<T> {} | ||
631 | #[lang = "coerce_unsized"] | ||
632 | pub trait CoerceUnsized<T> {} | ||
633 | |||
634 | impl<T: Unsize<U>, U> CoerceUnsized<&U> for &T {} | ||
635 | |||
636 | trait A {} | ||
637 | trait B: C + A {} | ||
638 | trait C: B {} | ||
639 | trait D: C | ||
640 | |||
641 | struct S; | ||
642 | impl A for S {} | ||
643 | impl B for S {} | ||
644 | impl C for S {} | ||
645 | impl D for S {} | ||
646 | |||
647 | fn test() { | ||
648 | let obj: &dyn D = &S; | ||
649 | let obj: &dyn A = obj; | ||
650 | } | ||
651 | "#, true), | ||
652 | @r###" | ||
653 | [292; 348) '{ ...obj; }': () | ||
654 | [302; 305) 'obj': &dyn D | ||
655 | [316; 318) '&S': &S | ||
656 | [317; 318) 'S': S | ||
657 | [328; 331) 'obj': &dyn A | ||
658 | [342; 345) 'obj': &dyn D | ||
659 | "### | ||
660 | ); | ||
661 | } | ||
662 | |||
663 | #[ignore] | ||
664 | #[test] | ||
665 | fn coerce_unsize_generic() { | ||
666 | // FIXME: Implement this | ||
667 | // https://doc.rust-lang.org/reference/type-coercions.html#unsized-coercions | ||
668 | assert_snapshot!( | ||
669 | infer_with_mismatches(r#" | ||
670 | #[lang = "unsize"] | ||
671 | pub trait Unsize<T> {} | ||
672 | #[lang = "coerce_unsized"] | ||
673 | pub trait CoerceUnsized<T> {} | ||
674 | |||
675 | impl<T: Unsize<U>, U> CoerceUnsized<&U> for &T {} | ||
676 | |||
677 | struct Foo<T> { t: T }; | ||
678 | struct Bar<T>(Foo<T>); | ||
679 | |||
680 | fn test() { | ||
681 | let _: &Foo<[usize]> = &Foo { t: [1, 2, 3] }; | ||
682 | let _: &Bar<[usize]> = &Bar(Foo { t: [1, 2, 3] }); | ||
683 | } | ||
684 | "#, true), | ||
685 | @r###" | ||
686 | "### | ||
687 | ); | ||
688 | } | ||
diff --git a/crates/ra_hir_ty/src/traits.rs b/crates/ra_hir_ty/src/traits.rs index e83449957..2317fcac3 100644 --- a/crates/ra_hir_ty/src/traits.rs +++ b/crates/ra_hir_ty/src/traits.rs | |||
@@ -335,6 +335,12 @@ pub struct ClosureFnTraitImplData { | |||
335 | fn_trait: FnTrait, | 335 | fn_trait: FnTrait, |
336 | } | 336 | } |
337 | 337 | ||
338 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
339 | pub struct UnsizeToSuperTraitObjectData { | ||
340 | trait_: TraitId, | ||
341 | super_trait: TraitId, | ||
342 | } | ||
343 | |||
338 | /// An impl. Usually this comes from an impl block, but some built-in types get | 344 | /// An impl. Usually this comes from an impl block, but some built-in types get |
339 | /// synthetic impls. | 345 | /// synthetic impls. |
340 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 346 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
@@ -343,6 +349,12 @@ pub enum Impl { | |||
343 | ImplBlock(ImplId), | 349 | ImplBlock(ImplId), |
344 | /// Closure types implement the Fn traits synthetically. | 350 | /// Closure types implement the Fn traits synthetically. |
345 | ClosureFnTraitImpl(ClosureFnTraitImplData), | 351 | ClosureFnTraitImpl(ClosureFnTraitImplData), |
352 | /// [T; n]: Unsize<[T]> | ||
353 | UnsizeArray, | ||
354 | /// T: Unsize<dyn Trait> where T: Trait | ||
355 | UnsizeToTraitObject(TraitId), | ||
356 | /// dyn Trait: Unsize<dyn SuperTrait> if Trait: SuperTrait | ||
357 | UnsizeToSuperTraitObject(UnsizeToSuperTraitObjectData), | ||
346 | } | 358 | } |
347 | /// This exists just for Chalk, because our ImplIds are only unique per module. | 359 | /// This exists just for Chalk, because our ImplIds are only unique per module. |
348 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 360 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
diff --git a/crates/ra_hir_ty/src/traits/builtin.rs b/crates/ra_hir_ty/src/traits/builtin.rs index a537420a5..cc0f3eeb4 100644 --- a/crates/ra_hir_ty/src/traits/builtin.rs +++ b/crates/ra_hir_ty/src/traits/builtin.rs | |||
@@ -4,8 +4,12 @@ use hir_def::{expr::Expr, lang_item::LangItemTarget, TraitId, TypeAliasId}; | |||
4 | use hir_expand::name::name; | 4 | use hir_expand::name::name; |
5 | use ra_db::CrateId; | 5 | use ra_db::CrateId; |
6 | 6 | ||
7 | use super::{AssocTyValue, Impl}; | 7 | use super::{AssocTyValue, Impl, UnsizeToSuperTraitObjectData}; |
8 | use crate::{db::HirDatabase, ApplicationTy, Substs, TraitRef, Ty, TypeCtor}; | 8 | use crate::{ |
9 | db::HirDatabase, | ||
10 | utils::{all_super_traits, generics}, | ||
11 | ApplicationTy, Binders, GenericPredicate, Substs, TraitRef, Ty, TypeCtor, | ||
12 | }; | ||
9 | 13 | ||
10 | pub(super) struct BuiltinImplData { | 14 | pub(super) struct BuiltinImplData { |
11 | pub num_vars: usize, | 15 | pub num_vars: usize, |
@@ -25,6 +29,8 @@ pub(super) fn get_builtin_impls( | |||
25 | db: &impl HirDatabase, | 29 | db: &impl HirDatabase, |
26 | krate: CrateId, | 30 | krate: CrateId, |
27 | ty: &Ty, | 31 | ty: &Ty, |
32 | // The first argument for the trait, if present | ||
33 | arg: &Option<Ty>, | ||
28 | trait_: TraitId, | 34 | trait_: TraitId, |
29 | mut callback: impl FnMut(Impl), | 35 | mut callback: impl FnMut(Impl), |
30 | ) { | 36 | ) { |
@@ -43,12 +49,60 @@ pub(super) fn get_builtin_impls( | |||
43 | } | 49 | } |
44 | } | 50 | } |
45 | } | 51 | } |
52 | |||
53 | let unsize_trait = get_unsize_trait(db, krate); | ||
54 | if let Some(actual_trait) = unsize_trait { | ||
55 | if trait_ == actual_trait { | ||
56 | get_builtin_unsize_impls(db, krate, ty, arg, callback); | ||
57 | } | ||
58 | } | ||
59 | } | ||
60 | |||
61 | fn get_builtin_unsize_impls( | ||
62 | db: &impl HirDatabase, | ||
63 | krate: CrateId, | ||
64 | ty: &Ty, | ||
65 | // The first argument for the trait, if present | ||
66 | arg: &Option<Ty>, | ||
67 | mut callback: impl FnMut(Impl), | ||
68 | ) { | ||
69 | if !check_unsize_impl_prerequisites(db, krate) { | ||
70 | return; | ||
71 | } | ||
72 | |||
73 | if let Ty::Apply(ApplicationTy { ctor: TypeCtor::Array, .. }) = ty { | ||
74 | callback(Impl::UnsizeArray); | ||
75 | return; // array is unsized, the rest of the impls shouldn't apply | ||
76 | } | ||
77 | |||
78 | if let Some(target_trait) = arg.as_ref().and_then(|t| t.dyn_trait_ref()) { | ||
79 | // FIXME what about more complicated dyn tys with marker traits? | ||
80 | if let Some(trait_ref) = ty.dyn_trait_ref() { | ||
81 | if trait_ref.trait_ != target_trait.trait_ { | ||
82 | let super_traits = all_super_traits(db, trait_ref.trait_); | ||
83 | if super_traits.contains(&target_trait.trait_) { | ||
84 | callback(Impl::UnsizeToSuperTraitObject(UnsizeToSuperTraitObjectData { | ||
85 | trait_: trait_ref.trait_, | ||
86 | super_trait: target_trait.trait_, | ||
87 | })); | ||
88 | } | ||
89 | } | ||
90 | } else { | ||
91 | // FIXME only for sized types | ||
92 | callback(Impl::UnsizeToTraitObject(target_trait.trait_)); | ||
93 | } | ||
94 | } | ||
46 | } | 95 | } |
47 | 96 | ||
48 | pub(super) fn impl_datum(db: &impl HirDatabase, krate: CrateId, impl_: Impl) -> BuiltinImplData { | 97 | pub(super) fn impl_datum(db: &impl HirDatabase, krate: CrateId, impl_: Impl) -> BuiltinImplData { |
49 | match impl_ { | 98 | match impl_ { |
50 | Impl::ImplBlock(_) => unreachable!(), | 99 | Impl::ImplBlock(_) => unreachable!(), |
51 | Impl::ClosureFnTraitImpl(data) => closure_fn_trait_impl_datum(db, krate, data), | 100 | Impl::ClosureFnTraitImpl(data) => closure_fn_trait_impl_datum(db, krate, data), |
101 | Impl::UnsizeArray => array_unsize_impl_datum(db, krate), | ||
102 | Impl::UnsizeToTraitObject(trait_) => trait_object_unsize_impl_datum(db, krate, trait_), | ||
103 | Impl::UnsizeToSuperTraitObject(data) => { | ||
104 | super_trait_object_unsize_impl_datum(db, krate, data) | ||
105 | } | ||
52 | } | 106 | } |
53 | } | 107 | } |
54 | 108 | ||
@@ -65,6 +119,8 @@ pub(super) fn associated_ty_value( | |||
65 | } | 119 | } |
66 | } | 120 | } |
67 | 121 | ||
122 | // Closure Fn trait impls | ||
123 | |||
68 | fn check_closure_fn_trait_impl_prerequisites( | 124 | fn check_closure_fn_trait_impl_prerequisites( |
69 | db: &impl HirDatabase, | 125 | db: &impl HirDatabase, |
70 | krate: CrateId, | 126 | krate: CrateId, |
@@ -165,6 +221,129 @@ fn closure_fn_trait_output_assoc_ty_value( | |||
165 | } | 221 | } |
166 | } | 222 | } |
167 | 223 | ||
224 | // Array unsizing | ||
225 | |||
226 | fn check_unsize_impl_prerequisites(db: &impl HirDatabase, krate: CrateId) -> bool { | ||
227 | // the Unsize trait needs to exist and have two type parameters (Self and T) | ||
228 | let unsize_trait = match get_unsize_trait(db, krate) { | ||
229 | Some(t) => t, | ||
230 | None => return false, | ||
231 | }; | ||
232 | let generic_params = generics(db, unsize_trait.into()); | ||
233 | generic_params.len() == 2 | ||
234 | } | ||
235 | |||
236 | fn array_unsize_impl_datum(db: &impl HirDatabase, krate: CrateId) -> BuiltinImplData { | ||
237 | // impl<T> Unsize<[T]> for [T; _] | ||
238 | // (this can be a single impl because we don't distinguish array sizes currently) | ||
239 | |||
240 | let trait_ = get_unsize_trait(db, krate) // get unsize trait | ||
241 | // the existence of the Unsize trait has been checked before | ||
242 | .expect("Unsize trait missing"); | ||
243 | |||
244 | let var = Ty::Bound(0); | ||
245 | let substs = Substs::builder(2) | ||
246 | .push(Ty::apply_one(TypeCtor::Array, var.clone())) | ||
247 | .push(Ty::apply_one(TypeCtor::Slice, var)) | ||
248 | .build(); | ||
249 | |||
250 | let trait_ref = TraitRef { trait_, substs }; | ||
251 | |||
252 | BuiltinImplData { | ||
253 | num_vars: 1, | ||
254 | trait_ref, | ||
255 | where_clauses: Vec::new(), | ||
256 | assoc_ty_values: Vec::new(), | ||
257 | } | ||
258 | } | ||
259 | |||
260 | // Trait object unsizing | ||
261 | |||
262 | fn trait_object_unsize_impl_datum( | ||
263 | db: &impl HirDatabase, | ||
264 | krate: CrateId, | ||
265 | trait_: TraitId, | ||
266 | ) -> BuiltinImplData { | ||
267 | // impl<T, T1, ...> Unsize<dyn Trait<T1, ...>> for T where T: Trait<T1, ...> | ||
268 | |||
269 | let unsize_trait = get_unsize_trait(db, krate) // get unsize trait | ||
270 | // the existence of the Unsize trait has been checked before | ||
271 | .expect("Unsize trait missing"); | ||
272 | |||
273 | let self_ty = Ty::Bound(0); | ||
274 | |||
275 | let target_substs = Substs::build_for_def(db, trait_) | ||
276 | .push(Ty::Bound(0)) | ||
277 | // starting from ^2 because we want to start with ^1 outside of the | ||
278 | // `dyn`, which is ^2 inside | ||
279 | .fill_with_bound_vars(2) | ||
280 | .build(); | ||
281 | let num_vars = target_substs.len(); | ||
282 | let target_trait_ref = TraitRef { trait_, substs: target_substs }; | ||
283 | let target_bounds = vec![GenericPredicate::Implemented(target_trait_ref)]; | ||
284 | |||
285 | let self_substs = Substs::build_for_def(db, trait_).fill_with_bound_vars(0).build(); | ||
286 | let self_trait_ref = TraitRef { trait_, substs: self_substs }; | ||
287 | let where_clauses = vec![GenericPredicate::Implemented(self_trait_ref)]; | ||
288 | |||
289 | let impl_substs = | ||
290 | Substs::builder(2).push(self_ty).push(Ty::Dyn(target_bounds.clone().into())).build(); | ||
291 | |||
292 | let trait_ref = TraitRef { trait_: unsize_trait, substs: impl_substs }; | ||
293 | |||
294 | BuiltinImplData { num_vars, trait_ref, where_clauses, assoc_ty_values: Vec::new() } | ||
295 | } | ||
296 | |||
297 | fn super_trait_object_unsize_impl_datum( | ||
298 | db: &impl HirDatabase, | ||
299 | krate: CrateId, | ||
300 | data: UnsizeToSuperTraitObjectData, | ||
301 | ) -> BuiltinImplData { | ||
302 | // impl<T1, ...> Unsize<dyn SuperTrait> for dyn Trait<T1, ...> | ||
303 | |||
304 | let unsize_trait = get_unsize_trait(db, krate) // get unsize trait | ||
305 | // the existence of the Unsize trait has been checked before | ||
306 | .expect("Unsize trait missing"); | ||
307 | |||
308 | let self_substs = Substs::build_for_def(db, data.trait_).fill_with_bound_vars(0).build(); | ||
309 | |||
310 | let num_vars = self_substs.len() - 1; | ||
311 | |||
312 | let self_trait_ref = TraitRef { trait_: data.trait_, substs: self_substs.clone() }; | ||
313 | let self_bounds = vec![GenericPredicate::Implemented(self_trait_ref.clone())]; | ||
314 | |||
315 | // we need to go from our trait to the super trait, substituting type parameters | ||
316 | let path = crate::utils::find_super_trait_path(db, data.trait_, data.super_trait); | ||
317 | |||
318 | let mut current_trait_ref = self_trait_ref; | ||
319 | for t in path.into_iter().skip(1) { | ||
320 | let bounds = db.generic_predicates(current_trait_ref.trait_.into()); | ||
321 | let super_trait_ref = bounds | ||
322 | .iter() | ||
323 | .find_map(|b| match &b.value { | ||
324 | GenericPredicate::Implemented(tr) | ||
325 | if tr.trait_ == t && tr.substs[0] == Ty::Bound(0) => | ||
326 | { | ||
327 | Some(Binders { value: tr, num_binders: b.num_binders }) | ||
328 | } | ||
329 | _ => None, | ||
330 | }) | ||
331 | .expect("trait bound for known super trait not found"); | ||
332 | current_trait_ref = super_trait_ref.cloned().subst(¤t_trait_ref.substs); | ||
333 | } | ||
334 | |||
335 | let super_bounds = vec![GenericPredicate::Implemented(current_trait_ref)]; | ||
336 | |||
337 | let substs = Substs::builder(2) | ||
338 | .push(Ty::Dyn(self_bounds.into())) | ||
339 | .push(Ty::Dyn(super_bounds.into())) | ||
340 | .build(); | ||
341 | |||
342 | let trait_ref = TraitRef { trait_: unsize_trait, substs }; | ||
343 | |||
344 | BuiltinImplData { num_vars, trait_ref, where_clauses: Vec::new(), assoc_ty_values: Vec::new() } | ||
345 | } | ||
346 | |||
168 | fn get_fn_trait( | 347 | fn get_fn_trait( |
169 | db: &impl HirDatabase, | 348 | db: &impl HirDatabase, |
170 | krate: CrateId, | 349 | krate: CrateId, |
@@ -176,3 +355,11 @@ fn get_fn_trait( | |||
176 | _ => None, | 355 | _ => None, |
177 | } | 356 | } |
178 | } | 357 | } |
358 | |||
359 | fn get_unsize_trait(db: &impl HirDatabase, krate: CrateId) -> Option<TraitId> { | ||
360 | let target = db.lang_item(krate, "unsize".into())?; | ||
361 | match target { | ||
362 | LangItemTarget::TraitId(t) => Some(t), | ||
363 | _ => None, | ||
364 | } | ||
365 | } | ||
diff --git a/crates/ra_hir_ty/src/traits/chalk.rs b/crates/ra_hir_ty/src/traits/chalk.rs index 1bdf13e48..e1e430aeb 100644 --- a/crates/ra_hir_ty/src/traits/chalk.rs +++ b/crates/ra_hir_ty/src/traits/chalk.rs | |||
@@ -572,8 +572,10 @@ where | |||
572 | .collect(); | 572 | .collect(); |
573 | 573 | ||
574 | let ty: Ty = from_chalk(self.db, parameters[0].assert_ty_ref().clone()); | 574 | let ty: Ty = from_chalk(self.db, parameters[0].assert_ty_ref().clone()); |
575 | let arg: Option<Ty> = | ||
576 | parameters.get(1).map(|p| from_chalk(self.db, p.assert_ty_ref().clone())); | ||
575 | 577 | ||
576 | builtin::get_builtin_impls(self.db, self.krate, &ty, trait_, |i| { | 578 | builtin::get_builtin_impls(self.db, self.krate, &ty, &arg, trait_, |i| { |
577 | result.push(i.to_chalk(self.db)) | 579 | result.push(i.to_chalk(self.db)) |
578 | }); | 580 | }); |
579 | 581 | ||
diff --git a/crates/ra_hir_ty/src/utils.rs b/crates/ra_hir_ty/src/utils.rs index 508ae9046..463fd65b4 100644 --- a/crates/ra_hir_ty/src/utils.rs +++ b/crates/ra_hir_ty/src/utils.rs | |||
@@ -62,6 +62,38 @@ pub(super) fn all_super_traits(db: &impl DefDatabase, trait_: TraitId) -> Vec<Tr | |||
62 | result | 62 | result |
63 | } | 63 | } |
64 | 64 | ||
65 | /// Finds a path from a trait to one of its super traits. Returns an empty | ||
66 | /// vector if there is no path. | ||
67 | pub(super) fn find_super_trait_path( | ||
68 | db: &impl DefDatabase, | ||
69 | trait_: TraitId, | ||
70 | super_trait: TraitId, | ||
71 | ) -> Vec<TraitId> { | ||
72 | let mut result = Vec::with_capacity(2); | ||
73 | result.push(trait_); | ||
74 | return if go(db, super_trait, &mut result) { result } else { Vec::new() }; | ||
75 | |||
76 | fn go(db: &impl DefDatabase, super_trait: TraitId, path: &mut Vec<TraitId>) -> bool { | ||
77 | let trait_ = *path.last().unwrap(); | ||
78 | if trait_ == super_trait { | ||
79 | return true; | ||
80 | } | ||
81 | |||
82 | for tt in direct_super_traits(db, trait_) { | ||
83 | if path.contains(&tt) { | ||
84 | continue; | ||
85 | } | ||
86 | path.push(tt); | ||
87 | if go(db, super_trait, path) { | ||
88 | return true; | ||
89 | } else { | ||
90 | path.pop(); | ||
91 | } | ||
92 | } | ||
93 | false | ||
94 | } | ||
95 | } | ||
96 | |||
65 | pub(super) fn associated_type_by_name_including_super_traits( | 97 | pub(super) fn associated_type_by_name_including_super_traits( |
66 | db: &impl DefDatabase, | 98 | db: &impl DefDatabase, |
67 | trait_: TraitId, | 99 | trait_: TraitId, |
diff --git a/crates/ra_ide/src/completion/complete_path.rs b/crates/ra_ide/src/completion/complete_path.rs index af24e9f48..2d7f09a6c 100644 --- a/crates/ra_ide/src/completion/complete_path.rs +++ b/crates/ra_ide/src/completion/complete_path.rs | |||
@@ -1,4 +1,4 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! Completion of paths, including when writing a single name. |
2 | 2 | ||
3 | use hir::{Adt, PathResolution, ScopeDef}; | 3 | use hir::{Adt, PathResolution, ScopeDef}; |
4 | use ra_syntax::AstNode; | 4 | use ra_syntax::AstNode; |
@@ -20,10 +20,6 @@ pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) { | |||
20 | let module_scope = module.scope(ctx.db); | 20 | let module_scope = module.scope(ctx.db); |
21 | for (name, def) in module_scope { | 21 | for (name, def) in module_scope { |
22 | if ctx.use_item_syntax.is_some() { | 22 | if ctx.use_item_syntax.is_some() { |
23 | if let hir::ScopeDef::ModuleDef(hir::ModuleDef::BuiltinType(..)) = def { | ||
24 | tested_by!(dont_complete_primitive_in_use); | ||
25 | continue; | ||
26 | } | ||
27 | if let ScopeDef::Unknown = def { | 23 | if let ScopeDef::Unknown = def { |
28 | if let Some(name_ref) = ctx.name_ref_syntax.as_ref() { | 24 | if let Some(name_ref) = ctx.name_ref_syntax.as_ref() { |
29 | if name_ref.syntax().text() == name.to_string().as_str() { | 25 | if name_ref.syntax().text() == name.to_string().as_str() { |
@@ -125,12 +121,17 @@ mod tests { | |||
125 | 121 | ||
126 | #[test] | 122 | #[test] |
127 | fn dont_complete_primitive_in_use() { | 123 | fn dont_complete_primitive_in_use() { |
128 | covers!(dont_complete_primitive_in_use); | ||
129 | let completions = do_completion(r"use self::<|>;", CompletionKind::BuiltinType); | 124 | let completions = do_completion(r"use self::<|>;", CompletionKind::BuiltinType); |
130 | assert!(completions.is_empty()); | 125 | assert!(completions.is_empty()); |
131 | } | 126 | } |
132 | 127 | ||
133 | #[test] | 128 | #[test] |
129 | fn dont_complete_primitive_in_module_scope() { | ||
130 | let completions = do_completion(r"fn foo() { self::<|> }", CompletionKind::BuiltinType); | ||
131 | assert!(completions.is_empty()); | ||
132 | } | ||
133 | |||
134 | #[test] | ||
134 | fn completes_primitives() { | 135 | fn completes_primitives() { |
135 | let completions = | 136 | let completions = |
136 | do_completion(r"fn main() { let _: <|> = 92; }", CompletionKind::BuiltinType); | 137 | do_completion(r"fn main() { let _: <|> = 92; }", CompletionKind::BuiltinType); |
diff --git a/crates/ra_ide/src/marks.rs b/crates/ra_ide/src/marks.rs index 5bf4d2062..bcb67e373 100644 --- a/crates/ra_ide/src/marks.rs +++ b/crates/ra_ide/src/marks.rs | |||
@@ -10,6 +10,5 @@ test_utils::marks!( | |||
10 | goto_def_for_field_init_shorthand | 10 | goto_def_for_field_init_shorthand |
11 | call_info_bad_offset | 11 | call_info_bad_offset |
12 | dont_complete_current_use | 12 | dont_complete_current_use |
13 | dont_complete_primitive_in_use | ||
14 | test_resolve_parent_module_on_module_decl | 13 | test_resolve_parent_module_on_module_decl |
15 | ); | 14 | ); |
diff --git a/crates/ra_mbe/src/subtree_source.rs b/crates/ra_mbe/src/subtree_source.rs index dacca8279..91e324db9 100644 --- a/crates/ra_mbe/src/subtree_source.rs +++ b/crates/ra_mbe/src/subtree_source.rs | |||
@@ -1,7 +1,7 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | 2 | ||
3 | use ra_parser::{Token, TokenSource}; | 3 | use ra_parser::{Token, TokenSource}; |
4 | use ra_syntax::{lex_single_valid_syntax_kind, SmolStr, SyntaxKind, SyntaxKind::*, T}; | 4 | use ra_syntax::{lex_single_syntax_kind, SmolStr, SyntaxKind, SyntaxKind::*, T}; |
5 | use std::cell::{Cell, Ref, RefCell}; | 5 | use std::cell::{Cell, Ref, RefCell}; |
6 | use tt::buffer::{Cursor, TokenBuffer}; | 6 | use tt::buffer::{Cursor, TokenBuffer}; |
7 | 7 | ||
@@ -129,7 +129,8 @@ fn convert_delim(d: Option<tt::DelimiterKind>, closing: bool) -> TtToken { | |||
129 | } | 129 | } |
130 | 130 | ||
131 | fn convert_literal(l: &tt::Literal) -> TtToken { | 131 | fn convert_literal(l: &tt::Literal) -> TtToken { |
132 | let kind = lex_single_valid_syntax_kind(&l.text) | 132 | let kind = lex_single_syntax_kind(&l.text) |
133 | .map(|(kind, _error)| kind) | ||
133 | .filter(|kind| kind.is_literal()) | 134 | .filter(|kind| kind.is_literal()) |
134 | .unwrap_or_else(|| match l.text.as_ref() { | 135 | .unwrap_or_else(|| match l.text.as_ref() { |
135 | "true" => T![true], | 136 | "true" => T![true], |
diff --git a/crates/ra_mbe/src/tests.rs b/crates/ra_mbe/src/tests.rs index e0d689704..cb228702f 100644 --- a/crates/ra_mbe/src/tests.rs +++ b/crates/ra_mbe/src/tests.rs | |||
@@ -1374,14 +1374,22 @@ pub(crate) struct MacroFixture { | |||
1374 | 1374 | ||
1375 | impl MacroFixture { | 1375 | impl MacroFixture { |
1376 | pub(crate) fn expand_tt(&self, invocation: &str) -> tt::Subtree { | 1376 | pub(crate) fn expand_tt(&self, invocation: &str) -> tt::Subtree { |
1377 | let source_file = ast::SourceFile::parse(invocation).ok().unwrap(); | 1377 | self.try_expand_tt(invocation).unwrap() |
1378 | } | ||
1379 | |||
1380 | fn try_expand_tt(&self, invocation: &str) -> Result<tt::Subtree, ExpandError> { | ||
1381 | let source_file = ast::SourceFile::parse(invocation).tree(); | ||
1378 | let macro_invocation = | 1382 | let macro_invocation = |
1379 | source_file.syntax().descendants().find_map(ast::MacroCall::cast).unwrap(); | 1383 | source_file.syntax().descendants().find_map(ast::MacroCall::cast).unwrap(); |
1380 | 1384 | ||
1381 | let (invocation_tt, _) = | 1385 | let (invocation_tt, _) = |
1382 | ast_to_token_tree(¯o_invocation.token_tree().unwrap()).unwrap(); | 1386 | ast_to_token_tree(¯o_invocation.token_tree().unwrap()).unwrap(); |
1383 | 1387 | ||
1384 | self.rules.expand(&invocation_tt).unwrap() | 1388 | self.rules.expand(&invocation_tt) |
1389 | } | ||
1390 | |||
1391 | fn assert_expand_err(&self, invocation: &str, err: &ExpandError) { | ||
1392 | assert_eq!(self.try_expand_tt(invocation).as_ref(), Err(err)); | ||
1385 | } | 1393 | } |
1386 | 1394 | ||
1387 | fn expand_items(&self, invocation: &str) -> SyntaxNode { | 1395 | fn expand_items(&self, invocation: &str) -> SyntaxNode { |
@@ -1539,3 +1547,13 @@ fn test_repeat_bad_var() { | |||
1539 | ) | 1547 | ) |
1540 | .assert_expand_items("foo!(b0 b1);", "b0 b1"); | 1548 | .assert_expand_items("foo!(b0 b1);", "b0 b1"); |
1541 | } | 1549 | } |
1550 | |||
1551 | #[test] | ||
1552 | fn test_expand_bad_literal() { | ||
1553 | parse_macro( | ||
1554 | r#" | ||
1555 | macro_rules! foo { ($i:literal) => {}; } | ||
1556 | "#, | ||
1557 | ) | ||
1558 | .assert_expand_err(r#"foo!(&k");"#, &ExpandError::NoMatchingRule); | ||
1559 | } | ||
diff --git a/crates/ra_parser/src/parser.rs b/crates/ra_parser/src/parser.rs index 76e2d4f7d..faa63d53f 100644 --- a/crates/ra_parser/src/parser.rs +++ b/crates/ra_parser/src/parser.rs | |||
@@ -164,7 +164,7 @@ impl<'t> Parser<'t> { | |||
164 | assert!(self.eat(kind)); | 164 | assert!(self.eat(kind)); |
165 | } | 165 | } |
166 | 166 | ||
167 | /// Advances the parser by one token with composite puncts handled | 167 | /// Advances the parser by one token |
168 | pub(crate) fn bump_any(&mut self) { | 168 | pub(crate) fn bump_any(&mut self) { |
169 | let kind = self.nth(0); | 169 | let kind = self.nth(0); |
170 | if kind == EOF { | 170 | if kind == EOF { |