diff options
Diffstat (limited to 'crates/ra_hir_ty')
-rw-r--r-- | crates/ra_hir_ty/src/display.rs | 373 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/infer/unify.rs | 2 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/lib.rs | 383 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/lower.rs | 40 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/marks.rs | 2 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/method_resolution.rs | 9 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/tests/coercion.rs | 22 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/tests/method_resolution.rs | 32 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/tests/traits.rs | 48 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/traits.rs | 3 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/traits/chalk.rs | 4 |
11 files changed, 532 insertions, 386 deletions
diff --git a/crates/ra_hir_ty/src/display.rs b/crates/ra_hir_ty/src/display.rs index d1ff85f0f..14e089cf4 100644 --- a/crates/ra_hir_ty/src/display.rs +++ b/crates/ra_hir_ty/src/display.rs | |||
@@ -2,7 +2,12 @@ | |||
2 | 2 | ||
3 | use std::fmt; | 3 | use std::fmt; |
4 | 4 | ||
5 | use crate::db::HirDatabase; | 5 | use crate::{ |
6 | db::HirDatabase, utils::generics, ApplicationTy, CallableDef, FnSig, GenericPredicate, | ||
7 | Obligation, ProjectionTy, Substs, TraitRef, Ty, TypeCtor, | ||
8 | }; | ||
9 | use hir_def::{generics::TypeParamProvenance, AdtId, AssocContainerId, Lookup}; | ||
10 | use hir_expand::name::Name; | ||
6 | 11 | ||
7 | pub struct HirFormatter<'a, 'b, DB> { | 12 | pub struct HirFormatter<'a, 'b, DB> { |
8 | pub db: &'a DB, | 13 | pub db: &'a DB, |
@@ -97,3 +102,369 @@ where | |||
97 | }) | 102 | }) |
98 | } | 103 | } |
99 | } | 104 | } |
105 | |||
106 | const TYPE_HINT_TRUNCATION: &str = "…"; | ||
107 | |||
108 | impl HirDisplay for &Ty { | ||
109 | fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result { | ||
110 | HirDisplay::hir_fmt(*self, f) | ||
111 | } | ||
112 | } | ||
113 | |||
114 | impl HirDisplay for ApplicationTy { | ||
115 | fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result { | ||
116 | if f.should_truncate() { | ||
117 | return write!(f, "{}", TYPE_HINT_TRUNCATION); | ||
118 | } | ||
119 | |||
120 | match self.ctor { | ||
121 | TypeCtor::Bool => write!(f, "bool")?, | ||
122 | TypeCtor::Char => write!(f, "char")?, | ||
123 | TypeCtor::Int(t) => write!(f, "{}", t)?, | ||
124 | TypeCtor::Float(t) => write!(f, "{}", t)?, | ||
125 | TypeCtor::Str => write!(f, "str")?, | ||
126 | TypeCtor::Slice => { | ||
127 | let t = self.parameters.as_single(); | ||
128 | write!(f, "[{}]", t.display(f.db))?; | ||
129 | } | ||
130 | TypeCtor::Array => { | ||
131 | let t = self.parameters.as_single(); | ||
132 | write!(f, "[{}; _]", t.display(f.db))?; | ||
133 | } | ||
134 | TypeCtor::RawPtr(m) => { | ||
135 | let t = self.parameters.as_single(); | ||
136 | write!(f, "*{}{}", m.as_keyword_for_ptr(), t.display(f.db))?; | ||
137 | } | ||
138 | TypeCtor::Ref(m) => { | ||
139 | let t = self.parameters.as_single(); | ||
140 | let ty_display = if f.omit_verbose_types() { | ||
141 | t.display_truncated(f.db, f.max_size) | ||
142 | } else { | ||
143 | t.display(f.db) | ||
144 | }; | ||
145 | write!(f, "&{}{}", m.as_keyword_for_ref(), ty_display)?; | ||
146 | } | ||
147 | TypeCtor::Never => write!(f, "!")?, | ||
148 | TypeCtor::Tuple { .. } => { | ||
149 | let ts = &self.parameters; | ||
150 | if ts.len() == 1 { | ||
151 | write!(f, "({},)", ts[0].display(f.db))?; | ||
152 | } else { | ||
153 | write!(f, "(")?; | ||
154 | f.write_joined(&*ts.0, ", ")?; | ||
155 | write!(f, ")")?; | ||
156 | } | ||
157 | } | ||
158 | TypeCtor::FnPtr { .. } => { | ||
159 | let sig = FnSig::from_fn_ptr_substs(&self.parameters); | ||
160 | write!(f, "fn(")?; | ||
161 | f.write_joined(sig.params(), ", ")?; | ||
162 | write!(f, ") -> {}", sig.ret().display(f.db))?; | ||
163 | } | ||
164 | TypeCtor::FnDef(def) => { | ||
165 | let sig = f.db.callable_item_signature(def).subst(&self.parameters); | ||
166 | let name = match def { | ||
167 | CallableDef::FunctionId(ff) => f.db.function_data(ff).name.clone(), | ||
168 | CallableDef::StructId(s) => f.db.struct_data(s).name.clone(), | ||
169 | CallableDef::EnumVariantId(e) => { | ||
170 | let enum_data = f.db.enum_data(e.parent); | ||
171 | enum_data.variants[e.local_id].name.clone() | ||
172 | } | ||
173 | }; | ||
174 | match def { | ||
175 | CallableDef::FunctionId(_) => write!(f, "fn {}", name)?, | ||
176 | CallableDef::StructId(_) | CallableDef::EnumVariantId(_) => { | ||
177 | write!(f, "{}", name)? | ||
178 | } | ||
179 | } | ||
180 | if self.parameters.len() > 0 { | ||
181 | let generics = generics(f.db, def.into()); | ||
182 | let (parent_params, self_param, type_params, _impl_trait_params) = | ||
183 | generics.provenance_split(); | ||
184 | let total_len = parent_params + self_param + type_params; | ||
185 | // We print all params except implicit impl Trait params. Still a bit weird; should we leave out parent and self? | ||
186 | if total_len > 0 { | ||
187 | write!(f, "<")?; | ||
188 | f.write_joined(&self.parameters.0[..total_len], ", ")?; | ||
189 | write!(f, ">")?; | ||
190 | } | ||
191 | } | ||
192 | write!(f, "(")?; | ||
193 | f.write_joined(sig.params(), ", ")?; | ||
194 | write!(f, ") -> {}", sig.ret().display(f.db))?; | ||
195 | } | ||
196 | TypeCtor::Adt(def_id) => { | ||
197 | let name = match def_id { | ||
198 | AdtId::StructId(it) => f.db.struct_data(it).name.clone(), | ||
199 | AdtId::UnionId(it) => f.db.union_data(it).name.clone(), | ||
200 | AdtId::EnumId(it) => f.db.enum_data(it).name.clone(), | ||
201 | }; | ||
202 | write!(f, "{}", name)?; | ||
203 | if self.parameters.len() > 0 { | ||
204 | write!(f, "<")?; | ||
205 | |||
206 | let mut non_default_parameters = Vec::with_capacity(self.parameters.len()); | ||
207 | let parameters_to_write = if f.omit_verbose_types() { | ||
208 | match self | ||
209 | .ctor | ||
210 | .as_generic_def() | ||
211 | .map(|generic_def_id| f.db.generic_defaults(generic_def_id)) | ||
212 | .filter(|defaults| !defaults.is_empty()) | ||
213 | { | ||
214 | Option::None => self.parameters.0.as_ref(), | ||
215 | Option::Some(default_parameters) => { | ||
216 | for (i, parameter) in self.parameters.iter().enumerate() { | ||
217 | match (parameter, default_parameters.get(i)) { | ||
218 | (&Ty::Unknown, _) | (_, None) => { | ||
219 | non_default_parameters.push(parameter.clone()) | ||
220 | } | ||
221 | (_, Some(default_parameter)) | ||
222 | if parameter != default_parameter => | ||
223 | { | ||
224 | non_default_parameters.push(parameter.clone()) | ||
225 | } | ||
226 | _ => (), | ||
227 | } | ||
228 | } | ||
229 | &non_default_parameters | ||
230 | } | ||
231 | } | ||
232 | } else { | ||
233 | self.parameters.0.as_ref() | ||
234 | }; | ||
235 | |||
236 | f.write_joined(parameters_to_write, ", ")?; | ||
237 | write!(f, ">")?; | ||
238 | } | ||
239 | } | ||
240 | TypeCtor::AssociatedType(type_alias) => { | ||
241 | let trait_ = match type_alias.lookup(f.db).container { | ||
242 | AssocContainerId::TraitId(it) => it, | ||
243 | _ => panic!("not an associated type"), | ||
244 | }; | ||
245 | let trait_name = f.db.trait_data(trait_).name.clone(); | ||
246 | let name = f.db.type_alias_data(type_alias).name.clone(); | ||
247 | write!(f, "{}::{}", trait_name, name)?; | ||
248 | if self.parameters.len() > 0 { | ||
249 | write!(f, "<")?; | ||
250 | f.write_joined(&*self.parameters.0, ", ")?; | ||
251 | write!(f, ">")?; | ||
252 | } | ||
253 | } | ||
254 | TypeCtor::Closure { .. } => { | ||
255 | let sig = self.parameters[0] | ||
256 | .callable_sig(f.db) | ||
257 | .expect("first closure parameter should contain signature"); | ||
258 | let return_type_hint = sig.ret().display(f.db); | ||
259 | if sig.params().is_empty() { | ||
260 | write!(f, "|| -> {}", return_type_hint)?; | ||
261 | } else if f.omit_verbose_types() { | ||
262 | write!(f, "|{}| -> {}", TYPE_HINT_TRUNCATION, return_type_hint)?; | ||
263 | } else { | ||
264 | write!(f, "|")?; | ||
265 | f.write_joined(sig.params(), ", ")?; | ||
266 | write!(f, "| -> {}", return_type_hint)?; | ||
267 | }; | ||
268 | } | ||
269 | } | ||
270 | Ok(()) | ||
271 | } | ||
272 | } | ||
273 | |||
274 | impl HirDisplay for ProjectionTy { | ||
275 | fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result { | ||
276 | if f.should_truncate() { | ||
277 | return write!(f, "{}", TYPE_HINT_TRUNCATION); | ||
278 | } | ||
279 | |||
280 | let trait_name = f.db.trait_data(self.trait_(f.db)).name.clone(); | ||
281 | write!(f, "<{} as {}", self.parameters[0].display(f.db), trait_name,)?; | ||
282 | if self.parameters.len() > 1 { | ||
283 | write!(f, "<")?; | ||
284 | f.write_joined(&self.parameters[1..], ", ")?; | ||
285 | write!(f, ">")?; | ||
286 | } | ||
287 | write!(f, ">::{}", f.db.type_alias_data(self.associated_ty).name)?; | ||
288 | Ok(()) | ||
289 | } | ||
290 | } | ||
291 | |||
292 | impl HirDisplay for Ty { | ||
293 | fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result { | ||
294 | if f.should_truncate() { | ||
295 | return write!(f, "{}", TYPE_HINT_TRUNCATION); | ||
296 | } | ||
297 | |||
298 | match self { | ||
299 | Ty::Apply(a_ty) => a_ty.hir_fmt(f)?, | ||
300 | Ty::Projection(p_ty) => p_ty.hir_fmt(f)?, | ||
301 | Ty::Placeholder(id) => { | ||
302 | let generics = generics(f.db, id.parent); | ||
303 | let param_data = &generics.params.types[id.local_id]; | ||
304 | match param_data.provenance { | ||
305 | TypeParamProvenance::TypeParamList | TypeParamProvenance::TraitSelf => { | ||
306 | write!(f, "{}", param_data.name.clone().unwrap_or_else(Name::missing))? | ||
307 | } | ||
308 | TypeParamProvenance::ArgumentImplTrait => { | ||
309 | write!(f, "impl ")?; | ||
310 | let bounds = f.db.generic_predicates_for_param(*id); | ||
311 | let substs = Substs::type_params_for_generics(&generics); | ||
312 | write_bounds_like_dyn_trait( | ||
313 | &bounds.iter().map(|b| b.clone().subst(&substs)).collect::<Vec<_>>(), | ||
314 | f, | ||
315 | )?; | ||
316 | } | ||
317 | } | ||
318 | } | ||
319 | Ty::Bound(idx) => write!(f, "?{}", idx)?, | ||
320 | Ty::Dyn(predicates) | Ty::Opaque(predicates) => { | ||
321 | match self { | ||
322 | Ty::Dyn(_) => write!(f, "dyn ")?, | ||
323 | Ty::Opaque(_) => write!(f, "impl ")?, | ||
324 | _ => unreachable!(), | ||
325 | }; | ||
326 | write_bounds_like_dyn_trait(&predicates, f)?; | ||
327 | } | ||
328 | Ty::Unknown => write!(f, "{{unknown}}")?, | ||
329 | Ty::Infer(..) => write!(f, "_")?, | ||
330 | } | ||
331 | Ok(()) | ||
332 | } | ||
333 | } | ||
334 | |||
335 | fn write_bounds_like_dyn_trait( | ||
336 | predicates: &[GenericPredicate], | ||
337 | f: &mut HirFormatter<impl HirDatabase>, | ||
338 | ) -> fmt::Result { | ||
339 | // Note: This code is written to produce nice results (i.e. | ||
340 | // corresponding to surface Rust) for types that can occur in | ||
341 | // actual Rust. It will have weird results if the predicates | ||
342 | // aren't as expected (i.e. self types = $0, projection | ||
343 | // predicates for a certain trait come after the Implemented | ||
344 | // predicate for that trait). | ||
345 | let mut first = true; | ||
346 | let mut angle_open = false; | ||
347 | for p in predicates.iter() { | ||
348 | match p { | ||
349 | GenericPredicate::Implemented(trait_ref) => { | ||
350 | if angle_open { | ||
351 | write!(f, ">")?; | ||
352 | } | ||
353 | if !first { | ||
354 | write!(f, " + ")?; | ||
355 | } | ||
356 | // We assume that the self type is $0 (i.e. the | ||
357 | // existential) here, which is the only thing that's | ||
358 | // possible in actual Rust, and hence don't print it | ||
359 | write!(f, "{}", f.db.trait_data(trait_ref.trait_).name.clone())?; | ||
360 | if trait_ref.substs.len() > 1 { | ||
361 | write!(f, "<")?; | ||
362 | f.write_joined(&trait_ref.substs[1..], ", ")?; | ||
363 | // there might be assoc type bindings, so we leave the angle brackets open | ||
364 | angle_open = true; | ||
365 | } | ||
366 | } | ||
367 | GenericPredicate::Projection(projection_pred) => { | ||
368 | // in types in actual Rust, these will always come | ||
369 | // after the corresponding Implemented predicate | ||
370 | if angle_open { | ||
371 | write!(f, ", ")?; | ||
372 | } else { | ||
373 | write!(f, "<")?; | ||
374 | angle_open = true; | ||
375 | } | ||
376 | let name = | ||
377 | f.db.type_alias_data(projection_pred.projection_ty.associated_ty).name.clone(); | ||
378 | write!(f, "{} = ", name)?; | ||
379 | projection_pred.ty.hir_fmt(f)?; | ||
380 | } | ||
381 | GenericPredicate::Error => { | ||
382 | if angle_open { | ||
383 | // impl Trait<X, {error}> | ||
384 | write!(f, ", ")?; | ||
385 | } else if !first { | ||
386 | // impl Trait + {error} | ||
387 | write!(f, " + ")?; | ||
388 | } | ||
389 | p.hir_fmt(f)?; | ||
390 | } | ||
391 | } | ||
392 | first = false; | ||
393 | } | ||
394 | if angle_open { | ||
395 | write!(f, ">")?; | ||
396 | } | ||
397 | Ok(()) | ||
398 | } | ||
399 | |||
400 | impl TraitRef { | ||
401 | fn hir_fmt_ext(&self, f: &mut HirFormatter<impl HirDatabase>, use_as: bool) -> fmt::Result { | ||
402 | if f.should_truncate() { | ||
403 | return write!(f, "{}", TYPE_HINT_TRUNCATION); | ||
404 | } | ||
405 | |||
406 | self.substs[0].hir_fmt(f)?; | ||
407 | if use_as { | ||
408 | write!(f, " as ")?; | ||
409 | } else { | ||
410 | write!(f, ": ")?; | ||
411 | } | ||
412 | write!(f, "{}", f.db.trait_data(self.trait_).name.clone())?; | ||
413 | if self.substs.len() > 1 { | ||
414 | write!(f, "<")?; | ||
415 | f.write_joined(&self.substs[1..], ", ")?; | ||
416 | write!(f, ">")?; | ||
417 | } | ||
418 | Ok(()) | ||
419 | } | ||
420 | } | ||
421 | |||
422 | impl HirDisplay for TraitRef { | ||
423 | fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result { | ||
424 | self.hir_fmt_ext(f, false) | ||
425 | } | ||
426 | } | ||
427 | |||
428 | impl HirDisplay for &GenericPredicate { | ||
429 | fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result { | ||
430 | HirDisplay::hir_fmt(*self, f) | ||
431 | } | ||
432 | } | ||
433 | |||
434 | impl HirDisplay for GenericPredicate { | ||
435 | fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result { | ||
436 | if f.should_truncate() { | ||
437 | return write!(f, "{}", TYPE_HINT_TRUNCATION); | ||
438 | } | ||
439 | |||
440 | match self { | ||
441 | GenericPredicate::Implemented(trait_ref) => trait_ref.hir_fmt(f)?, | ||
442 | GenericPredicate::Projection(projection_pred) => { | ||
443 | write!(f, "<")?; | ||
444 | projection_pred.projection_ty.trait_ref(f.db).hir_fmt_ext(f, true)?; | ||
445 | write!( | ||
446 | f, | ||
447 | ">::{} = {}", | ||
448 | f.db.type_alias_data(projection_pred.projection_ty.associated_ty).name, | ||
449 | projection_pred.ty.display(f.db) | ||
450 | )?; | ||
451 | } | ||
452 | GenericPredicate::Error => write!(f, "{{error}}")?, | ||
453 | } | ||
454 | Ok(()) | ||
455 | } | ||
456 | } | ||
457 | |||
458 | impl HirDisplay for Obligation { | ||
459 | fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result { | ||
460 | match self { | ||
461 | Obligation::Trait(tr) => write!(f, "Implements({})", tr.display(f.db)), | ||
462 | Obligation::Projection(proj) => write!( | ||
463 | f, | ||
464 | "Normalize({} => {})", | ||
465 | proj.projection_ty.display(f.db), | ||
466 | proj.ty.display(f.db) | ||
467 | ), | ||
468 | } | ||
469 | } | ||
470 | } | ||
diff --git a/crates/ra_hir_ty/src/infer/unify.rs b/crates/ra_hir_ty/src/infer/unify.rs index fe05642ae..1dc842f40 100644 --- a/crates/ra_hir_ty/src/infer/unify.rs +++ b/crates/ra_hir_ty/src/infer/unify.rs | |||
@@ -249,6 +249,8 @@ impl InferenceTable { | |||
249 | match (ty1, ty2) { | 249 | match (ty1, ty2) { |
250 | (Ty::Unknown, _) | (_, Ty::Unknown) => true, | 250 | (Ty::Unknown, _) | (_, Ty::Unknown) => true, |
251 | 251 | ||
252 | (Ty::Placeholder(p1), Ty::Placeholder(p2)) if *p1 == *p2 => true, | ||
253 | |||
252 | (Ty::Infer(InferTy::TypeVar(tv1)), Ty::Infer(InferTy::TypeVar(tv2))) | 254 | (Ty::Infer(InferTy::TypeVar(tv1)), Ty::Infer(InferTy::TypeVar(tv2))) |
253 | | (Ty::Infer(InferTy::IntVar(tv1)), Ty::Infer(InferTy::IntVar(tv2))) | 255 | | (Ty::Infer(InferTy::IntVar(tv1)), Ty::Infer(InferTy::IntVar(tv2))) |
254 | | (Ty::Infer(InferTy::FloatVar(tv1)), Ty::Infer(InferTy::FloatVar(tv2))) | 256 | | (Ty::Infer(InferTy::FloatVar(tv1)), Ty::Infer(InferTy::FloatVar(tv2))) |
diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs index c5fe18c85..571579cc4 100644 --- a/crates/ra_hir_ty/src/lib.rs +++ b/crates/ra_hir_ty/src/lib.rs | |||
@@ -41,13 +41,12 @@ mod marks; | |||
41 | 41 | ||
42 | use std::ops::Deref; | 42 | use std::ops::Deref; |
43 | use std::sync::Arc; | 43 | use std::sync::Arc; |
44 | use std::{fmt, iter, mem}; | 44 | use std::{iter, mem}; |
45 | 45 | ||
46 | use hir_def::{ | 46 | use hir_def::{ |
47 | expr::ExprId, generics::TypeParamProvenance, type_ref::Mutability, AdtId, AssocContainerId, | 47 | expr::ExprId, type_ref::Mutability, AdtId, AssocContainerId, DefWithBodyId, GenericDefId, |
48 | DefWithBodyId, GenericDefId, HasModule, Lookup, TraitId, TypeAliasId, TypeParamId, | 48 | HasModule, Lookup, TraitId, TypeAliasId, TypeParamId, |
49 | }; | 49 | }; |
50 | use hir_expand::name::Name; | ||
51 | use ra_db::{impl_intern_key, salsa, CrateId}; | 50 | use ra_db::{impl_intern_key, salsa, CrateId}; |
52 | 51 | ||
53 | use crate::{ | 52 | use crate::{ |
@@ -55,7 +54,7 @@ use crate::{ | |||
55 | primitive::{FloatTy, IntTy, Uncertain}, | 54 | primitive::{FloatTy, IntTy, Uncertain}, |
56 | utils::{generics, make_mut_slice, Generics}, | 55 | utils::{generics, make_mut_slice, Generics}, |
57 | }; | 56 | }; |
58 | use display::{HirDisplay, HirFormatter}; | 57 | use display::HirDisplay; |
59 | 58 | ||
60 | pub use autoderef::autoderef; | 59 | pub use autoderef::autoderef; |
61 | pub use infer::{do_infer_query, InferTy, InferenceResult}; | 60 | pub use infer::{do_infer_query, InferTy, InferenceResult}; |
@@ -291,7 +290,7 @@ pub enum Ty { | |||
291 | /// {}` when we're type-checking the body of that function. In this | 290 | /// {}` when we're type-checking the body of that function. In this |
292 | /// situation, we know this stands for *some* type, but don't know the exact | 291 | /// situation, we know this stands for *some* type, but don't know the exact |
293 | /// type. | 292 | /// type. |
294 | Param(TypeParamId), | 293 | Placeholder(TypeParamId), |
295 | 294 | ||
296 | /// A bound type variable. This is used in various places: when representing | 295 | /// A bound type variable. This is used in various places: when representing |
297 | /// some polymorphic type like the type of function `fn f<T>`, the type | 296 | /// some polymorphic type like the type of function `fn f<T>`, the type |
@@ -365,7 +364,7 @@ impl Substs { | |||
365 | 364 | ||
366 | /// Return Substs that replace each parameter by itself (i.e. `Ty::Param`). | 365 | /// Return Substs that replace each parameter by itself (i.e. `Ty::Param`). |
367 | pub(crate) fn type_params_for_generics(generic_params: &Generics) -> Substs { | 366 | pub(crate) fn type_params_for_generics(generic_params: &Generics) -> Substs { |
368 | Substs(generic_params.iter().map(|(id, _)| Ty::Param(id)).collect()) | 367 | Substs(generic_params.iter().map(|(id, _)| Ty::Placeholder(id)).collect()) |
369 | } | 368 | } |
370 | 369 | ||
371 | /// Return Substs that replace each parameter by itself (i.e. `Ty::Param`). | 370 | /// Return Substs that replace each parameter by itself (i.e. `Ty::Param`). |
@@ -813,7 +812,7 @@ impl TypeWalk for Ty { | |||
813 | p.walk(f); | 812 | p.walk(f); |
814 | } | 813 | } |
815 | } | 814 | } |
816 | Ty::Param { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {} | 815 | Ty::Placeholder { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {} |
817 | } | 816 | } |
818 | f(self); | 817 | f(self); |
819 | } | 818 | } |
@@ -831,374 +830,8 @@ impl TypeWalk for Ty { | |||
831 | p.walk_mut_binders(f, binders + 1); | 830 | p.walk_mut_binders(f, binders + 1); |
832 | } | 831 | } |
833 | } | 832 | } |
834 | Ty::Param { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {} | 833 | Ty::Placeholder { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {} |
835 | } | 834 | } |
836 | f(self, binders); | 835 | f(self, binders); |
837 | } | 836 | } |
838 | } | 837 | } |
839 | |||
840 | const TYPE_HINT_TRUNCATION: &str = "…"; | ||
841 | |||
842 | impl HirDisplay for &Ty { | ||
843 | fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result { | ||
844 | HirDisplay::hir_fmt(*self, f) | ||
845 | } | ||
846 | } | ||
847 | |||
848 | impl HirDisplay for ApplicationTy { | ||
849 | fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result { | ||
850 | if f.should_truncate() { | ||
851 | return write!(f, "{}", TYPE_HINT_TRUNCATION); | ||
852 | } | ||
853 | |||
854 | match self.ctor { | ||
855 | TypeCtor::Bool => write!(f, "bool")?, | ||
856 | TypeCtor::Char => write!(f, "char")?, | ||
857 | TypeCtor::Int(t) => write!(f, "{}", t)?, | ||
858 | TypeCtor::Float(t) => write!(f, "{}", t)?, | ||
859 | TypeCtor::Str => write!(f, "str")?, | ||
860 | TypeCtor::Slice => { | ||
861 | let t = self.parameters.as_single(); | ||
862 | write!(f, "[{}]", t.display(f.db))?; | ||
863 | } | ||
864 | TypeCtor::Array => { | ||
865 | let t = self.parameters.as_single(); | ||
866 | write!(f, "[{}; _]", t.display(f.db))?; | ||
867 | } | ||
868 | TypeCtor::RawPtr(m) => { | ||
869 | let t = self.parameters.as_single(); | ||
870 | write!(f, "*{}{}", m.as_keyword_for_ptr(), t.display(f.db))?; | ||
871 | } | ||
872 | TypeCtor::Ref(m) => { | ||
873 | let t = self.parameters.as_single(); | ||
874 | let ty_display = if f.omit_verbose_types() { | ||
875 | t.display_truncated(f.db, f.max_size) | ||
876 | } else { | ||
877 | t.display(f.db) | ||
878 | }; | ||
879 | write!(f, "&{}{}", m.as_keyword_for_ref(), ty_display)?; | ||
880 | } | ||
881 | TypeCtor::Never => write!(f, "!")?, | ||
882 | TypeCtor::Tuple { .. } => { | ||
883 | let ts = &self.parameters; | ||
884 | if ts.len() == 1 { | ||
885 | write!(f, "({},)", ts[0].display(f.db))?; | ||
886 | } else { | ||
887 | write!(f, "(")?; | ||
888 | f.write_joined(&*ts.0, ", ")?; | ||
889 | write!(f, ")")?; | ||
890 | } | ||
891 | } | ||
892 | TypeCtor::FnPtr { .. } => { | ||
893 | let sig = FnSig::from_fn_ptr_substs(&self.parameters); | ||
894 | write!(f, "fn(")?; | ||
895 | f.write_joined(sig.params(), ", ")?; | ||
896 | write!(f, ") -> {}", sig.ret().display(f.db))?; | ||
897 | } | ||
898 | TypeCtor::FnDef(def) => { | ||
899 | let sig = f.db.callable_item_signature(def).subst(&self.parameters); | ||
900 | let name = match def { | ||
901 | CallableDef::FunctionId(ff) => f.db.function_data(ff).name.clone(), | ||
902 | CallableDef::StructId(s) => f.db.struct_data(s).name.clone(), | ||
903 | CallableDef::EnumVariantId(e) => { | ||
904 | let enum_data = f.db.enum_data(e.parent); | ||
905 | enum_data.variants[e.local_id].name.clone() | ||
906 | } | ||
907 | }; | ||
908 | match def { | ||
909 | CallableDef::FunctionId(_) => write!(f, "fn {}", name)?, | ||
910 | CallableDef::StructId(_) | CallableDef::EnumVariantId(_) => { | ||
911 | write!(f, "{}", name)? | ||
912 | } | ||
913 | } | ||
914 | if self.parameters.len() > 0 { | ||
915 | let generics = generics(f.db, def.into()); | ||
916 | let (parent_params, self_param, type_params, _impl_trait_params) = | ||
917 | generics.provenance_split(); | ||
918 | let total_len = parent_params + self_param + type_params; | ||
919 | // We print all params except implicit impl Trait params. Still a bit weird; should we leave out parent and self? | ||
920 | if total_len > 0 { | ||
921 | write!(f, "<")?; | ||
922 | f.write_joined(&self.parameters.0[..total_len], ", ")?; | ||
923 | write!(f, ">")?; | ||
924 | } | ||
925 | } | ||
926 | write!(f, "(")?; | ||
927 | f.write_joined(sig.params(), ", ")?; | ||
928 | write!(f, ") -> {}", sig.ret().display(f.db))?; | ||
929 | } | ||
930 | TypeCtor::Adt(def_id) => { | ||
931 | let name = match def_id { | ||
932 | AdtId::StructId(it) => f.db.struct_data(it).name.clone(), | ||
933 | AdtId::UnionId(it) => f.db.union_data(it).name.clone(), | ||
934 | AdtId::EnumId(it) => f.db.enum_data(it).name.clone(), | ||
935 | }; | ||
936 | write!(f, "{}", name)?; | ||
937 | if self.parameters.len() > 0 { | ||
938 | write!(f, "<")?; | ||
939 | |||
940 | let mut non_default_parameters = Vec::with_capacity(self.parameters.len()); | ||
941 | let parameters_to_write = if f.omit_verbose_types() { | ||
942 | match self | ||
943 | .ctor | ||
944 | .as_generic_def() | ||
945 | .map(|generic_def_id| f.db.generic_defaults(generic_def_id)) | ||
946 | .filter(|defaults| !defaults.is_empty()) | ||
947 | { | ||
948 | Option::None => self.parameters.0.as_ref(), | ||
949 | Option::Some(default_parameters) => { | ||
950 | for (i, parameter) in self.parameters.iter().enumerate() { | ||
951 | match (parameter, default_parameters.get(i)) { | ||
952 | (&Ty::Unknown, _) | (_, None) => { | ||
953 | non_default_parameters.push(parameter.clone()) | ||
954 | } | ||
955 | (_, Some(default_parameter)) | ||
956 | if parameter != default_parameter => | ||
957 | { | ||
958 | non_default_parameters.push(parameter.clone()) | ||
959 | } | ||
960 | _ => (), | ||
961 | } | ||
962 | } | ||
963 | &non_default_parameters | ||
964 | } | ||
965 | } | ||
966 | } else { | ||
967 | self.parameters.0.as_ref() | ||
968 | }; | ||
969 | |||
970 | f.write_joined(parameters_to_write, ", ")?; | ||
971 | write!(f, ">")?; | ||
972 | } | ||
973 | } | ||
974 | TypeCtor::AssociatedType(type_alias) => { | ||
975 | let trait_ = match type_alias.lookup(f.db).container { | ||
976 | AssocContainerId::TraitId(it) => it, | ||
977 | _ => panic!("not an associated type"), | ||
978 | }; | ||
979 | let trait_name = f.db.trait_data(trait_).name.clone(); | ||
980 | let name = f.db.type_alias_data(type_alias).name.clone(); | ||
981 | write!(f, "{}::{}", trait_name, name)?; | ||
982 | if self.parameters.len() > 0 { | ||
983 | write!(f, "<")?; | ||
984 | f.write_joined(&*self.parameters.0, ", ")?; | ||
985 | write!(f, ">")?; | ||
986 | } | ||
987 | } | ||
988 | TypeCtor::Closure { .. } => { | ||
989 | let sig = self.parameters[0] | ||
990 | .callable_sig(f.db) | ||
991 | .expect("first closure parameter should contain signature"); | ||
992 | let return_type_hint = sig.ret().display(f.db); | ||
993 | if sig.params().is_empty() { | ||
994 | write!(f, "|| -> {}", return_type_hint)?; | ||
995 | } else if f.omit_verbose_types() { | ||
996 | write!(f, "|{}| -> {}", TYPE_HINT_TRUNCATION, return_type_hint)?; | ||
997 | } else { | ||
998 | write!(f, "|")?; | ||
999 | f.write_joined(sig.params(), ", ")?; | ||
1000 | write!(f, "| -> {}", return_type_hint)?; | ||
1001 | }; | ||
1002 | } | ||
1003 | } | ||
1004 | Ok(()) | ||
1005 | } | ||
1006 | } | ||
1007 | |||
1008 | impl HirDisplay for ProjectionTy { | ||
1009 | fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result { | ||
1010 | if f.should_truncate() { | ||
1011 | return write!(f, "{}", TYPE_HINT_TRUNCATION); | ||
1012 | } | ||
1013 | |||
1014 | let trait_name = f.db.trait_data(self.trait_(f.db)).name.clone(); | ||
1015 | write!(f, "<{} as {}", self.parameters[0].display(f.db), trait_name,)?; | ||
1016 | if self.parameters.len() > 1 { | ||
1017 | write!(f, "<")?; | ||
1018 | f.write_joined(&self.parameters[1..], ", ")?; | ||
1019 | write!(f, ">")?; | ||
1020 | } | ||
1021 | write!(f, ">::{}", f.db.type_alias_data(self.associated_ty).name)?; | ||
1022 | Ok(()) | ||
1023 | } | ||
1024 | } | ||
1025 | |||
1026 | impl HirDisplay for Ty { | ||
1027 | fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result { | ||
1028 | if f.should_truncate() { | ||
1029 | return write!(f, "{}", TYPE_HINT_TRUNCATION); | ||
1030 | } | ||
1031 | |||
1032 | match self { | ||
1033 | Ty::Apply(a_ty) => a_ty.hir_fmt(f)?, | ||
1034 | Ty::Projection(p_ty) => p_ty.hir_fmt(f)?, | ||
1035 | Ty::Param(id) => { | ||
1036 | let generics = generics(f.db, id.parent); | ||
1037 | let param_data = &generics.params.types[id.local_id]; | ||
1038 | match param_data.provenance { | ||
1039 | TypeParamProvenance::TypeParamList | TypeParamProvenance::TraitSelf => { | ||
1040 | write!(f, "{}", param_data.name.clone().unwrap_or_else(Name::missing))? | ||
1041 | } | ||
1042 | TypeParamProvenance::ArgumentImplTrait => { | ||
1043 | write!(f, "impl ")?; | ||
1044 | let bounds = f.db.generic_predicates_for_param(*id); | ||
1045 | let substs = Substs::type_params_for_generics(&generics); | ||
1046 | write_bounds_like_dyn_trait( | ||
1047 | &bounds.iter().map(|b| b.clone().subst(&substs)).collect::<Vec<_>>(), | ||
1048 | f, | ||
1049 | )?; | ||
1050 | } | ||
1051 | } | ||
1052 | } | ||
1053 | Ty::Bound(idx) => write!(f, "?{}", idx)?, | ||
1054 | Ty::Dyn(predicates) | Ty::Opaque(predicates) => { | ||
1055 | match self { | ||
1056 | Ty::Dyn(_) => write!(f, "dyn ")?, | ||
1057 | Ty::Opaque(_) => write!(f, "impl ")?, | ||
1058 | _ => unreachable!(), | ||
1059 | }; | ||
1060 | write_bounds_like_dyn_trait(&predicates, f)?; | ||
1061 | } | ||
1062 | Ty::Unknown => write!(f, "{{unknown}}")?, | ||
1063 | Ty::Infer(..) => write!(f, "_")?, | ||
1064 | } | ||
1065 | Ok(()) | ||
1066 | } | ||
1067 | } | ||
1068 | |||
1069 | fn write_bounds_like_dyn_trait( | ||
1070 | predicates: &[GenericPredicate], | ||
1071 | f: &mut HirFormatter<impl HirDatabase>, | ||
1072 | ) -> fmt::Result { | ||
1073 | // Note: This code is written to produce nice results (i.e. | ||
1074 | // corresponding to surface Rust) for types that can occur in | ||
1075 | // actual Rust. It will have weird results if the predicates | ||
1076 | // aren't as expected (i.e. self types = $0, projection | ||
1077 | // predicates for a certain trait come after the Implemented | ||
1078 | // predicate for that trait). | ||
1079 | let mut first = true; | ||
1080 | let mut angle_open = false; | ||
1081 | for p in predicates.iter() { | ||
1082 | match p { | ||
1083 | GenericPredicate::Implemented(trait_ref) => { | ||
1084 | if angle_open { | ||
1085 | write!(f, ">")?; | ||
1086 | } | ||
1087 | if !first { | ||
1088 | write!(f, " + ")?; | ||
1089 | } | ||
1090 | // We assume that the self type is $0 (i.e. the | ||
1091 | // existential) here, which is the only thing that's | ||
1092 | // possible in actual Rust, and hence don't print it | ||
1093 | write!(f, "{}", f.db.trait_data(trait_ref.trait_).name.clone())?; | ||
1094 | if trait_ref.substs.len() > 1 { | ||
1095 | write!(f, "<")?; | ||
1096 | f.write_joined(&trait_ref.substs[1..], ", ")?; | ||
1097 | // there might be assoc type bindings, so we leave the angle brackets open | ||
1098 | angle_open = true; | ||
1099 | } | ||
1100 | } | ||
1101 | GenericPredicate::Projection(projection_pred) => { | ||
1102 | // in types in actual Rust, these will always come | ||
1103 | // after the corresponding Implemented predicate | ||
1104 | if angle_open { | ||
1105 | write!(f, ", ")?; | ||
1106 | } else { | ||
1107 | write!(f, "<")?; | ||
1108 | angle_open = true; | ||
1109 | } | ||
1110 | let name = | ||
1111 | f.db.type_alias_data(projection_pred.projection_ty.associated_ty).name.clone(); | ||
1112 | write!(f, "{} = ", name)?; | ||
1113 | projection_pred.ty.hir_fmt(f)?; | ||
1114 | } | ||
1115 | GenericPredicate::Error => { | ||
1116 | if angle_open { | ||
1117 | // impl Trait<X, {error}> | ||
1118 | write!(f, ", ")?; | ||
1119 | } else if !first { | ||
1120 | // impl Trait + {error} | ||
1121 | write!(f, " + ")?; | ||
1122 | } | ||
1123 | p.hir_fmt(f)?; | ||
1124 | } | ||
1125 | } | ||
1126 | first = false; | ||
1127 | } | ||
1128 | if angle_open { | ||
1129 | write!(f, ">")?; | ||
1130 | } | ||
1131 | Ok(()) | ||
1132 | } | ||
1133 | |||
1134 | impl TraitRef { | ||
1135 | fn hir_fmt_ext(&self, f: &mut HirFormatter<impl HirDatabase>, use_as: bool) -> fmt::Result { | ||
1136 | if f.should_truncate() { | ||
1137 | return write!(f, "{}", TYPE_HINT_TRUNCATION); | ||
1138 | } | ||
1139 | |||
1140 | self.substs[0].hir_fmt(f)?; | ||
1141 | if use_as { | ||
1142 | write!(f, " as ")?; | ||
1143 | } else { | ||
1144 | write!(f, ": ")?; | ||
1145 | } | ||
1146 | write!(f, "{}", f.db.trait_data(self.trait_).name.clone())?; | ||
1147 | if self.substs.len() > 1 { | ||
1148 | write!(f, "<")?; | ||
1149 | f.write_joined(&self.substs[1..], ", ")?; | ||
1150 | write!(f, ">")?; | ||
1151 | } | ||
1152 | Ok(()) | ||
1153 | } | ||
1154 | } | ||
1155 | |||
1156 | impl HirDisplay for TraitRef { | ||
1157 | fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result { | ||
1158 | self.hir_fmt_ext(f, false) | ||
1159 | } | ||
1160 | } | ||
1161 | |||
1162 | impl HirDisplay for &GenericPredicate { | ||
1163 | fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result { | ||
1164 | HirDisplay::hir_fmt(*self, f) | ||
1165 | } | ||
1166 | } | ||
1167 | |||
1168 | impl HirDisplay for GenericPredicate { | ||
1169 | fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result { | ||
1170 | if f.should_truncate() { | ||
1171 | return write!(f, "{}", TYPE_HINT_TRUNCATION); | ||
1172 | } | ||
1173 | |||
1174 | match self { | ||
1175 | GenericPredicate::Implemented(trait_ref) => trait_ref.hir_fmt(f)?, | ||
1176 | GenericPredicate::Projection(projection_pred) => { | ||
1177 | write!(f, "<")?; | ||
1178 | projection_pred.projection_ty.trait_ref(f.db).hir_fmt_ext(f, true)?; | ||
1179 | write!( | ||
1180 | f, | ||
1181 | ">::{} = {}", | ||
1182 | f.db.type_alias_data(projection_pred.projection_ty.associated_ty).name, | ||
1183 | projection_pred.ty.display(f.db) | ||
1184 | )?; | ||
1185 | } | ||
1186 | GenericPredicate::Error => write!(f, "{{error}}")?, | ||
1187 | } | ||
1188 | Ok(()) | ||
1189 | } | ||
1190 | } | ||
1191 | |||
1192 | impl HirDisplay for Obligation { | ||
1193 | fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result { | ||
1194 | match self { | ||
1195 | Obligation::Trait(tr) => write!(f, "Implements({})", tr.display(f.db)), | ||
1196 | Obligation::Projection(proj) => write!( | ||
1197 | f, | ||
1198 | "Normalize({} => {})", | ||
1199 | proj.projection_ty.display(f.db), | ||
1200 | proj.ty.display(f.db) | ||
1201 | ), | ||
1202 | } | ||
1203 | } | ||
1204 | } | ||
diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs index c68c5852b..6a2aded02 100644 --- a/crates/ra_hir_ty/src/lower.rs +++ b/crates/ra_hir_ty/src/lower.rs | |||
@@ -14,9 +14,9 @@ use hir_def::{ | |||
14 | path::{GenericArg, Path, PathSegment, PathSegments}, | 14 | path::{GenericArg, Path, PathSegment, PathSegments}, |
15 | resolver::{HasResolver, Resolver, TypeNs}, | 15 | resolver::{HasResolver, Resolver, TypeNs}, |
16 | type_ref::{TypeBound, TypeRef}, | 16 | type_ref::{TypeBound, TypeRef}, |
17 | AdtId, ConstId, EnumId, EnumVariantId, FunctionId, GenericDefId, HasModule, ImplId, | 17 | AdtId, AssocContainerId, ConstId, EnumId, EnumVariantId, FunctionId, GenericDefId, HasModule, |
18 | LocalStructFieldId, Lookup, StaticId, StructId, TraitId, TypeAliasId, TypeParamId, UnionId, | 18 | ImplId, LocalStructFieldId, Lookup, StaticId, StructId, TraitId, TypeAliasId, TypeParamId, |
19 | VariantId, | 19 | UnionId, VariantId, |
20 | }; | 20 | }; |
21 | use ra_arena::map::ArenaMap; | 21 | use ra_arena::map::ArenaMap; |
22 | use ra_db::CrateId; | 22 | use ra_db::CrateId; |
@@ -152,7 +152,7 @@ impl Ty { | |||
152 | data.provenance == TypeParamProvenance::ArgumentImplTrait | 152 | data.provenance == TypeParamProvenance::ArgumentImplTrait |
153 | }) | 153 | }) |
154 | .nth(idx as usize) | 154 | .nth(idx as usize) |
155 | .map_or(Ty::Unknown, |(id, _)| Ty::Param(id)); | 155 | .map_or(Ty::Unknown, |(id, _)| Ty::Placeholder(id)); |
156 | param | 156 | param |
157 | } else { | 157 | } else { |
158 | Ty::Unknown | 158 | Ty::Unknown |
@@ -270,7 +270,7 @@ impl Ty { | |||
270 | let generics = | 270 | let generics = |
271 | generics(ctx.db, ctx.resolver.generic_def().expect("generics in scope")); | 271 | generics(ctx.db, ctx.resolver.generic_def().expect("generics in scope")); |
272 | match ctx.type_param_mode { | 272 | match ctx.type_param_mode { |
273 | TypeParamLoweringMode::Placeholder => Ty::Param(param_id), | 273 | TypeParamLoweringMode::Placeholder => Ty::Placeholder(param_id), |
274 | TypeParamLoweringMode::Variable => { | 274 | TypeParamLoweringMode::Variable => { |
275 | let idx = generics.param_idx(param_id).expect("matching generics"); | 275 | let idx = generics.param_idx(param_id).expect("matching generics"); |
276 | Ty::Bound(idx) | 276 | Ty::Bound(idx) |
@@ -339,7 +339,7 @@ impl Ty { | |||
339 | None => return Ty::Unknown, // this can't actually happen | 339 | None => return Ty::Unknown, // this can't actually happen |
340 | }; | 340 | }; |
341 | let param_id = match self_ty { | 341 | let param_id = match self_ty { |
342 | Ty::Param(id) if ctx.type_param_mode == TypeParamLoweringMode::Placeholder => id, | 342 | Ty::Placeholder(id) if ctx.type_param_mode == TypeParamLoweringMode::Placeholder => id, |
343 | Ty::Bound(idx) if ctx.type_param_mode == TypeParamLoweringMode::Variable => { | 343 | Ty::Bound(idx) if ctx.type_param_mode == TypeParamLoweringMode::Variable => { |
344 | let generics = generics(ctx.db, def); | 344 | let generics = generics(ctx.db, def); |
345 | let param_id = if let Some((id, _)) = generics.iter().nth(idx as usize) { | 345 | let param_id = if let Some((id, _)) = generics.iter().nth(idx as usize) { |
@@ -544,7 +544,7 @@ impl GenericPredicate { | |||
544 | let generics = generics(ctx.db, generic_def); | 544 | let generics = generics(ctx.db, generic_def); |
545 | let param_id = hir_def::TypeParamId { parent: generic_def, local_id: *param_id }; | 545 | let param_id = hir_def::TypeParamId { parent: generic_def, local_id: *param_id }; |
546 | match ctx.type_param_mode { | 546 | match ctx.type_param_mode { |
547 | TypeParamLoweringMode::Placeholder => Ty::Param(param_id), | 547 | TypeParamLoweringMode::Placeholder => Ty::Placeholder(param_id), |
548 | TypeParamLoweringMode::Variable => { | 548 | TypeParamLoweringMode::Variable => { |
549 | let idx = generics.param_idx(param_id).expect("matching generics"); | 549 | let idx = generics.param_idx(param_id).expect("matching generics"); |
550 | Ty::Bound(idx) | 550 | Ty::Bound(idx) |
@@ -672,11 +672,35 @@ impl TraitEnvironment { | |||
672 | pub fn lower(db: &impl HirDatabase, resolver: &Resolver) -> Arc<TraitEnvironment> { | 672 | pub fn lower(db: &impl HirDatabase, resolver: &Resolver) -> Arc<TraitEnvironment> { |
673 | let ctx = TyLoweringContext::new(db, &resolver) | 673 | let ctx = TyLoweringContext::new(db, &resolver) |
674 | .with_type_param_mode(TypeParamLoweringMode::Placeholder); | 674 | .with_type_param_mode(TypeParamLoweringMode::Placeholder); |
675 | let predicates = resolver | 675 | let mut predicates = resolver |
676 | .where_predicates_in_scope() | 676 | .where_predicates_in_scope() |
677 | .flat_map(|pred| GenericPredicate::from_where_predicate(&ctx, pred)) | 677 | .flat_map(|pred| GenericPredicate::from_where_predicate(&ctx, pred)) |
678 | .collect::<Vec<_>>(); | 678 | .collect::<Vec<_>>(); |
679 | 679 | ||
680 | if let Some(def) = resolver.generic_def() { | ||
681 | let container: Option<AssocContainerId> = match def { | ||
682 | // FIXME: is there a function for this? | ||
683 | GenericDefId::FunctionId(f) => Some(f.lookup(db).container), | ||
684 | GenericDefId::AdtId(_) => None, | ||
685 | GenericDefId::TraitId(_) => None, | ||
686 | GenericDefId::TypeAliasId(t) => Some(t.lookup(db).container), | ||
687 | GenericDefId::ImplId(_) => None, | ||
688 | GenericDefId::EnumVariantId(_) => None, | ||
689 | GenericDefId::ConstId(c) => Some(c.lookup(db).container), | ||
690 | }; | ||
691 | if let Some(AssocContainerId::TraitId(trait_id)) = container { | ||
692 | // add `Self: Trait<T1, T2, ...>` to the environment in trait | ||
693 | // function default implementations (and hypothetical code | ||
694 | // inside consts or type aliases) | ||
695 | test_utils::tested_by!(trait_self_implements_self); | ||
696 | let substs = Substs::type_params(db, trait_id); | ||
697 | let trait_ref = TraitRef { trait_: trait_id, substs }; | ||
698 | let pred = GenericPredicate::Implemented(trait_ref); | ||
699 | |||
700 | predicates.push(pred); | ||
701 | } | ||
702 | } | ||
703 | |||
680 | Arc::new(TraitEnvironment { predicates }) | 704 | Arc::new(TraitEnvironment { predicates }) |
681 | } | 705 | } |
682 | } | 706 | } |
diff --git a/crates/ra_hir_ty/src/marks.rs b/crates/ra_hir_ty/src/marks.rs index 0f754eb9c..de5cb1d6b 100644 --- a/crates/ra_hir_ty/src/marks.rs +++ b/crates/ra_hir_ty/src/marks.rs | |||
@@ -4,6 +4,8 @@ test_utils::marks!( | |||
4 | type_var_cycles_resolve_completely | 4 | type_var_cycles_resolve_completely |
5 | type_var_cycles_resolve_as_possible | 5 | type_var_cycles_resolve_as_possible |
6 | type_var_resolves_to_int_var | 6 | type_var_resolves_to_int_var |
7 | impl_self_type_match_without_receiver | ||
7 | match_ergonomics_ref | 8 | match_ergonomics_ref |
8 | coerce_merge_fail_fallback | 9 | coerce_merge_fail_fallback |
10 | trait_self_implements_self | ||
9 | ); | 11 | ); |
diff --git a/crates/ra_hir_ty/src/method_resolution.rs b/crates/ra_hir_ty/src/method_resolution.rs index 5283bff28..4f8c52433 100644 --- a/crates/ra_hir_ty/src/method_resolution.rs +++ b/crates/ra_hir_ty/src/method_resolution.rs | |||
@@ -425,6 +425,15 @@ fn iterate_inherent_methods<T>( | |||
425 | if !is_valid_candidate(db, name, receiver_ty, item, self_ty) { | 425 | if !is_valid_candidate(db, name, receiver_ty, item, self_ty) { |
426 | continue; | 426 | continue; |
427 | } | 427 | } |
428 | // we have to check whether the self type unifies with the type | ||
429 | // that the impl is for. If we have a receiver type, this | ||
430 | // already happens in `is_valid_candidate` above; if not, we | ||
431 | // check it here | ||
432 | if receiver_ty.is_none() && inherent_impl_substs(db, impl_block, self_ty).is_none() | ||
433 | { | ||
434 | test_utils::tested_by!(impl_self_type_match_without_receiver); | ||
435 | continue; | ||
436 | } | ||
428 | if let Some(result) = callback(&self_ty.value, item) { | 437 | if let Some(result) = callback(&self_ty.value, item) { |
429 | return Some(result); | 438 | return Some(result); |
430 | } | 439 | } |
diff --git a/crates/ra_hir_ty/src/tests/coercion.rs b/crates/ra_hir_ty/src/tests/coercion.rs index fc5ef36a5..42330b269 100644 --- a/crates/ra_hir_ty/src/tests/coercion.rs +++ b/crates/ra_hir_ty/src/tests/coercion.rs | |||
@@ -526,3 +526,25 @@ fn test() { | |||
526 | "### | 526 | "### |
527 | ); | 527 | ); |
528 | } | 528 | } |
529 | |||
530 | #[test] | ||
531 | fn coerce_placeholder_ref() { | ||
532 | // placeholders should unify, even behind references | ||
533 | assert_snapshot!( | ||
534 | infer_with_mismatches(r#" | ||
535 | struct S<T> { t: T } | ||
536 | impl<TT> S<TT> { | ||
537 | fn get(&self) -> &TT { | ||
538 | &self.t | ||
539 | } | ||
540 | } | ||
541 | "#, true), | ||
542 | @r###" | ||
543 | [51; 55) 'self': &S<TT> | ||
544 | [64; 87) '{ ... }': &TT | ||
545 | [74; 81) '&self.t': &TT | ||
546 | [75; 79) 'self': &S<TT> | ||
547 | [75; 81) 'self.t': TT | ||
548 | "### | ||
549 | ); | ||
550 | } | ||
diff --git a/crates/ra_hir_ty/src/tests/method_resolution.rs b/crates/ra_hir_ty/src/tests/method_resolution.rs index 1722563aa..1f767d324 100644 --- a/crates/ra_hir_ty/src/tests/method_resolution.rs +++ b/crates/ra_hir_ty/src/tests/method_resolution.rs | |||
@@ -964,6 +964,38 @@ fn test() { S2.into()<|>; } | |||
964 | } | 964 | } |
965 | 965 | ||
966 | #[test] | 966 | #[test] |
967 | fn method_resolution_overloaded_method() { | ||
968 | test_utils::covers!(impl_self_type_match_without_receiver); | ||
969 | let t = type_at( | ||
970 | r#" | ||
971 | //- main.rs | ||
972 | struct Wrapper<T>(T); | ||
973 | struct Foo<T>(T); | ||
974 | struct Bar<T>(T); | ||
975 | |||
976 | impl<T> Wrapper<Foo<T>> { | ||
977 | pub fn new(foo_: T) -> Self { | ||
978 | Wrapper(Foo(foo_)) | ||
979 | } | ||
980 | } | ||
981 | |||
982 | impl<T> Wrapper<Bar<T>> { | ||
983 | pub fn new(bar_: T) -> Self { | ||
984 | Wrapper(Bar(bar_)) | ||
985 | } | ||
986 | } | ||
987 | |||
988 | fn main() { | ||
989 | let a = Wrapper::<Foo<f32>>::new(1.0); | ||
990 | let b = Wrapper::<Bar<f32>>::new(1.0); | ||
991 | (a, b)<|>; | ||
992 | } | ||
993 | "#, | ||
994 | ); | ||
995 | assert_eq!(t, "(Wrapper<Foo<f32>>, Wrapper<Bar<f32>>)") | ||
996 | } | ||
997 | |||
998 | #[test] | ||
967 | fn method_resolution_encountering_fn_type() { | 999 | fn method_resolution_encountering_fn_type() { |
968 | type_at( | 1000 | type_at( |
969 | r#" | 1001 | r#" |
diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs index 17611ddbf..aa2018944 100644 --- a/crates/ra_hir_ty/src/tests/traits.rs +++ b/crates/ra_hir_ty/src/tests/traits.rs | |||
@@ -300,6 +300,54 @@ fn test() { | |||
300 | } | 300 | } |
301 | 301 | ||
302 | #[test] | 302 | #[test] |
303 | fn trait_default_method_self_bound_implements_trait() { | ||
304 | test_utils::covers!(trait_self_implements_self); | ||
305 | assert_snapshot!( | ||
306 | infer(r#" | ||
307 | trait Trait { | ||
308 | fn foo(&self) -> i64; | ||
309 | fn bar(&self) -> { | ||
310 | let x = self.foo(); | ||
311 | } | ||
312 | } | ||
313 | "#), | ||
314 | @r###" | ||
315 | [27; 31) 'self': &Self | ||
316 | [53; 57) 'self': &Self | ||
317 | [62; 97) '{ ... }': () | ||
318 | [76; 77) 'x': i64 | ||
319 | [80; 84) 'self': &Self | ||
320 | [80; 90) 'self.foo()': i64 | ||
321 | "### | ||
322 | ); | ||
323 | } | ||
324 | |||
325 | #[test] | ||
326 | fn trait_default_method_self_bound_implements_super_trait() { | ||
327 | test_utils::covers!(trait_self_implements_self); | ||
328 | assert_snapshot!( | ||
329 | infer(r#" | ||
330 | trait SuperTrait { | ||
331 | fn foo(&self) -> i64; | ||
332 | } | ||
333 | trait Trait: SuperTrait { | ||
334 | fn bar(&self) -> { | ||
335 | let x = self.foo(); | ||
336 | } | ||
337 | } | ||
338 | "#), | ||
339 | @r###" | ||
340 | [32; 36) 'self': &Self | ||
341 | [86; 90) 'self': &Self | ||
342 | [95; 130) '{ ... }': () | ||
343 | [109; 110) 'x': i64 | ||
344 | [113; 117) 'self': &Self | ||
345 | [113; 123) 'self.foo()': i64 | ||
346 | "### | ||
347 | ); | ||
348 | } | ||
349 | |||
350 | #[test] | ||
303 | fn infer_project_associated_type() { | 351 | fn infer_project_associated_type() { |
304 | // y, z, a don't yet work because of https://github.com/rust-lang/chalk/issues/234 | 352 | // y, z, a don't yet work because of https://github.com/rust-lang/chalk/issues/234 |
305 | assert_snapshot!( | 353 | assert_snapshot!( |
diff --git a/crates/ra_hir_ty/src/traits.rs b/crates/ra_hir_ty/src/traits.rs index 88af61e87..ff8e75b48 100644 --- a/crates/ra_hir_ty/src/traits.rs +++ b/crates/ra_hir_ty/src/traits.rs | |||
@@ -60,6 +60,9 @@ impl TraitSolver { | |||
60 | context.0.db.check_canceled(); | 60 | context.0.db.check_canceled(); |
61 | let remaining = fuel.get(); | 61 | let remaining = fuel.get(); |
62 | fuel.set(remaining - 1); | 62 | fuel.set(remaining - 1); |
63 | if remaining == 0 { | ||
64 | log::debug!("fuel exhausted"); | ||
65 | } | ||
63 | remaining > 0 | 66 | remaining > 0 |
64 | }) | 67 | }) |
65 | } | 68 | } |
diff --git a/crates/ra_hir_ty/src/traits/chalk.rs b/crates/ra_hir_ty/src/traits/chalk.rs index 4974c565b..882160fa8 100644 --- a/crates/ra_hir_ty/src/traits/chalk.rs +++ b/crates/ra_hir_ty/src/traits/chalk.rs | |||
@@ -142,7 +142,7 @@ impl ToChalk for Ty { | |||
142 | let substitution = proj_ty.parameters.to_chalk(db); | 142 | let substitution = proj_ty.parameters.to_chalk(db); |
143 | chalk_ir::AliasTy { associated_ty_id, substitution }.cast().intern() | 143 | chalk_ir::AliasTy { associated_ty_id, substitution }.cast().intern() |
144 | } | 144 | } |
145 | Ty::Param(id) => { | 145 | Ty::Placeholder(id) => { |
146 | let interned_id = db.intern_type_param_id(id); | 146 | let interned_id = db.intern_type_param_id(id); |
147 | PlaceholderIndex { | 147 | PlaceholderIndex { |
148 | ui: UniverseIndex::ROOT, | 148 | ui: UniverseIndex::ROOT, |
@@ -184,7 +184,7 @@ impl ToChalk for Ty { | |||
184 | let interned_id = crate::db::GlobalTypeParamId::from_intern_id( | 184 | let interned_id = crate::db::GlobalTypeParamId::from_intern_id( |
185 | crate::salsa::InternId::from(idx.idx), | 185 | crate::salsa::InternId::from(idx.idx), |
186 | ); | 186 | ); |
187 | Ty::Param(db.lookup_intern_type_param_id(interned_id)) | 187 | Ty::Placeholder(db.lookup_intern_type_param_id(interned_id)) |
188 | } | 188 | } |
189 | chalk_ir::TyData::Alias(proj) => { | 189 | chalk_ir::TyData::Alias(proj) => { |
190 | let associated_ty = from_chalk(db, proj.associated_ty_id); | 190 | let associated_ty = from_chalk(db, proj.associated_ty_id); |