aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_ty
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir_ty')
-rw-r--r--crates/ra_hir_ty/src/autoderef.rs4
-rw-r--r--crates/ra_hir_ty/src/expr.rs4
-rw-r--r--crates/ra_hir_ty/src/infer.rs67
-rw-r--r--crates/ra_hir_ty/src/infer/expr.rs5
-rw-r--r--crates/ra_hir_ty/src/infer/path.rs25
-rw-r--r--crates/ra_hir_ty/src/lower.rs70
-rw-r--r--crates/ra_hir_ty/src/marks.rs1
-rw-r--r--crates/ra_hir_ty/src/tests/traits.rs65
-rw-r--r--crates/ra_hir_ty/src/traits/builtin.rs6
-rw-r--r--crates/ra_hir_ty/src/utils.rs9
10 files changed, 171 insertions, 85 deletions
diff --git a/crates/ra_hir_ty/src/autoderef.rs b/crates/ra_hir_ty/src/autoderef.rs
index d557962b4..ee48fa537 100644
--- a/crates/ra_hir_ty/src/autoderef.rs
+++ b/crates/ra_hir_ty/src/autoderef.rs
@@ -6,7 +6,7 @@
6use std::iter::successors; 6use std::iter::successors;
7 7
8use hir_def::lang_item::LangItemTarget; 8use hir_def::lang_item::LangItemTarget;
9use hir_expand::name; 9use hir_expand::name::name;
10use log::{info, warn}; 10use log::{info, warn};
11use ra_db::CrateId; 11use ra_db::CrateId;
12 12
@@ -52,7 +52,7 @@ fn deref_by_trait(
52 LangItemTarget::TraitId(it) => it, 52 LangItemTarget::TraitId(it) => it,
53 _ => return None, 53 _ => return None,
54 }; 54 };
55 let target = db.trait_data(deref_trait).associated_type_by_name(&name::TARGET_TYPE)?; 55 let target = db.trait_data(deref_trait).associated_type_by_name(&name![Target])?;
56 56
57 let generic_params = generics(db, target.into()); 57 let generic_params = generics(db, target.into());
58 if generic_params.len() != 1 { 58 if generic_params.len() != 1 {
diff --git a/crates/ra_hir_ty/src/expr.rs b/crates/ra_hir_ty/src/expr.rs
index d2bd64e5c..f752a9f09 100644
--- a/crates/ra_hir_ty/src/expr.rs
+++ b/crates/ra_hir_ty/src/expr.rs
@@ -3,7 +3,7 @@
3use std::sync::Arc; 3use std::sync::Arc;
4 4
5use hir_def::{ 5use hir_def::{
6 path::{known, Path}, 6 path::{path, Path},
7 resolver::HasResolver, 7 resolver::HasResolver,
8 AdtId, FunctionId, 8 AdtId, FunctionId,
9}; 9};
@@ -124,7 +124,7 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
124 None => return, 124 None => return,
125 }; 125 };
126 126
127 let std_result_path = known::std_result_result(); 127 let std_result_path = path![std::result::Result];
128 128
129 let resolver = self.func.resolver(db); 129 let resolver = self.func.resolver(db);
130 let std_result_enum = match resolver.resolve_known_enum(db, &std_result_path) { 130 let std_result_enum = match resolver.resolve_known_enum(db, &std_result_path) {
diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs
index a1201b3e4..98ba05fc2 100644
--- a/crates/ra_hir_ty/src/infer.rs
+++ b/crates/ra_hir_ty/src/infer.rs
@@ -24,14 +24,15 @@ use hir_def::{
24 body::Body, 24 body::Body,
25 data::{ConstData, FunctionData}, 25 data::{ConstData, FunctionData},
26 expr::{BindingAnnotation, ExprId, PatId}, 26 expr::{BindingAnnotation, ExprId, PatId},
27 path::{known, Path}, 27 path::{path, Path},
28 resolver::{HasResolver, Resolver, TypeNs}, 28 resolver::{HasResolver, Resolver, TypeNs},
29 type_ref::{Mutability, TypeRef}, 29 type_ref::{Mutability, TypeRef},
30 AdtId, AssocItemId, DefWithBodyId, FunctionId, StructFieldId, TypeAliasId, VariantId, 30 AdtId, AssocItemId, DefWithBodyId, FunctionId, StructFieldId, TypeAliasId, VariantId,
31}; 31};
32use hir_expand::{diagnostics::DiagnosticSink, name}; 32use hir_expand::{diagnostics::DiagnosticSink, name::name};
33use ra_arena::map::ArenaMap; 33use ra_arena::map::ArenaMap;
34use ra_prof::profile; 34use ra_prof::profile;
35use test_utils::tested_by;
35 36
36use super::{ 37use super::{
37 primitive::{FloatTy, IntTy}, 38 primitive::{FloatTy, IntTy},
@@ -274,6 +275,29 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
274 self.normalize_associated_types_in(ty) 275 self.normalize_associated_types_in(ty)
275 } 276 }
276 277
278 /// Replaces `impl Trait` in `ty` by type variables and obligations for
279 /// those variables. This is done for function arguments when calling a
280 /// function, and for return types when inside the function body, i.e. in
281 /// the cases where the `impl Trait` is 'transparent'. In other cases, `impl
282 /// Trait` is represented by `Ty::Opaque`.
283 fn insert_vars_for_impl_trait(&mut self, ty: Ty) -> Ty {
284 ty.fold(&mut |ty| match ty {
285 Ty::Opaque(preds) => {
286 tested_by!(insert_vars_for_impl_trait);
287 let var = self.table.new_type_var();
288 let var_subst = Substs::builder(1).push(var.clone()).build();
289 self.obligations.extend(
290 preds
291 .iter()
292 .map(|pred| pred.clone().subst_bound_vars(&var_subst))
293 .filter_map(Obligation::from_predicate),
294 );
295 var
296 }
297 _ => ty,
298 })
299 }
300
277 /// Replaces Ty::Unknown by a new type var, so we can maybe still infer it. 301 /// Replaces Ty::Unknown by a new type var, so we can maybe still infer it.
278 fn insert_type_vars_shallow(&mut self, ty: Ty) -> Ty { 302 fn insert_type_vars_shallow(&mut self, ty: Ty) -> Ty {
279 match ty { 303 match ty {
@@ -386,7 +410,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
386 let resolver = &self.resolver; 410 let resolver = &self.resolver;
387 // FIXME: this should resolve assoc items as well, see this example: 411 // FIXME: this should resolve assoc items as well, see this example:
388 // https://play.rust-lang.org/?gist=087992e9e22495446c01c0d4e2d69521 412 // https://play.rust-lang.org/?gist=087992e9e22495446c01c0d4e2d69521
389 match resolver.resolve_path_in_type_ns_fully(self.db, &path) { 413 match resolver.resolve_path_in_type_ns_fully(self.db, path.mod_path()) {
390 Some(TypeNs::AdtId(AdtId::StructId(strukt))) => { 414 Some(TypeNs::AdtId(AdtId::StructId(strukt))) => {
391 let substs = Ty::substs_from_path(self.db, resolver, path, strukt.into()); 415 let substs = Ty::substs_from_path(self.db, resolver, path, strukt.into());
392 let ty = self.db.ty(strukt.into()); 416 let ty = self.db.ty(strukt.into());
@@ -414,7 +438,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
414 438
415 self.infer_pat(*pat, &ty, BindingMode::default()); 439 self.infer_pat(*pat, &ty, BindingMode::default());
416 } 440 }
417 self.return_ty = self.make_ty(&data.ret_type); 441 let return_ty = self.make_ty(&data.ret_type);
442 self.return_ty = self.insert_vars_for_impl_trait(return_ty);
418 } 443 }
419 444
420 fn infer_body(&mut self) { 445 fn infer_body(&mut self) {
@@ -422,73 +447,73 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
422 } 447 }
423 448
424 fn resolve_into_iter_item(&self) -> Option<TypeAliasId> { 449 fn resolve_into_iter_item(&self) -> Option<TypeAliasId> {
425 let path = known::std_iter_into_iterator(); 450 let path = path![std::iter::IntoIterator];
426 let trait_ = self.resolver.resolve_known_trait(self.db, &path)?; 451 let trait_ = self.resolver.resolve_known_trait(self.db, &path)?;
427 self.db.trait_data(trait_).associated_type_by_name(&name::ITEM_TYPE) 452 self.db.trait_data(trait_).associated_type_by_name(&name![Item])
428 } 453 }
429 454
430 fn resolve_ops_try_ok(&self) -> Option<TypeAliasId> { 455 fn resolve_ops_try_ok(&self) -> Option<TypeAliasId> {
431 let path = known::std_ops_try(); 456 let path = path![std::ops::Try];
432 let trait_ = self.resolver.resolve_known_trait(self.db, &path)?; 457 let trait_ = self.resolver.resolve_known_trait(self.db, &path)?;
433 self.db.trait_data(trait_).associated_type_by_name(&name::OK_TYPE) 458 self.db.trait_data(trait_).associated_type_by_name(&name![Ok])
434 } 459 }
435 460
436 fn resolve_ops_neg_output(&self) -> Option<TypeAliasId> { 461 fn resolve_ops_neg_output(&self) -> Option<TypeAliasId> {
437 let path = known::std_ops_neg(); 462 let path = path![std::ops::Neg];
438 let trait_ = self.resolver.resolve_known_trait(self.db, &path)?; 463 let trait_ = self.resolver.resolve_known_trait(self.db, &path)?;
439 self.db.trait_data(trait_).associated_type_by_name(&name::OUTPUT_TYPE) 464 self.db.trait_data(trait_).associated_type_by_name(&name![Output])
440 } 465 }
441 466
442 fn resolve_ops_not_output(&self) -> Option<TypeAliasId> { 467 fn resolve_ops_not_output(&self) -> Option<TypeAliasId> {
443 let path = known::std_ops_not(); 468 let path = path![std::ops::Not];
444 let trait_ = self.resolver.resolve_known_trait(self.db, &path)?; 469 let trait_ = self.resolver.resolve_known_trait(self.db, &path)?;
445 self.db.trait_data(trait_).associated_type_by_name(&name::OUTPUT_TYPE) 470 self.db.trait_data(trait_).associated_type_by_name(&name![Output])
446 } 471 }
447 472
448 fn resolve_future_future_output(&self) -> Option<TypeAliasId> { 473 fn resolve_future_future_output(&self) -> Option<TypeAliasId> {
449 let path = known::std_future_future(); 474 let path = path![std::future::Future];
450 let trait_ = self.resolver.resolve_known_trait(self.db, &path)?; 475 let trait_ = self.resolver.resolve_known_trait(self.db, &path)?;
451 self.db.trait_data(trait_).associated_type_by_name(&name::OUTPUT_TYPE) 476 self.db.trait_data(trait_).associated_type_by_name(&name![Output])
452 } 477 }
453 478
454 fn resolve_boxed_box(&self) -> Option<AdtId> { 479 fn resolve_boxed_box(&self) -> Option<AdtId> {
455 let path = known::std_boxed_box(); 480 let path = path![std::boxed::Box];
456 let struct_ = self.resolver.resolve_known_struct(self.db, &path)?; 481 let struct_ = self.resolver.resolve_known_struct(self.db, &path)?;
457 Some(struct_.into()) 482 Some(struct_.into())
458 } 483 }
459 484
460 fn resolve_range_full(&self) -> Option<AdtId> { 485 fn resolve_range_full(&self) -> Option<AdtId> {
461 let path = known::std_ops_range_full(); 486 let path = path![std::ops::RangeFull];
462 let struct_ = self.resolver.resolve_known_struct(self.db, &path)?; 487 let struct_ = self.resolver.resolve_known_struct(self.db, &path)?;
463 Some(struct_.into()) 488 Some(struct_.into())
464 } 489 }
465 490
466 fn resolve_range(&self) -> Option<AdtId> { 491 fn resolve_range(&self) -> Option<AdtId> {
467 let path = known::std_ops_range(); 492 let path = path![std::ops::Range];
468 let struct_ = self.resolver.resolve_known_struct(self.db, &path)?; 493 let struct_ = self.resolver.resolve_known_struct(self.db, &path)?;
469 Some(struct_.into()) 494 Some(struct_.into())
470 } 495 }
471 496
472 fn resolve_range_inclusive(&self) -> Option<AdtId> { 497 fn resolve_range_inclusive(&self) -> Option<AdtId> {
473 let path = known::std_ops_range_inclusive(); 498 let path = path![std::ops::RangeInclusive];
474 let struct_ = self.resolver.resolve_known_struct(self.db, &path)?; 499 let struct_ = self.resolver.resolve_known_struct(self.db, &path)?;
475 Some(struct_.into()) 500 Some(struct_.into())
476 } 501 }
477 502
478 fn resolve_range_from(&self) -> Option<AdtId> { 503 fn resolve_range_from(&self) -> Option<AdtId> {
479 let path = known::std_ops_range_from(); 504 let path = path![std::ops::RangeFrom];
480 let struct_ = self.resolver.resolve_known_struct(self.db, &path)?; 505 let struct_ = self.resolver.resolve_known_struct(self.db, &path)?;
481 Some(struct_.into()) 506 Some(struct_.into())
482 } 507 }
483 508
484 fn resolve_range_to(&self) -> Option<AdtId> { 509 fn resolve_range_to(&self) -> Option<AdtId> {
485 let path = known::std_ops_range_to(); 510 let path = path![std::ops::RangeTo];
486 let struct_ = self.resolver.resolve_known_struct(self.db, &path)?; 511 let struct_ = self.resolver.resolve_known_struct(self.db, &path)?;
487 Some(struct_.into()) 512 Some(struct_.into())
488 } 513 }
489 514
490 fn resolve_range_to_inclusive(&self) -> Option<AdtId> { 515 fn resolve_range_to_inclusive(&self) -> Option<AdtId> {
491 let path = known::std_ops_range_to_inclusive(); 516 let path = path![std::ops::RangeToInclusive];
492 let struct_ = self.resolver.resolve_known_struct(self.db, &path)?; 517 let struct_ = self.resolver.resolve_known_struct(self.db, &path)?;
493 Some(struct_.into()) 518 Some(struct_.into())
494 } 519 }
diff --git a/crates/ra_hir_ty/src/infer/expr.rs b/crates/ra_hir_ty/src/infer/expr.rs
index f8c00a7b4..924ad3e81 100644
--- a/crates/ra_hir_ty/src/infer/expr.rs
+++ b/crates/ra_hir_ty/src/infer/expr.rs
@@ -10,7 +10,7 @@ use hir_def::{
10 resolver::resolver_for_expr, 10 resolver::resolver_for_expr,
11 AdtId, ContainerId, Lookup, StructFieldId, 11 AdtId, ContainerId, Lookup, StructFieldId,
12}; 12};
13use hir_expand::name::{self, Name}; 13use hir_expand::name::{name, Name};
14use ra_syntax::ast::RangeOp; 14use ra_syntax::ast::RangeOp;
15 15
16use crate::{ 16use crate::{
@@ -613,6 +613,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
613 continue; 613 continue;
614 } 614 }
615 615
616 let param_ty = self.insert_vars_for_impl_trait(param_ty);
616 let param_ty = self.normalize_associated_types_in(param_ty); 617 let param_ty = self.normalize_associated_types_in(param_ty);
617 self.infer_expr_coerce(arg, &Expectation::has_type(param_ty.clone())); 618 self.infer_expr_coerce(arg, &Expectation::has_type(param_ty.clone()));
618 } 619 }
@@ -631,7 +632,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
631 // Parent arguments are unknown, except for the receiver type 632 // Parent arguments are unknown, except for the receiver type
632 if let Some(parent_generics) = def_generics.as_ref().map(|p| p.iter_parent()) { 633 if let Some(parent_generics) = def_generics.as_ref().map(|p| p.iter_parent()) {
633 for (_id, param) in parent_generics { 634 for (_id, param) in parent_generics {
634 if param.name == name::SELF_TYPE { 635 if param.name == name![Self] {
635 substs.push(receiver_ty.clone()); 636 substs.push(receiver_ty.clone());
636 } else { 637 } else {
637 substs.push(Ty::Unknown); 638 substs.push(Ty::Unknown);
diff --git a/crates/ra_hir_ty/src/infer/path.rs b/crates/ra_hir_ty/src/infer/path.rs
index 37db005ea..3bae0ca6c 100644
--- a/crates/ra_hir_ty/src/infer/path.rs
+++ b/crates/ra_hir_ty/src/infer/path.rs
@@ -32,21 +32,21 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
32 path: &Path, 32 path: &Path,
33 id: ExprOrPatId, 33 id: ExprOrPatId,
34 ) -> Option<Ty> { 34 ) -> Option<Ty> {
35 let (value, self_subst) = if let PathKind::Type(type_ref) = &path.kind { 35 let (value, self_subst) = if let PathKind::Type(type_ref) = path.kind() {
36 if path.segments.is_empty() { 36 if path.segments().is_empty() {
37 // This can't actually happen syntax-wise 37 // This can't actually happen syntax-wise
38 return None; 38 return None;
39 } 39 }
40 let ty = self.make_ty(type_ref); 40 let ty = self.make_ty(type_ref);
41 let remaining_segments_for_ty = &path.segments[..path.segments.len() - 1]; 41 let remaining_segments_for_ty = path.segments().take(path.segments().len() - 1);
42 let ty = Ty::from_type_relative_path(self.db, resolver, ty, remaining_segments_for_ty); 42 let ty = Ty::from_type_relative_path(self.db, resolver, ty, remaining_segments_for_ty);
43 self.resolve_ty_assoc_item( 43 self.resolve_ty_assoc_item(
44 ty, 44 ty,
45 &path.segments.last().expect("path had at least one segment").name, 45 &path.segments().last().expect("path had at least one segment").name,
46 id, 46 id,
47 )? 47 )?
48 } else { 48 } else {
49 let value_or_partial = resolver.resolve_path_in_value_ns(self.db, &path)?; 49 let value_or_partial = resolver.resolve_path_in_value_ns(self.db, path.mod_path())?;
50 50
51 match value_or_partial { 51 match value_or_partial {
52 ResolveValueResult::ValueNs(it) => (it, None), 52 ResolveValueResult::ValueNs(it) => (it, None),
@@ -85,13 +85,13 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
85 remaining_index: usize, 85 remaining_index: usize,
86 id: ExprOrPatId, 86 id: ExprOrPatId,
87 ) -> Option<(ValueNs, Option<Substs>)> { 87 ) -> Option<(ValueNs, Option<Substs>)> {
88 assert!(remaining_index < path.segments.len()); 88 assert!(remaining_index < path.segments().len());
89 // there may be more intermediate segments between the resolved one and 89 // there may be more intermediate segments between the resolved one and
90 // the end. Only the last segment needs to be resolved to a value; from 90 // the end. Only the last segment needs to be resolved to a value; from
91 // the segments before that, we need to get either a type or a trait ref. 91 // the segments before that, we need to get either a type or a trait ref.
92 92
93 let resolved_segment = &path.segments[remaining_index - 1]; 93 let resolved_segment = path.segments().get(remaining_index - 1).unwrap();
94 let remaining_segments = &path.segments[remaining_index..]; 94 let remaining_segments = path.segments().skip(remaining_index);
95 let is_before_last = remaining_segments.len() == 1; 95 let is_before_last = remaining_segments.len() == 1;
96 96
97 match (def, is_before_last) { 97 match (def, is_before_last) {
@@ -112,7 +112,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
112 // trait but it's not the last segment, so the next segment 112 // trait but it's not the last segment, so the next segment
113 // should resolve to an associated type of that trait (e.g. `<T 113 // should resolve to an associated type of that trait (e.g. `<T
114 // as Iterator>::Item::default`) 114 // as Iterator>::Item::default`)
115 let remaining_segments_for_ty = &remaining_segments[..remaining_segments.len() - 1]; 115 let remaining_segments_for_ty =
116 remaining_segments.take(remaining_segments.len() - 1);
116 let ty = Ty::from_partly_resolved_hir_path( 117 let ty = Ty::from_partly_resolved_hir_path(
117 self.db, 118 self.db,
118 &self.resolver, 119 &self.resolver,
@@ -138,7 +139,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
138 fn resolve_trait_assoc_item( 139 fn resolve_trait_assoc_item(
139 &mut self, 140 &mut self,
140 trait_ref: TraitRef, 141 trait_ref: TraitRef,
141 segment: &PathSegment, 142 segment: PathSegment<'_>,
142 id: ExprOrPatId, 143 id: ExprOrPatId,
143 ) -> Option<(ValueNs, Option<Substs>)> { 144 ) -> Option<(ValueNs, Option<Substs>)> {
144 let trait_ = trait_ref.trait_; 145 let trait_ = trait_ref.trait_;
@@ -150,7 +151,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
150 .map(|(_name, id)| (*id).into()) 151 .map(|(_name, id)| (*id).into())
151 .find_map(|item| match item { 152 .find_map(|item| match item {
152 AssocItemId::FunctionId(func) => { 153 AssocItemId::FunctionId(func) => {
153 if segment.name == self.db.function_data(func).name { 154 if segment.name == &self.db.function_data(func).name {
154 Some(AssocItemId::FunctionId(func)) 155 Some(AssocItemId::FunctionId(func))
155 } else { 156 } else {
156 None 157 None
@@ -158,7 +159,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
158 } 159 }
159 160
160 AssocItemId::ConstId(konst) => { 161 AssocItemId::ConstId(konst) => {
161 if self.db.const_data(konst).name.as_ref().map_or(false, |n| n == &segment.name) 162 if self.db.const_data(konst).name.as_ref().map_or(false, |n| n == segment.name)
162 { 163 {
163 Some(AssocItemId::ConstId(konst)) 164 Some(AssocItemId::ConstId(konst))
164 } else { 165 } else {
diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs
index 5f795bc02..a4ddfc8ef 100644
--- a/crates/ra_hir_ty/src/lower.rs
+++ b/crates/ra_hir_ty/src/lower.rs
@@ -11,7 +11,7 @@ use std::sync::Arc;
11use hir_def::{ 11use hir_def::{
12 builtin_type::BuiltinType, 12 builtin_type::BuiltinType,
13 generics::WherePredicate, 13 generics::WherePredicate,
14 path::{GenericArg, Path, PathKind, PathSegment}, 14 path::{GenericArg, Path, PathKind, 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, ConstId, EnumId, EnumVariantId, FunctionId, GenericDefId, HasModule, ImplId,
@@ -101,13 +101,13 @@ impl Ty {
101 TypeRef::Path(path) => path, 101 TypeRef::Path(path) => path,
102 _ => return None, 102 _ => return None,
103 }; 103 };
104 if let PathKind::Type(_) = &path.kind { 104 if let PathKind::Type(_) = path.kind() {
105 return None; 105 return None;
106 } 106 }
107 if path.segments.len() > 1 { 107 if path.segments().len() > 1 {
108 return None; 108 return None;
109 } 109 }
110 let resolution = match resolver.resolve_path_in_type_ns(db, path) { 110 let resolution = match resolver.resolve_path_in_type_ns(db, path.mod_path()) {
111 Some((it, None)) => it, 111 Some((it, None)) => it,
112 _ => return None, 112 _ => return None,
113 }; 113 };
@@ -124,11 +124,11 @@ impl Ty {
124 db: &impl HirDatabase, 124 db: &impl HirDatabase,
125 resolver: &Resolver, 125 resolver: &Resolver,
126 ty: Ty, 126 ty: Ty,
127 remaining_segments: &[PathSegment], 127 remaining_segments: PathSegments<'_>,
128 ) -> Ty { 128 ) -> Ty {
129 if remaining_segments.len() == 1 { 129 if remaining_segments.len() == 1 {
130 // resolve unselected assoc types 130 // resolve unselected assoc types
131 let segment = &remaining_segments[0]; 131 let segment = remaining_segments.first().unwrap();
132 Ty::select_associated_type(db, resolver, ty, segment) 132 Ty::select_associated_type(db, resolver, ty, segment)
133 } else if remaining_segments.len() > 1 { 133 } else if remaining_segments.len() > 1 {
134 // FIXME report error (ambiguous associated type) 134 // FIXME report error (ambiguous associated type)
@@ -142,15 +142,15 @@ impl Ty {
142 db: &impl HirDatabase, 142 db: &impl HirDatabase,
143 resolver: &Resolver, 143 resolver: &Resolver,
144 resolution: TypeNs, 144 resolution: TypeNs,
145 resolved_segment: &PathSegment, 145 resolved_segment: PathSegment<'_>,
146 remaining_segments: &[PathSegment], 146 remaining_segments: PathSegments<'_>,
147 ) -> Ty { 147 ) -> Ty {
148 let ty = match resolution { 148 let ty = match resolution {
149 TypeNs::TraitId(trait_) => { 149 TypeNs::TraitId(trait_) => {
150 let trait_ref = 150 let trait_ref =
151 TraitRef::from_resolved_path(db, resolver, trait_, resolved_segment, None); 151 TraitRef::from_resolved_path(db, resolver, trait_, resolved_segment, None);
152 return if remaining_segments.len() == 1 { 152 return if remaining_segments.len() == 1 {
153 let segment = &remaining_segments[0]; 153 let segment = remaining_segments.first().unwrap();
154 let associated_ty = associated_type_by_name_including_super_traits( 154 let associated_ty = associated_type_by_name_including_super_traits(
155 db, 155 db,
156 trait_ref.trait_, 156 trait_ref.trait_,
@@ -202,21 +202,21 @@ impl Ty {
202 202
203 pub(crate) fn from_hir_path(db: &impl HirDatabase, resolver: &Resolver, path: &Path) -> Ty { 203 pub(crate) fn from_hir_path(db: &impl HirDatabase, resolver: &Resolver, path: &Path) -> Ty {
204 // Resolve the path (in type namespace) 204 // Resolve the path (in type namespace)
205 if let PathKind::Type(type_ref) = &path.kind { 205 if let PathKind::Type(type_ref) = path.kind() {
206 let ty = Ty::from_hir(db, resolver, &type_ref); 206 let ty = Ty::from_hir(db, resolver, &type_ref);
207 let remaining_segments = &path.segments[..]; 207 return Ty::from_type_relative_path(db, resolver, ty, path.segments());
208 return Ty::from_type_relative_path(db, resolver, ty, remaining_segments);
209 } 208 }
210 let (resolution, remaining_index) = match resolver.resolve_path_in_type_ns(db, path) { 209 let (resolution, remaining_index) =
211 Some(it) => it, 210 match resolver.resolve_path_in_type_ns(db, path.mod_path()) {
212 None => return Ty::Unknown, 211 Some(it) => it,
213 }; 212 None => return Ty::Unknown,
213 };
214 let (resolved_segment, remaining_segments) = match remaining_index { 214 let (resolved_segment, remaining_segments) = match remaining_index {
215 None => ( 215 None => (
216 path.segments.last().expect("resolved path has at least one element"), 216 path.segments().last().expect("resolved path has at least one element"),
217 &[] as &[PathSegment], 217 PathSegments::EMPTY,
218 ), 218 ),
219 Some(i) => (&path.segments[i - 1], &path.segments[i..]), 219 Some(i) => (path.segments().get(i - 1).unwrap(), path.segments().skip(i)),
220 }; 220 };
221 Ty::from_partly_resolved_hir_path( 221 Ty::from_partly_resolved_hir_path(
222 db, 222 db,
@@ -231,7 +231,7 @@ impl Ty {
231 db: &impl HirDatabase, 231 db: &impl HirDatabase,
232 resolver: &Resolver, 232 resolver: &Resolver,
233 self_ty: Ty, 233 self_ty: Ty,
234 segment: &PathSegment, 234 segment: PathSegment<'_>,
235 ) -> Ty { 235 ) -> Ty {
236 let param_idx = match self_ty { 236 let param_idx = match self_ty {
237 Ty::Param { idx, .. } => idx, 237 Ty::Param { idx, .. } => idx,
@@ -261,7 +261,7 @@ impl Ty {
261 fn from_hir_path_inner( 261 fn from_hir_path_inner(
262 db: &impl HirDatabase, 262 db: &impl HirDatabase,
263 resolver: &Resolver, 263 resolver: &Resolver,
264 segment: &PathSegment, 264 segment: PathSegment<'_>,
265 typable: TyDefId, 265 typable: TyDefId,
266 ) -> Ty { 266 ) -> Ty {
267 let generic_def = match typable { 267 let generic_def = match typable {
@@ -284,7 +284,7 @@ impl Ty {
284 // special-case enum variants 284 // special-case enum variants
285 resolved: ValueTyDefId, 285 resolved: ValueTyDefId,
286 ) -> Substs { 286 ) -> Substs {
287 let last = path.segments.last().expect("path should have at least one segment"); 287 let last = path.segments().last().expect("path should have at least one segment");
288 let (segment, generic_def) = match resolved { 288 let (segment, generic_def) = match resolved {
289 ValueTyDefId::FunctionId(it) => (last, Some(it.into())), 289 ValueTyDefId::FunctionId(it) => (last, Some(it.into())),
290 ValueTyDefId::StructId(it) => (last, Some(it.into())), 290 ValueTyDefId::StructId(it) => (last, Some(it.into())),
@@ -296,13 +296,11 @@ impl Ty {
296 // referring to the variant. So `Option::<T>::None` and 296 // referring to the variant. So `Option::<T>::None` and
297 // `Option::None::<T>` are both allowed (though the former is 297 // `Option::None::<T>` are both allowed (though the former is
298 // preferred). See also `def_ids_for_path_segments` in rustc. 298 // preferred). See also `def_ids_for_path_segments` in rustc.
299 let len = path.segments.len(); 299 let len = path.segments().len();
300 let segment = if len >= 2 && path.segments[len - 2].args_and_bindings.is_some() { 300 let penultimate = if len >= 2 { path.segments().get(len - 2) } else { None };
301 // Option::<T>::None 301 let segment = match penultimate {
302 &path.segments[len - 2] 302 Some(segment) if segment.args_and_bindings.is_some() => segment,
303 } else { 303 _ => last,
304 // Option::None::<T>
305 last
306 }; 304 };
307 (segment, Some(var.parent.into())) 305 (segment, Some(var.parent.into()))
308 } 306 }
@@ -314,7 +312,7 @@ impl Ty {
314pub(super) fn substs_from_path_segment( 312pub(super) fn substs_from_path_segment(
315 db: &impl HirDatabase, 313 db: &impl HirDatabase,
316 resolver: &Resolver, 314 resolver: &Resolver,
317 segment: &PathSegment, 315 segment: PathSegment<'_>,
318 def_generic: Option<GenericDefId>, 316 def_generic: Option<GenericDefId>,
319 add_self_param: bool, 317 add_self_param: bool,
320) -> Substs { 318) -> Substs {
@@ -372,11 +370,11 @@ impl TraitRef {
372 path: &Path, 370 path: &Path,
373 explicit_self_ty: Option<Ty>, 371 explicit_self_ty: Option<Ty>,
374 ) -> Option<Self> { 372 ) -> Option<Self> {
375 let resolved = match resolver.resolve_path_in_type_ns_fully(db, &path)? { 373 let resolved = match resolver.resolve_path_in_type_ns_fully(db, path.mod_path())? {
376 TypeNs::TraitId(tr) => tr, 374 TypeNs::TraitId(tr) => tr,
377 _ => return None, 375 _ => return None,
378 }; 376 };
379 let segment = path.segments.last().expect("path should have at least one segment"); 377 let segment = path.segments().last().expect("path should have at least one segment");
380 Some(TraitRef::from_resolved_path(db, resolver, resolved.into(), segment, explicit_self_ty)) 378 Some(TraitRef::from_resolved_path(db, resolver, resolved.into(), segment, explicit_self_ty))
381 } 379 }
382 380
@@ -384,7 +382,7 @@ impl TraitRef {
384 db: &impl HirDatabase, 382 db: &impl HirDatabase,
385 resolver: &Resolver, 383 resolver: &Resolver,
386 resolved: TraitId, 384 resolved: TraitId,
387 segment: &PathSegment, 385 segment: PathSegment<'_>,
388 explicit_self_ty: Option<Ty>, 386 explicit_self_ty: Option<Ty>,
389 ) -> Self { 387 ) -> Self {
390 let mut substs = TraitRef::substs_from_path(db, resolver, segment, resolved); 388 let mut substs = TraitRef::substs_from_path(db, resolver, segment, resolved);
@@ -410,7 +408,7 @@ impl TraitRef {
410 fn substs_from_path( 408 fn substs_from_path(
411 db: &impl HirDatabase, 409 db: &impl HirDatabase,
412 resolver: &Resolver, 410 resolver: &Resolver,
413 segment: &PathSegment, 411 segment: PathSegment<'_>,
414 resolved: TraitId, 412 resolved: TraitId,
415 ) -> Substs { 413 ) -> Substs {
416 let has_self_param = 414 let has_self_param =
@@ -464,12 +462,12 @@ fn assoc_type_bindings_from_type_bound<'a>(
464 trait_ref: TraitRef, 462 trait_ref: TraitRef,
465) -> impl Iterator<Item = GenericPredicate> + 'a { 463) -> impl Iterator<Item = GenericPredicate> + 'a {
466 let last_segment = match bound { 464 let last_segment = match bound {
467 TypeBound::Path(path) => path.segments.last(), 465 TypeBound::Path(path) => path.segments().last(),
468 TypeBound::Error => None, 466 TypeBound::Error => None,
469 }; 467 };
470 last_segment 468 last_segment
471 .into_iter() 469 .into_iter()
472 .flat_map(|segment| segment.args_and_bindings.iter()) 470 .flat_map(|segment| segment.args_and_bindings.into_iter())
473 .flat_map(|args_and_bindings| args_and_bindings.bindings.iter()) 471 .flat_map(|args_and_bindings| args_and_bindings.bindings.iter())
474 .map(move |(name, type_ref)| { 472 .map(move |(name, type_ref)| {
475 let associated_ty = 473 let associated_ty =
diff --git a/crates/ra_hir_ty/src/marks.rs b/crates/ra_hir_ty/src/marks.rs
index 0f754eb9c..fe74acf11 100644
--- a/crates/ra_hir_ty/src/marks.rs
+++ b/crates/ra_hir_ty/src/marks.rs
@@ -6,4 +6,5 @@ test_utils::marks!(
6 type_var_resolves_to_int_var 6 type_var_resolves_to_int_var
7 match_ergonomics_ref 7 match_ergonomics_ref
8 coerce_merge_fail_fallback 8 coerce_merge_fail_fallback
9 insert_vars_for_impl_trait
9); 10);
diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs
index 6139adb72..802937cb0 100644
--- a/crates/ra_hir_ty/src/tests/traits.rs
+++ b/crates/ra_hir_ty/src/tests/traits.rs
@@ -1,7 +1,10 @@
1use super::{infer, type_at, type_at_pos};
2use crate::test_db::TestDB;
3use insta::assert_snapshot; 1use insta::assert_snapshot;
2
4use ra_db::fixture::WithFixture; 3use ra_db::fixture::WithFixture;
4use test_utils::covers;
5
6use super::{infer, infer_with_mismatches, type_at, type_at_pos};
7use crate::test_db::TestDB;
5 8
6#[test] 9#[test]
7fn infer_await() { 10fn infer_await() {
@@ -1486,3 +1489,61 @@ fn test<T, U>() where T: Trait<U::Item>, U: Trait<T::Item> {
1486 // this is a legitimate cycle 1489 // this is a legitimate cycle
1487 assert_eq!(t, "{unknown}"); 1490 assert_eq!(t, "{unknown}");
1488} 1491}
1492
1493#[test]
1494fn unify_impl_trait() {
1495 covers!(insert_vars_for_impl_trait);
1496 assert_snapshot!(
1497 infer_with_mismatches(r#"
1498trait Trait<T> {}
1499
1500fn foo(x: impl Trait<u32>) { loop {} }
1501fn bar<T>(x: impl Trait<T>) -> T { loop {} }
1502
1503struct S<T>(T);
1504impl<T> Trait<T> for S<T> {}
1505
1506fn default<T>() -> T { loop {} }
1507
1508fn test() -> impl Trait<i32> {
1509 let s1 = S(default());
1510 foo(s1);
1511 let x: i32 = bar(S(default()));
1512 S(default())
1513}
1514"#, true),
1515 @r###"
1516 [27; 28) 'x': impl Trait<u32>
1517 [47; 58) '{ loop {} }': ()
1518 [49; 56) 'loop {}': !
1519 [54; 56) '{}': ()
1520 [69; 70) 'x': impl Trait<T>
1521 [92; 103) '{ loop {} }': T
1522 [94; 101) 'loop {}': !
1523 [99; 101) '{}': ()
1524 [172; 183) '{ loop {} }': T
1525 [174; 181) 'loop {}': !
1526 [179; 181) '{}': ()
1527 [214; 310) '{ ...t()) }': S<i32>
1528 [224; 226) 's1': S<u32>
1529 [229; 230) 'S': S<u32>(T) -> S<T>
1530 [229; 241) 'S(default())': S<u32>
1531 [231; 238) 'default': fn default<u32>() -> T
1532 [231; 240) 'default()': u32
1533 [247; 250) 'foo': fn foo(impl Trait<u32>) -> ()
1534 [247; 254) 'foo(s1)': ()
1535 [251; 253) 's1': S<u32>
1536 [264; 265) 'x': i32
1537 [273; 276) 'bar': fn bar<i32>(impl Trait<T>) -> T
1538 [273; 290) 'bar(S(...lt()))': i32
1539 [277; 278) 'S': S<i32>(T) -> S<T>
1540 [277; 289) 'S(default())': S<i32>
1541 [279; 286) 'default': fn default<i32>() -> T
1542 [279; 288) 'default()': i32
1543 [296; 297) 'S': S<i32>(T) -> S<T>
1544 [296; 308) 'S(default())': S<i32>
1545 [298; 305) 'default': fn default<i32>() -> T
1546 [298; 307) 'default()': i32
1547 "###
1548 );
1549}
diff --git a/crates/ra_hir_ty/src/traits/builtin.rs b/crates/ra_hir_ty/src/traits/builtin.rs
index 598fd81e3..cd587a338 100644
--- a/crates/ra_hir_ty/src/traits/builtin.rs
+++ b/crates/ra_hir_ty/src/traits/builtin.rs
@@ -1,7 +1,7 @@
1//! This module provides the built-in trait implementations, e.g. to make 1//! This module provides the built-in trait implementations, e.g. to make
2//! closures implement `Fn`. 2//! closures implement `Fn`.
3use hir_def::{expr::Expr, lang_item::LangItemTarget, TraitId, TypeAliasId}; 3use hir_def::{expr::Expr, lang_item::LangItemTarget, TraitId, TypeAliasId};
4use hir_expand::name; 4use hir_expand::name::name;
5use ra_db::CrateId; 5use ra_db::CrateId;
6 6
7use super::{AssocTyValue, Impl}; 7use super::{AssocTyValue, Impl};
@@ -79,7 +79,7 @@ fn closure_fn_trait_impl_datum(
79 // and don't want to return a valid value only to find out later that FnOnce 79 // and don't want to return a valid value only to find out later that FnOnce
80 // is broken 80 // is broken
81 let fn_once_trait = get_fn_trait(db, krate, super::FnTrait::FnOnce)?; 81 let fn_once_trait = get_fn_trait(db, krate, super::FnTrait::FnOnce)?;
82 let _output = db.trait_data(fn_once_trait).associated_type_by_name(&name::OUTPUT_TYPE)?; 82 let _output = db.trait_data(fn_once_trait).associated_type_by_name(&name![Output])?;
83 83
84 let num_args: u16 = match &db.body(data.def.into())[data.expr] { 84 let num_args: u16 = match &db.body(data.def.into())[data.expr] {
85 Expr::Lambda { args, .. } => args.len() as u16, 85 Expr::Lambda { args, .. } => args.len() as u16,
@@ -137,7 +137,7 @@ fn closure_fn_trait_output_assoc_ty_value(
137 137
138 let output_ty_id = db 138 let output_ty_id = db
139 .trait_data(fn_once_trait) 139 .trait_data(fn_once_trait)
140 .associated_type_by_name(&name::OUTPUT_TYPE) 140 .associated_type_by_name(&name![Output])
141 .expect("assoc ty value should not exist"); 141 .expect("assoc ty value should not exist");
142 142
143 BuiltinImplAssocTyValueData { 143 BuiltinImplAssocTyValueData {
diff --git a/crates/ra_hir_ty/src/utils.rs b/crates/ra_hir_ty/src/utils.rs
index aeb211a91..29799a8cb 100644
--- a/crates/ra_hir_ty/src/utils.rs
+++ b/crates/ra_hir_ty/src/utils.rs
@@ -6,14 +6,13 @@ use hir_def::{
6 adt::VariantData, 6 adt::VariantData,
7 db::DefDatabase, 7 db::DefDatabase,
8 generics::{GenericParams, TypeParamData}, 8 generics::{GenericParams, TypeParamData},
9 path::Path,
9 resolver::{HasResolver, TypeNs}, 10 resolver::{HasResolver, TypeNs},
10 type_ref::TypeRef, 11 type_ref::TypeRef,
11 ContainerId, GenericDefId, Lookup, TraitId, TypeAliasId, TypeParamId, VariantId, 12 ContainerId, GenericDefId, Lookup, TraitId, TypeAliasId, TypeParamId, VariantId,
12}; 13};
13use hir_expand::name::{self, Name}; 14use hir_expand::name::{name, Name};
14 15
15// FIXME: this is wrong, b/c it can't express `trait T: PartialEq<()>`.
16// We should return a `TraitREf` here.
17fn direct_super_traits(db: &impl DefDatabase, trait_: TraitId) -> Vec<TraitId> { 16fn direct_super_traits(db: &impl DefDatabase, trait_: TraitId) -> Vec<TraitId> {
18 let resolver = trait_.resolver(db); 17 let resolver = trait_.resolver(db);
19 // returning the iterator directly doesn't easily work because of 18 // returning the iterator directly doesn't easily work because of
@@ -24,10 +23,10 @@ fn direct_super_traits(db: &impl DefDatabase, trait_: TraitId) -> Vec<TraitId> {
24 .where_predicates 23 .where_predicates
25 .iter() 24 .iter()
26 .filter_map(|pred| match &pred.type_ref { 25 .filter_map(|pred| match &pred.type_ref {
27 TypeRef::Path(p) if p.as_ident() == Some(&name::SELF_TYPE) => pred.bound.as_path(), 26 TypeRef::Path(p) if p == &Path::from(name![Self]) => pred.bound.as_path(),
28 _ => None, 27 _ => None,
29 }) 28 })
30 .filter_map(|path| match resolver.resolve_path_in_type_ns_fully(db, path) { 29 .filter_map(|path| match resolver.resolve_path_in_type_ns_fully(db, path.mod_path()) {
31 Some(TypeNs::TraitId(t)) => Some(t), 30 Some(TypeNs::TraitId(t)) => Some(t),
32 _ => None, 31 _ => None,
33 }) 32 })