aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock1
-rw-r--r--crates/ra_hir_def/src/data.rs8
-rw-r--r--crates/ra_hir_def/src/path.rs21
-rw-r--r--crates/ra_hir_def/src/path/lower.rs21
-rw-r--r--crates/ra_hir_def/src/type_ref.rs12
-rw-r--r--crates/ra_hir_ty/Cargo.toml1
-rw-r--r--crates/ra_hir_ty/src/lower.rs42
-rw-r--r--crates/ra_hir_ty/src/tests/regression.rs3
-rw-r--r--crates/ra_hir_ty/src/tests/traits.rs73
-rw-r--r--crates/ra_hir_ty/src/traits/chalk/tls.rs42
10 files changed, 192 insertions, 32 deletions
diff --git a/Cargo.lock b/Cargo.lock
index aca737627..01fa64e6f 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1014,6 +1014,7 @@ dependencies = [
1014 "chalk-solve", 1014 "chalk-solve",
1015 "ena", 1015 "ena",
1016 "insta", 1016 "insta",
1017 "itertools",
1017 "log", 1018 "log",
1018 "ra_arena", 1019 "ra_arena",
1019 "ra_db", 1020 "ra_db",
diff --git a/crates/ra_hir_def/src/data.rs b/crates/ra_hir_def/src/data.rs
index 56a20c5bd..b3c91fea2 100644
--- a/crates/ra_hir_def/src/data.rs
+++ b/crates/ra_hir_def/src/data.rs
@@ -15,7 +15,7 @@ use ra_syntax::ast::{
15use crate::{ 15use crate::{
16 attr::Attrs, 16 attr::Attrs,
17 db::DefDatabase, 17 db::DefDatabase,
18 path::{path, GenericArgs, Path}, 18 path::{path, AssociatedTypeBinding, GenericArgs, Path},
19 src::HasSource, 19 src::HasSource,
20 type_ref::{Mutability, TypeBound, TypeRef}, 20 type_ref::{Mutability, TypeBound, TypeRef},
21 visibility::RawVisibility, 21 visibility::RawVisibility,
@@ -95,7 +95,11 @@ fn desugar_future_path(orig: TypeRef) -> Path {
95 let path = path![std::future::Future]; 95 let path = path![std::future::Future];
96 let mut generic_args: Vec<_> = std::iter::repeat(None).take(path.segments.len() - 1).collect(); 96 let mut generic_args: Vec<_> = std::iter::repeat(None).take(path.segments.len() - 1).collect();
97 let mut last = GenericArgs::empty(); 97 let mut last = GenericArgs::empty();
98 last.bindings.push((name![Output], orig)); 98 last.bindings.push(AssociatedTypeBinding {
99 name: name![Output],
100 type_ref: Some(orig),
101 bounds: Vec::new(),
102 });
99 generic_args.push(Some(Arc::new(last))); 103 generic_args.push(Some(Arc::new(last)));
100 104
101 Path::from_known_path(path, generic_args) 105 Path::from_known_path(path, generic_args)
diff --git a/crates/ra_hir_def/src/path.rs b/crates/ra_hir_def/src/path.rs
index 91c7b3e09..162b3c8c7 100644
--- a/crates/ra_hir_def/src/path.rs
+++ b/crates/ra_hir_def/src/path.rs
@@ -14,7 +14,10 @@ use hir_expand::{
14use ra_db::CrateId; 14use ra_db::CrateId;
15use ra_syntax::ast; 15use ra_syntax::ast;
16 16
17use crate::{type_ref::TypeRef, InFile}; 17use crate::{
18 type_ref::{TypeBound, TypeRef},
19 InFile,
20};
18 21
19#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] 22#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
20pub struct ModPath { 23pub struct ModPath {
@@ -111,7 +114,21 @@ pub struct GenericArgs {
111 /// is left out. 114 /// is left out.
112 pub has_self_type: bool, 115 pub has_self_type: bool,
113 /// Associated type bindings like in `Iterator<Item = T>`. 116 /// Associated type bindings like in `Iterator<Item = T>`.
114 pub bindings: Vec<(Name, TypeRef)>, 117 pub bindings: Vec<AssociatedTypeBinding>,
118}
119
120/// An associated type binding like in `Iterator<Item = T>`.
121#[derive(Debug, Clone, PartialEq, Eq, Hash)]
122pub struct AssociatedTypeBinding {
123 /// The name of the associated type.
124 pub name: Name,
125 /// The type bound to this associated type (in `Item = T`, this would be the
126 /// `T`). This can be `None` if there are bounds instead.
127 pub type_ref: Option<TypeRef>,
128 /// Bounds for the associated type, like in `Iterator<Item:
129 /// SomeOtherTrait>`. (This is the unstable `associated_type_bounds`
130 /// feature.)
131 pub bounds: Vec<TypeBound>,
115} 132}
116 133
117/// A single generic argument. 134/// A single generic argument.
diff --git a/crates/ra_hir_def/src/path/lower.rs b/crates/ra_hir_def/src/path/lower.rs
index 0f806d6fb..9ec2e0dcd 100644
--- a/crates/ra_hir_def/src/path/lower.rs
+++ b/crates/ra_hir_def/src/path/lower.rs
@@ -9,11 +9,12 @@ use hir_expand::{
9 hygiene::Hygiene, 9 hygiene::Hygiene,
10 name::{name, AsName}, 10 name::{name, AsName},
11}; 11};
12use ra_syntax::ast::{self, AstNode, TypeAscriptionOwner}; 12use ra_syntax::ast::{self, AstNode, TypeAscriptionOwner, TypeBoundsOwner};
13 13
14use super::AssociatedTypeBinding;
14use crate::{ 15use crate::{
15 path::{GenericArg, GenericArgs, ModPath, Path, PathKind}, 16 path::{GenericArg, GenericArgs, ModPath, Path, PathKind},
16 type_ref::TypeRef, 17 type_ref::{TypeBound, TypeRef},
17}; 18};
18 19
19pub(super) use lower_use::lower_use_tree; 20pub(super) use lower_use::lower_use_tree;
@@ -136,10 +137,16 @@ pub(super) fn lower_generic_args(node: ast::TypeArgList) -> Option<GenericArgs>
136 // lifetimes ignored for now 137 // lifetimes ignored for now
137 let mut bindings = Vec::new(); 138 let mut bindings = Vec::new();
138 for assoc_type_arg in node.assoc_type_args() { 139 for assoc_type_arg in node.assoc_type_args() {
140 let assoc_type_arg: ast::AssocTypeArg = assoc_type_arg;
139 if let Some(name_ref) = assoc_type_arg.name_ref() { 141 if let Some(name_ref) = assoc_type_arg.name_ref() {
140 let name = name_ref.as_name(); 142 let name = name_ref.as_name();
141 let type_ref = TypeRef::from_ast_opt(assoc_type_arg.type_ref()); 143 let type_ref = assoc_type_arg.type_ref().map(TypeRef::from_ast);
142 bindings.push((name, type_ref)); 144 let bounds = if let Some(l) = assoc_type_arg.type_bound_list() {
145 l.bounds().map(TypeBound::from_ast).collect()
146 } else {
147 Vec::new()
148 };
149 bindings.push(AssociatedTypeBinding { name, type_ref, bounds });
143 } 150 }
144 } 151 }
145 if args.is_empty() && bindings.is_empty() { 152 if args.is_empty() && bindings.is_empty() {
@@ -168,7 +175,11 @@ fn lower_generic_args_from_fn_path(
168 } 175 }
169 if let Some(ret_type) = ret_type { 176 if let Some(ret_type) = ret_type {
170 let type_ref = TypeRef::from_ast_opt(ret_type.type_ref()); 177 let type_ref = TypeRef::from_ast_opt(ret_type.type_ref());
171 bindings.push((name![Output], type_ref)) 178 bindings.push(AssociatedTypeBinding {
179 name: name![Output],
180 type_ref: Some(type_ref),
181 bounds: Vec::new(),
182 });
172 } 183 }
173 if args.is_empty() && bindings.is_empty() { 184 if args.is_empty() && bindings.is_empty() {
174 None 185 None
diff --git a/crates/ra_hir_def/src/type_ref.rs b/crates/ra_hir_def/src/type_ref.rs
index ea29c4176..f308c6bdf 100644
--- a/crates/ra_hir_def/src/type_ref.rs
+++ b/crates/ra_hir_def/src/type_ref.rs
@@ -163,8 +163,16 @@ impl TypeRef {
163 let crate::path::GenericArg::Type(type_ref) = arg; 163 let crate::path::GenericArg::Type(type_ref) = arg;
164 go(type_ref, f); 164 go(type_ref, f);
165 } 165 }
166 for (_, type_ref) in &args_and_bindings.bindings { 166 for binding in &args_and_bindings.bindings {
167 go(type_ref, f); 167 if let Some(type_ref) = &binding.type_ref {
168 go(type_ref, f);
169 }
170 for bound in &binding.bounds {
171 match bound {
172 TypeBound::Path(path) => go_path(path, f),
173 TypeBound::Error => (),
174 }
175 }
168 } 176 }
169 } 177 }
170 } 178 }
diff --git a/crates/ra_hir_ty/Cargo.toml b/crates/ra_hir_ty/Cargo.toml
index 0003456c1..e891d733f 100644
--- a/crates/ra_hir_ty/Cargo.toml
+++ b/crates/ra_hir_ty/Cargo.toml
@@ -8,6 +8,7 @@ authors = ["rust-analyzer developers"]
8doctest = false 8doctest = false
9 9
10[dependencies] 10[dependencies]
11itertools = "0.9.0"
11arrayvec = "0.5.1" 12arrayvec = "0.5.1"
12smallvec = "1.2.0" 13smallvec = "1.2.0"
13ena = "0.13.1" 14ena = "0.13.1"
diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs
index 6c7bbc448..cc1ac8e3e 100644
--- a/crates/ra_hir_ty/src/lower.rs
+++ b/crates/ra_hir_ty/src/lower.rs
@@ -8,6 +8,8 @@
8use std::iter; 8use std::iter;
9use std::sync::Arc; 9use std::sync::Arc;
10 10
11use smallvec::SmallVec;
12
11use hir_def::{ 13use hir_def::{
12 adt::StructKind, 14 adt::StructKind,
13 builtin_type::BuiltinType, 15 builtin_type::BuiltinType,
@@ -360,13 +362,23 @@ impl Ty {
360 }, 362 },
361 Some(TypeNs::GenericParam(param_id)) => { 363 Some(TypeNs::GenericParam(param_id)) => {
362 let predicates = ctx.db.generic_predicates_for_param(param_id); 364 let predicates = ctx.db.generic_predicates_for_param(param_id);
363 predicates 365 let mut traits_: Vec<_> = predicates
364 .iter() 366 .iter()
365 .filter_map(|pred| match &pred.value { 367 .filter_map(|pred| match &pred.value {
366 GenericPredicate::Implemented(tr) => Some(tr.trait_), 368 GenericPredicate::Implemented(tr) => Some(tr.trait_),
367 _ => None, 369 _ => None,
368 }) 370 })
369 .collect() 371 .collect();
372 // Handle `Self::Type` referring to own associated type in trait definitions
373 if let GenericDefId::TraitId(trait_id) = param_id.parent {
374 let generics = generics(ctx.db.upcast(), trait_id.into());
375 if generics.params.types[param_id.local_id].provenance
376 == TypeParamProvenance::TraitSelf
377 {
378 traits_.push(trait_id);
379 }
380 }
381 traits_
370 } 382 }
371 _ => return Ty::Unknown, 383 _ => return Ty::Unknown,
372 }; 384 };
@@ -596,21 +608,35 @@ fn assoc_type_bindings_from_type_bound<'a>(
596 .into_iter() 608 .into_iter()
597 .flat_map(|segment| segment.args_and_bindings.into_iter()) 609 .flat_map(|segment| segment.args_and_bindings.into_iter())
598 .flat_map(|args_and_bindings| args_and_bindings.bindings.iter()) 610 .flat_map(|args_and_bindings| args_and_bindings.bindings.iter())
599 .map(move |(name, type_ref)| { 611 .flat_map(move |binding| {
600 let associated_ty = associated_type_by_name_including_super_traits( 612 let associated_ty = associated_type_by_name_including_super_traits(
601 ctx.db.upcast(), 613 ctx.db.upcast(),
602 trait_ref.trait_, 614 trait_ref.trait_,
603 &name, 615 &binding.name,
604 ); 616 );
605 let associated_ty = match associated_ty { 617 let associated_ty = match associated_ty {
606 None => return GenericPredicate::Error, 618 None => return SmallVec::<[GenericPredicate; 1]>::new(),
607 Some(t) => t, 619 Some(t) => t,
608 }; 620 };
609 let projection_ty = 621 let projection_ty =
610 ProjectionTy { associated_ty, parameters: trait_ref.substs.clone() }; 622 ProjectionTy { associated_ty, parameters: trait_ref.substs.clone() };
611 let ty = Ty::from_hir(ctx, type_ref); 623 let mut preds = SmallVec::with_capacity(
612 let projection_predicate = ProjectionPredicate { projection_ty, ty }; 624 binding.type_ref.as_ref().map_or(0, |_| 1) + binding.bounds.len(),
613 GenericPredicate::Projection(projection_predicate) 625 );
626 if let Some(type_ref) = &binding.type_ref {
627 let ty = Ty::from_hir(ctx, type_ref);
628 let projection_predicate =
629 ProjectionPredicate { projection_ty: projection_ty.clone(), ty };
630 preds.push(GenericPredicate::Projection(projection_predicate));
631 }
632 for bound in &binding.bounds {
633 preds.extend(GenericPredicate::from_type_bound(
634 ctx,
635 bound,
636 Ty::Projection(projection_ty.clone()),
637 ));
638 }
639 preds
614 }) 640 })
615} 641}
616 642
diff --git a/crates/ra_hir_ty/src/tests/regression.rs b/crates/ra_hir_ty/src/tests/regression.rs
index 3402e0cb5..d69115a2f 100644
--- a/crates/ra_hir_ty/src/tests/regression.rs
+++ b/crates/ra_hir_ty/src/tests/regression.rs
@@ -451,8 +451,7 @@ pub mod str {
451"#, 451"#,
452 ); 452 );
453 453
454 // should be Option<char>, but currently not because of Chalk ambiguity problem 454 assert_eq!("(Option<char>, Option<char>)", super::type_at_pos(&db, pos));
455 assert_eq!("(Option<{unknown}>, Option<{unknown}>)", super::type_at_pos(&db, pos));
456} 455}
457 456
458#[test] 457#[test]
diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs
index 22ae6ca90..81c5e6299 100644
--- a/crates/ra_hir_ty/src/tests/traits.rs
+++ b/crates/ra_hir_ty/src/tests/traits.rs
@@ -1803,7 +1803,7 @@ fn test<T, U>() where T::Item: Trait2, T: Trait<U::Item>, U: Trait<()> {
1803} 1803}
1804 1804
1805#[test] 1805#[test]
1806fn unselected_projection_on_trait_self() { 1806fn unselected_projection_on_impl_self() {
1807 assert_snapshot!(infer( 1807 assert_snapshot!(infer(
1808 r#" 1808 r#"
1809//- /main.rs 1809//- /main.rs
@@ -1844,6 +1844,30 @@ impl Trait for S2 {
1844} 1844}
1845 1845
1846#[test] 1846#[test]
1847fn unselected_projection_on_trait_self() {
1848 let t = type_at(
1849 r#"
1850//- /main.rs
1851trait Trait {
1852 type Item;
1853
1854 fn f(&self) -> Self::Item { loop {} }
1855}
1856
1857struct S;
1858impl Trait for S {
1859 type Item = u32;
1860}
1861
1862fn test() {
1863 S.f()<|>;
1864}
1865"#,
1866 );
1867 assert_eq!(t, "u32");
1868}
1869
1870#[test]
1847fn trait_impl_self_ty() { 1871fn trait_impl_self_ty() {
1848 let t = type_at( 1872 let t = type_at(
1849 r#" 1873 r#"
@@ -1924,6 +1948,53 @@ fn test<T, U>() where T: Trait<U::Item>, U: Trait<T::Item> {
1924} 1948}
1925 1949
1926#[test] 1950#[test]
1951fn inline_assoc_type_bounds_1() {
1952 let t = type_at(
1953 r#"
1954//- /main.rs
1955trait Iterator {
1956 type Item;
1957}
1958trait OtherTrait<T> {
1959 fn foo(&self) -> T;
1960}
1961
1962// workaround for Chalk assoc type normalization problems
1963pub struct S<T>;
1964impl<T: Iterator> Iterator for S<T> {
1965 type Item = <T as Iterator>::Item;
1966}
1967
1968fn test<I: Iterator<Item: OtherTrait<u32>>>() {
1969 let x: <S<I> as Iterator>::Item;
1970 x.foo()<|>;
1971}
1972"#,
1973 );
1974 assert_eq!(t, "u32");
1975}
1976
1977#[test]
1978fn inline_assoc_type_bounds_2() {
1979 let t = type_at(
1980 r#"
1981//- /main.rs
1982trait Iterator {
1983 type Item;
1984}
1985
1986fn test<I: Iterator<Item: Iterator<Item = u32>>>() {
1987 let x: <<I as Iterator>::Item as Iterator>::Item;
1988 x<|>;
1989}
1990"#,
1991 );
1992 // assert_eq!(t, "u32");
1993 // doesn't currently work, Chalk #234
1994 assert_eq!(t, "{unknown}");
1995}
1996
1997#[test]
1927fn unify_impl_trait() { 1998fn unify_impl_trait() {
1928 assert_snapshot!( 1999 assert_snapshot!(
1929 infer_with_mismatches(r#" 2000 infer_with_mismatches(r#"
diff --git a/crates/ra_hir_ty/src/traits/chalk/tls.rs b/crates/ra_hir_ty/src/traits/chalk/tls.rs
index d9bbb54a5..fa8e4d1ad 100644
--- a/crates/ra_hir_ty/src/traits/chalk/tls.rs
+++ b/crates/ra_hir_ty/src/traits/chalk/tls.rs
@@ -2,10 +2,11 @@
2use std::fmt; 2use std::fmt;
3 3
4use chalk_ir::{AliasTy, Goal, Goals, Lifetime, Parameter, ProgramClauseImplication, TypeName}; 4use chalk_ir::{AliasTy, Goal, Goals, Lifetime, Parameter, ProgramClauseImplication, TypeName};
5use itertools::Itertools;
5 6
6use super::{from_chalk, Interner}; 7use super::{from_chalk, Interner};
7use crate::{db::HirDatabase, CallableDef, TypeCtor}; 8use crate::{db::HirDatabase, CallableDef, TypeCtor};
8use hir_def::{AdtId, AssocContainerId, Lookup, TypeAliasId}; 9use hir_def::{AdtId, AssocContainerId, DefWithBodyId, Lookup, TypeAliasId};
9 10
10pub use unsafe_tls::{set_current_program, with_current_program}; 11pub use unsafe_tls::{set_current_program, with_current_program};
11 12
@@ -69,7 +70,27 @@ impl DebugContext<'_> {
69 write!(f, "{}::{}", trait_name, name)?; 70 write!(f, "{}::{}", trait_name, name)?;
70 } 71 }
71 TypeCtor::Closure { def, expr } => { 72 TypeCtor::Closure { def, expr } => {
72 write!(f, "{{closure {:?} in {:?}}}", expr.into_raw(), def)?; 73 write!(f, "{{closure {:?} in ", expr.into_raw())?;
74 match def {
75 DefWithBodyId::FunctionId(func) => {
76 write!(f, "fn {}", self.0.function_data(func).name)?
77 }
78 DefWithBodyId::StaticId(s) => {
79 if let Some(name) = self.0.static_data(s).name.as_ref() {
80 write!(f, "body of static {}", name)?;
81 } else {
82 write!(f, "body of unnamed static {:?}", s)?;
83 }
84 }
85 DefWithBodyId::ConstId(c) => {
86 if let Some(name) = self.0.const_data(c).name.as_ref() {
87 write!(f, "body of const {}", name)?;
88 } else {
89 write!(f, "body of unnamed const {:?}", c)?;
90 }
91 }
92 };
93 write!(f, "}}")?;
73 } 94 }
74 } 95 }
75 Ok(()) 96 Ok(())
@@ -113,14 +134,15 @@ impl DebugContext<'_> {
113 }; 134 };
114 let trait_data = self.0.trait_data(trait_); 135 let trait_data = self.0.trait_data(trait_);
115 let params = alias.substitution.parameters(&Interner); 136 let params = alias.substitution.parameters(&Interner);
116 write!( 137 write!(fmt, "<{:?} as {}", &params[0], trait_data.name,)?;
117 fmt, 138 if params.len() > 1 {
118 "<{:?} as {}<{:?}>>::{}", 139 write!(
119 &params[0], 140 fmt,
120 trait_data.name, 141 "<{}>",
121 &params[1..], 142 &params[1..].iter().format_with(", ", |x, f| f(&format_args!("{:?}", x))),
122 type_alias_data.name 143 )?;
123 ) 144 }
145 write!(fmt, ">::{}", type_alias_data.name)
124 } 146 }
125 147
126 pub fn debug_ty( 148 pub fn debug_ty(