aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_ty/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir_ty/src')
-rw-r--r--crates/ra_hir_ty/src/_match.rs68
-rw-r--r--crates/ra_hir_ty/src/db.rs7
-rw-r--r--crates/ra_hir_ty/src/diagnostics.rs32
-rw-r--r--crates/ra_hir_ty/src/display.rs239
-rw-r--r--crates/ra_hir_ty/src/infer.rs159
-rw-r--r--crates/ra_hir_ty/src/infer/coerce.rs34
-rw-r--r--crates/ra_hir_ty/src/infer/expr.rs194
-rw-r--r--crates/ra_hir_ty/src/infer/pat.rs4
-rw-r--r--crates/ra_hir_ty/src/infer/path.rs35
-rw-r--r--crates/ra_hir_ty/src/infer/unify.rs8
-rw-r--r--crates/ra_hir_ty/src/lib.rs56
-rw-r--r--crates/ra_hir_ty/src/lower.rs2
-rw-r--r--crates/ra_hir_ty/src/marks.rs11
-rw-r--r--crates/ra_hir_ty/src/method_resolution.rs12
-rw-r--r--crates/ra_hir_ty/src/op.rs3
-rw-r--r--crates/ra_hir_ty/src/tests.rs62
-rw-r--r--crates/ra_hir_ty/src/tests/coercion.rs67
-rw-r--r--crates/ra_hir_ty/src/tests/display_source_code.rs50
-rw-r--r--crates/ra_hir_ty/src/tests/macros.rs72
-rw-r--r--crates/ra_hir_ty/src/tests/method_resolution.rs46
-rw-r--r--crates/ra_hir_ty/src/tests/never_type.rs177
-rw-r--r--crates/ra_hir_ty/src/tests/patterns.rs93
-rw-r--r--crates/ra_hir_ty/src/tests/regression.rs75
-rw-r--r--crates/ra_hir_ty/src/tests/simple.rs258
-rw-r--r--crates/ra_hir_ty/src/tests/traits.rs374
-rw-r--r--crates/ra_hir_ty/src/traits/builtin.rs3
-rw-r--r--crates/ra_hir_ty/src/traits/chalk.rs944
-rw-r--r--crates/ra_hir_ty/src/traits/chalk/interner.rs353
-rw-r--r--crates/ra_hir_ty/src/traits/chalk/mapping.rs701
-rw-r--r--crates/ra_hir_ty/src/traits/chalk/tls.rs83
30 files changed, 3128 insertions, 1094 deletions
diff --git a/crates/ra_hir_ty/src/_match.rs b/crates/ra_hir_ty/src/_match.rs
index 779e78574..3e6e1e333 100644
--- a/crates/ra_hir_ty/src/_match.rs
+++ b/crates/ra_hir_ty/src/_match.rs
@@ -573,14 +573,20 @@ pub(crate) fn is_useful(
573 matrix: &Matrix, 573 matrix: &Matrix,
574 v: &PatStack, 574 v: &PatStack,
575) -> MatchCheckResult<Usefulness> { 575) -> MatchCheckResult<Usefulness> {
576 // Handle the special case of enums with no variants. In that case, no match 576 // Handle two special cases:
577 // arm is useful. 577 // - enum with no variants
578 if let Ty::Apply(ApplicationTy { ctor: TypeCtor::Adt(AdtId::EnumId(enum_id)), .. }) = 578 // - `!` type
579 cx.infer[cx.match_expr].strip_references() 579 // In those cases, no match arm is useful.
580 { 580 match cx.infer[cx.match_expr].strip_references() {
581 if cx.db.enum_data(*enum_id).variants.is_empty() { 581 Ty::Apply(ApplicationTy { ctor: TypeCtor::Adt(AdtId::EnumId(enum_id)), .. }) => {
582 if cx.db.enum_data(*enum_id).variants.is_empty() {
583 return Ok(Usefulness::NotUseful);
584 }
585 }
586 Ty::Apply(ApplicationTy { ctor: TypeCtor::Never, .. }) => {
582 return Ok(Usefulness::NotUseful); 587 return Ok(Usefulness::NotUseful);
583 } 588 }
589 _ => (),
584 } 590 }
585 591
586 if v.is_empty() { 592 if v.is_empty() {
@@ -1918,6 +1924,17 @@ mod tests {
1918 } 1924 }
1919 1925
1920 #[test] 1926 #[test]
1927 fn type_never() {
1928 let content = r"
1929 fn test_fn(never: !) {
1930 match never {}
1931 }
1932 ";
1933
1934 check_no_diagnostic(content);
1935 }
1936
1937 #[test]
1921 fn enum_never_ref() { 1938 fn enum_never_ref() {
1922 let content = r" 1939 let content = r"
1923 enum Never {} 1940 enum Never {}
@@ -1929,6 +1946,23 @@ mod tests {
1929 1946
1930 check_no_diagnostic(content); 1947 check_no_diagnostic(content);
1931 } 1948 }
1949
1950 #[test]
1951 fn expr_diverges_missing_arm() {
1952 let content = r"
1953 enum Either {
1954 A,
1955 B,
1956 }
1957 fn test_fn() {
1958 match loop {} {
1959 Either::A => (),
1960 }
1961 }
1962 ";
1963
1964 check_no_diagnostic(content);
1965 }
1932} 1966}
1933 1967
1934#[cfg(test)] 1968#[cfg(test)]
@@ -1981,26 +2015,6 @@ mod false_negatives {
1981 } 2015 }
1982 2016
1983 #[test] 2017 #[test]
1984 fn expr_diverges_missing_arm() {
1985 let content = r"
1986 enum Either {
1987 A,
1988 B,
1989 }
1990 fn test_fn() {
1991 match loop {} {
1992 Either::A => (),
1993 }
1994 }
1995 ";
1996
1997 // This is a false negative.
1998 // Even though the match expression diverges, rustc fails
1999 // to compile here since `Either::B` is missing.
2000 check_no_diagnostic(content);
2001 }
2002
2003 #[test]
2004 fn expr_loop_missing_arm() { 2018 fn expr_loop_missing_arm() {
2005 let content = r" 2019 let content = r"
2006 enum Either { 2020 enum Either {
@@ -2018,7 +2032,7 @@ mod false_negatives {
2018 // We currently infer the type of `loop { break Foo::A }` to `!`, which 2032 // We currently infer the type of `loop { break Foo::A }` to `!`, which
2019 // causes us to skip the diagnostic since `Either::A` doesn't type check 2033 // causes us to skip the diagnostic since `Either::A` doesn't type check
2020 // with `!`. 2034 // with `!`.
2021 check_no_diagnostic(content); 2035 check_diagnostic(content);
2022 } 2036 }
2023 2037
2024 #[test] 2038 #[test]
diff --git a/crates/ra_hir_ty/src/db.rs b/crates/ra_hir_ty/src/db.rs
index fdb49560b..0a8bb24ac 100644
--- a/crates/ra_hir_ty/src/db.rs
+++ b/crates/ra_hir_ty/src/db.rs
@@ -76,6 +76,8 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
76 #[salsa::interned] 76 #[salsa::interned]
77 fn intern_type_ctor(&self, type_ctor: TypeCtor) -> crate::TypeCtorId; 77 fn intern_type_ctor(&self, type_ctor: TypeCtor) -> crate::TypeCtorId;
78 #[salsa::interned] 78 #[salsa::interned]
79 fn intern_callable_def(&self, callable_def: CallableDef) -> crate::CallableDefId;
80 #[salsa::interned]
79 fn intern_type_param_id(&self, param_id: TypeParamId) -> GlobalTypeParamId; 81 fn intern_type_param_id(&self, param_id: TypeParamId) -> GlobalTypeParamId;
80 #[salsa::interned] 82 #[salsa::interned]
81 fn intern_chalk_impl(&self, impl_: Impl) -> crate::traits::GlobalImplId; 83 fn intern_chalk_impl(&self, impl_: Impl) -> crate::traits::GlobalImplId;
@@ -89,11 +91,14 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
89 fn trait_datum(&self, krate: CrateId, trait_id: chalk::TraitId) -> Arc<chalk::TraitDatum>; 91 fn trait_datum(&self, krate: CrateId, trait_id: chalk::TraitId) -> Arc<chalk::TraitDatum>;
90 92
91 #[salsa::invoke(chalk::struct_datum_query)] 93 #[salsa::invoke(chalk::struct_datum_query)]
92 fn struct_datum(&self, krate: CrateId, struct_id: chalk::StructId) -> Arc<chalk::StructDatum>; 94 fn struct_datum(&self, krate: CrateId, struct_id: chalk::AdtId) -> Arc<chalk::StructDatum>;
93 95
94 #[salsa::invoke(crate::traits::chalk::impl_datum_query)] 96 #[salsa::invoke(crate::traits::chalk::impl_datum_query)]
95 fn impl_datum(&self, krate: CrateId, impl_id: chalk::ImplId) -> Arc<chalk::ImplDatum>; 97 fn impl_datum(&self, krate: CrateId, impl_id: chalk::ImplId) -> Arc<chalk::ImplDatum>;
96 98
99 #[salsa::invoke(crate::traits::chalk::fn_def_datum_query)]
100 fn fn_def_datum(&self, krate: CrateId, fn_def_id: chalk::FnDefId) -> Arc<chalk::FnDefDatum>;
101
97 #[salsa::invoke(crate::traits::chalk::associated_ty_value_query)] 102 #[salsa::invoke(crate::traits::chalk::associated_ty_value_query)]
98 fn associated_ty_value( 103 fn associated_ty_value(
99 &self, 104 &self,
diff --git a/crates/ra_hir_ty/src/diagnostics.rs b/crates/ra_hir_ty/src/diagnostics.rs
index c8fd54861..2c7298714 100644
--- a/crates/ra_hir_ty/src/diagnostics.rs
+++ b/crates/ra_hir_ty/src/diagnostics.rs
@@ -40,7 +40,7 @@ impl Diagnostic for MissingFields {
40 fn message(&self) -> String { 40 fn message(&self) -> String {
41 let mut buf = String::from("Missing structure fields:\n"); 41 let mut buf = String::from("Missing structure fields:\n");
42 for field in &self.missed_fields { 42 for field in &self.missed_fields {
43 format_to!(buf, "- {}", field); 43 format_to!(buf, "- {}\n", field);
44 } 44 }
45 buf 45 buf
46 } 46 }
@@ -73,7 +73,7 @@ impl Diagnostic for MissingPatFields {
73 fn message(&self) -> String { 73 fn message(&self) -> String {
74 let mut buf = String::from("Missing structure fields:\n"); 74 let mut buf = String::from("Missing structure fields:\n");
75 for field in &self.missed_fields { 75 for field in &self.missed_fields {
76 format_to!(buf, "- {}", field); 76 format_to!(buf, "- {}\n", field);
77 } 77 }
78 buf 78 buf
79 } 79 }
@@ -131,3 +131,31 @@ impl AstDiagnostic for MissingOkInTailExpr {
131 ast::Expr::cast(node).unwrap() 131 ast::Expr::cast(node).unwrap()
132 } 132 }
133} 133}
134
135#[derive(Debug)]
136pub struct BreakOutsideOfLoop {
137 pub file: HirFileId,
138 pub expr: AstPtr<ast::Expr>,
139}
140
141impl Diagnostic for BreakOutsideOfLoop {
142 fn message(&self) -> String {
143 "break outside of loop".to_string()
144 }
145 fn source(&self) -> InFile<SyntaxNodePtr> {
146 InFile { file_id: self.file, value: self.expr.clone().into() }
147 }
148 fn as_any(&self) -> &(dyn Any + Send + 'static) {
149 self
150 }
151}
152
153impl AstDiagnostic for BreakOutsideOfLoop {
154 type AST = ast::Expr;
155
156 fn ast(&self, db: &impl AstDatabase) -> Self::AST {
157 let root = db.parse_or_expand(self.file).unwrap();
158 let node = self.source().value.to_node(&root);
159 ast::Expr::cast(node).unwrap()
160 }
161}
diff --git a/crates/ra_hir_ty/src/display.rs b/crates/ra_hir_ty/src/display.rs
index d03bbd5a7..b9c4d2e89 100644
--- a/crates/ra_hir_ty/src/display.rs
+++ b/crates/ra_hir_ty/src/display.rs
@@ -6,28 +6,42 @@ use crate::{
6 db::HirDatabase, utils::generics, ApplicationTy, CallableDef, FnSig, GenericPredicate, 6 db::HirDatabase, utils::generics, ApplicationTy, CallableDef, FnSig, GenericPredicate,
7 Obligation, ProjectionTy, Substs, TraitRef, Ty, TypeCtor, 7 Obligation, ProjectionTy, Substs, TraitRef, Ty, TypeCtor,
8}; 8};
9use hir_def::{generics::TypeParamProvenance, AdtId, AssocContainerId, Lookup}; 9use hir_def::{
10 find_path, generics::TypeParamProvenance, item_scope::ItemInNs, AdtId, AssocContainerId,
11 Lookup, ModuleId,
12};
10use hir_expand::name::Name; 13use hir_expand::name::Name;
11 14
12pub struct HirFormatter<'a, 'b> { 15pub struct HirFormatter<'a> {
13 pub db: &'a dyn HirDatabase, 16 pub db: &'a dyn HirDatabase,
14 fmt: &'a mut fmt::Formatter<'b>, 17 fmt: &'a mut dyn fmt::Write,
15 buf: String, 18 buf: String,
16 curr_size: usize, 19 curr_size: usize,
17 pub(crate) max_size: Option<usize>, 20 pub(crate) max_size: Option<usize>,
18 omit_verbose_types: bool, 21 omit_verbose_types: bool,
22 display_target: DisplayTarget,
19} 23}
20 24
21pub trait HirDisplay { 25pub trait HirDisplay {
22 fn hir_fmt(&self, f: &mut HirFormatter) -> fmt::Result; 26 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError>;
23 27
28 /// Returns a `Display`able type that is human-readable.
29 /// Use this for showing types to the user (e.g. diagnostics)
24 fn display<'a>(&'a self, db: &'a dyn HirDatabase) -> HirDisplayWrapper<'a, Self> 30 fn display<'a>(&'a self, db: &'a dyn HirDatabase) -> HirDisplayWrapper<'a, Self>
25 where 31 where
26 Self: Sized, 32 Self: Sized,
27 { 33 {
28 HirDisplayWrapper(db, self, None, false) 34 HirDisplayWrapper {
35 db,
36 t: self,
37 max_size: None,
38 omit_verbose_types: false,
39 display_target: DisplayTarget::Diagnostics,
40 }
29 } 41 }
30 42
43 /// Returns a `Display`able type that is human-readable and tries to be succinct.
44 /// Use this for showing types to the user where space is constrained (e.g. doc popups)
31 fn display_truncated<'a>( 45 fn display_truncated<'a>(
32 &'a self, 46 &'a self,
33 db: &'a dyn HirDatabase, 47 db: &'a dyn HirDatabase,
@@ -36,16 +50,46 @@ pub trait HirDisplay {
36 where 50 where
37 Self: Sized, 51 Self: Sized,
38 { 52 {
39 HirDisplayWrapper(db, self, max_size, true) 53 HirDisplayWrapper {
54 db,
55 t: self,
56 max_size,
57 omit_verbose_types: true,
58 display_target: DisplayTarget::Diagnostics,
59 }
60 }
61
62 /// Returns a String representation of `self` that can be inserted into the given module.
63 /// Use this when generating code (e.g. assists)
64 fn display_source_code<'a>(
65 &'a self,
66 db: &'a dyn HirDatabase,
67 module_id: ModuleId,
68 ) -> Result<String, DisplaySourceCodeError> {
69 let mut result = String::new();
70 match self.hir_fmt(&mut HirFormatter {
71 db,
72 fmt: &mut result,
73 buf: String::with_capacity(20),
74 curr_size: 0,
75 max_size: None,
76 omit_verbose_types: false,
77 display_target: DisplayTarget::SourceCode { module_id },
78 }) {
79 Ok(()) => {}
80 Err(HirDisplayError::FmtError) => panic!("Writing to String can't fail!"),
81 Err(HirDisplayError::DisplaySourceCodeError(e)) => return Err(e),
82 };
83 Ok(result)
40 } 84 }
41} 85}
42 86
43impl<'a, 'b> HirFormatter<'a, 'b> { 87impl<'a> HirFormatter<'a> {
44 pub fn write_joined<T: HirDisplay>( 88 pub fn write_joined<T: HirDisplay>(
45 &mut self, 89 &mut self,
46 iter: impl IntoIterator<Item = T>, 90 iter: impl IntoIterator<Item = T>,
47 sep: &str, 91 sep: &str,
48 ) -> fmt::Result { 92 ) -> Result<(), HirDisplayError> {
49 let mut first = true; 93 let mut first = true;
50 for e in iter { 94 for e in iter {
51 if !first { 95 if !first {
@@ -58,14 +102,14 @@ impl<'a, 'b> HirFormatter<'a, 'b> {
58 } 102 }
59 103
60 /// This allows using the `write!` macro directly with a `HirFormatter`. 104 /// This allows using the `write!` macro directly with a `HirFormatter`.
61 pub fn write_fmt(&mut self, args: fmt::Arguments) -> fmt::Result { 105 pub fn write_fmt(&mut self, args: fmt::Arguments) -> Result<(), HirDisplayError> {
62 // We write to a buffer first to track output size 106 // We write to a buffer first to track output size
63 self.buf.clear(); 107 self.buf.clear();
64 fmt::write(&mut self.buf, args)?; 108 fmt::write(&mut self.buf, args)?;
65 self.curr_size += self.buf.len(); 109 self.curr_size += self.buf.len();
66 110
67 // Then we write to the internal formatter from the buffer 111 // Then we write to the internal formatter from the buffer
68 self.fmt.write_str(&self.buf) 112 self.fmt.write_str(&self.buf).map_err(HirDisplayError::from)
69 } 113 }
70 114
71 pub fn should_truncate(&self) -> bool { 115 pub fn should_truncate(&self) -> bool {
@@ -81,34 +125,82 @@ impl<'a, 'b> HirFormatter<'a, 'b> {
81 } 125 }
82} 126}
83 127
84pub struct HirDisplayWrapper<'a, T>(&'a dyn HirDatabase, &'a T, Option<usize>, bool); 128#[derive(Clone, Copy)]
129enum DisplayTarget {
130 /// Display types for inlays, doc popups, autocompletion, etc...
131 /// Showing `{unknown}` or not qualifying paths is fine here.
132 /// There's no reason for this to fail.
133 Diagnostics,
134 /// Display types for inserting them in source files.
135 /// The generated code should compile, so paths need to be qualified.
136 SourceCode { module_id: ModuleId },
137}
138
139impl DisplayTarget {
140 fn is_source_code(&self) -> bool {
141 matches!(self, Self::SourceCode {..})
142 }
143}
144
145#[derive(Debug)]
146pub enum DisplaySourceCodeError {
147 PathNotFound,
148}
149
150pub enum HirDisplayError {
151 /// Errors that can occur when generating source code
152 DisplaySourceCodeError(DisplaySourceCodeError),
153 /// `FmtError` is required to be compatible with std::fmt::Display
154 FmtError,
155}
156impl From<fmt::Error> for HirDisplayError {
157 fn from(_: fmt::Error) -> Self {
158 Self::FmtError
159 }
160}
161
162pub struct HirDisplayWrapper<'a, T> {
163 db: &'a dyn HirDatabase,
164 t: &'a T,
165 max_size: Option<usize>,
166 omit_verbose_types: bool,
167 display_target: DisplayTarget,
168}
85 169
86impl<'a, T> fmt::Display for HirDisplayWrapper<'a, T> 170impl<'a, T> fmt::Display for HirDisplayWrapper<'a, T>
87where 171where
88 T: HirDisplay, 172 T: HirDisplay,
89{ 173{
90 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 174 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
91 self.1.hir_fmt(&mut HirFormatter { 175 match self.t.hir_fmt(&mut HirFormatter {
92 db: self.0, 176 db: self.db,
93 fmt: f, 177 fmt: f,
94 buf: String::with_capacity(20), 178 buf: String::with_capacity(20),
95 curr_size: 0, 179 curr_size: 0,
96 max_size: self.2, 180 max_size: self.max_size,
97 omit_verbose_types: self.3, 181 omit_verbose_types: self.omit_verbose_types,
98 }) 182 display_target: self.display_target,
183 }) {
184 Ok(()) => Ok(()),
185 Err(HirDisplayError::FmtError) => Err(fmt::Error),
186 Err(HirDisplayError::DisplaySourceCodeError(_)) => {
187 // This should never happen
188 panic!("HirDisplay failed when calling Display::fmt!")
189 }
190 }
99 } 191 }
100} 192}
101 193
102const TYPE_HINT_TRUNCATION: &str = "…"; 194const TYPE_HINT_TRUNCATION: &str = "…";
103 195
104impl HirDisplay for &Ty { 196impl HirDisplay for &Ty {
105 fn hir_fmt(&self, f: &mut HirFormatter) -> fmt::Result { 197 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
106 HirDisplay::hir_fmt(*self, f) 198 HirDisplay::hir_fmt(*self, f)
107 } 199 }
108} 200}
109 201
110impl HirDisplay for ApplicationTy { 202impl HirDisplay for ApplicationTy {
111 fn hir_fmt(&self, f: &mut HirFormatter) -> fmt::Result { 203 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
112 if f.should_truncate() { 204 if f.should_truncate() {
113 return write!(f, "{}", TYPE_HINT_TRUNCATION); 205 return write!(f, "{}", TYPE_HINT_TRUNCATION);
114 } 206 }
@@ -191,45 +283,66 @@ impl HirDisplay for ApplicationTy {
191 } 283 }
192 } 284 }
193 TypeCtor::Adt(def_id) => { 285 TypeCtor::Adt(def_id) => {
194 let name = match def_id { 286 match f.display_target {
195 AdtId::StructId(it) => f.db.struct_data(it).name.clone(), 287 DisplayTarget::Diagnostics => {
196 AdtId::UnionId(it) => f.db.union_data(it).name.clone(), 288 let name = match def_id {
197 AdtId::EnumId(it) => f.db.enum_data(it).name.clone(), 289 AdtId::StructId(it) => f.db.struct_data(it).name.clone(),
198 }; 290 AdtId::UnionId(it) => f.db.union_data(it).name.clone(),
199 write!(f, "{}", name)?; 291 AdtId::EnumId(it) => f.db.enum_data(it).name.clone(),
292 };
293 write!(f, "{}", name)?;
294 }
295 DisplayTarget::SourceCode { module_id } => {
296 if let Some(path) = find_path::find_path(
297 f.db.upcast(),
298 ItemInNs::Types(def_id.into()),
299 module_id,
300 ) {
301 write!(f, "{}", path)?;
302 } else {
303 return Err(HirDisplayError::DisplaySourceCodeError(
304 DisplaySourceCodeError::PathNotFound,
305 ));
306 }
307 }
308 }
309
200 if self.parameters.len() > 0 { 310 if self.parameters.len() > 0 {
201 let mut non_default_parameters = Vec::with_capacity(self.parameters.len()); 311 let mut non_default_parameters = Vec::with_capacity(self.parameters.len());
202 let parameters_to_write = if f.omit_verbose_types() { 312 let parameters_to_write =
203 match self 313 if f.display_target.is_source_code() || f.omit_verbose_types() {
204 .ctor 314 match self
205 .as_generic_def() 315 .ctor
206 .map(|generic_def_id| f.db.generic_defaults(generic_def_id)) 316 .as_generic_def()
207 .filter(|defaults| !defaults.is_empty()) 317 .map(|generic_def_id| f.db.generic_defaults(generic_def_id))
208 { 318 .filter(|defaults| !defaults.is_empty())
209 None => self.parameters.0.as_ref(), 319 {
210 Some(default_parameters) => { 320 None => self.parameters.0.as_ref(),
211 for (i, parameter) in self.parameters.iter().enumerate() { 321 Some(default_parameters) => {
212 match (parameter, default_parameters.get(i)) { 322 for (i, parameter) in self.parameters.iter().enumerate() {
213 (&Ty::Unknown, _) | (_, None) => { 323 match (parameter, default_parameters.get(i)) {
214 non_default_parameters.push(parameter.clone()) 324 (&Ty::Unknown, _) | (_, None) => {
325 non_default_parameters.push(parameter.clone())
326 }
327 (_, Some(default_parameter))
328 if parameter != default_parameter =>
329 {
330 non_default_parameters.push(parameter.clone())
331 }
332 _ => (),
215 } 333 }
216 (_, Some(default_parameter))
217 if parameter != default_parameter =>
218 {
219 non_default_parameters.push(parameter.clone())
220 }
221 _ => (),
222 } 334 }
335 &non_default_parameters
223 } 336 }
224 &non_default_parameters
225 } 337 }
226 } 338 } else {
227 } else { 339 self.parameters.0.as_ref()
228 self.parameters.0.as_ref() 340 };
229 }; 341 if !parameters_to_write.is_empty() {
230 write!(f, "<")?; 342 write!(f, "<")?;
231 f.write_joined(parameters_to_write, ", ")?; 343 f.write_joined(parameters_to_write, ", ")?;
232 write!(f, ">")?; 344 write!(f, ">")?;
345 }
233 } 346 }
234 } 347 }
235 TypeCtor::AssociatedType(type_alias) => { 348 TypeCtor::AssociatedType(type_alias) => {
@@ -269,7 +382,7 @@ impl HirDisplay for ApplicationTy {
269} 382}
270 383
271impl HirDisplay for ProjectionTy { 384impl HirDisplay for ProjectionTy {
272 fn hir_fmt(&self, f: &mut HirFormatter) -> fmt::Result { 385 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
273 if f.should_truncate() { 386 if f.should_truncate() {
274 return write!(f, "{}", TYPE_HINT_TRUNCATION); 387 return write!(f, "{}", TYPE_HINT_TRUNCATION);
275 } 388 }
@@ -287,7 +400,7 @@ impl HirDisplay for ProjectionTy {
287} 400}
288 401
289impl HirDisplay for Ty { 402impl HirDisplay for Ty {
290 fn hir_fmt(&self, f: &mut HirFormatter) -> fmt::Result { 403 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
291 if f.should_truncate() { 404 if f.should_truncate() {
292 return write!(f, "{}", TYPE_HINT_TRUNCATION); 405 return write!(f, "{}", TYPE_HINT_TRUNCATION);
293 } 406 }
@@ -332,7 +445,7 @@ impl HirDisplay for Ty {
332fn write_bounds_like_dyn_trait( 445fn write_bounds_like_dyn_trait(
333 predicates: &[GenericPredicate], 446 predicates: &[GenericPredicate],
334 f: &mut HirFormatter, 447 f: &mut HirFormatter,
335) -> fmt::Result { 448) -> Result<(), HirDisplayError> {
336 // Note: This code is written to produce nice results (i.e. 449 // Note: This code is written to produce nice results (i.e.
337 // corresponding to surface Rust) for types that can occur in 450 // corresponding to surface Rust) for types that can occur in
338 // actual Rust. It will have weird results if the predicates 451 // actual Rust. It will have weird results if the predicates
@@ -394,7 +507,7 @@ fn write_bounds_like_dyn_trait(
394} 507}
395 508
396impl TraitRef { 509impl TraitRef {
397 fn hir_fmt_ext(&self, f: &mut HirFormatter, use_as: bool) -> fmt::Result { 510 fn hir_fmt_ext(&self, f: &mut HirFormatter, use_as: bool) -> Result<(), HirDisplayError> {
398 if f.should_truncate() { 511 if f.should_truncate() {
399 return write!(f, "{}", TYPE_HINT_TRUNCATION); 512 return write!(f, "{}", TYPE_HINT_TRUNCATION);
400 } 513 }
@@ -416,19 +529,19 @@ impl TraitRef {
416} 529}
417 530
418impl HirDisplay for TraitRef { 531impl HirDisplay for TraitRef {
419 fn hir_fmt(&self, f: &mut HirFormatter) -> fmt::Result { 532 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
420 self.hir_fmt_ext(f, false) 533 self.hir_fmt_ext(f, false)
421 } 534 }
422} 535}
423 536
424impl HirDisplay for &GenericPredicate { 537impl HirDisplay for &GenericPredicate {
425 fn hir_fmt(&self, f: &mut HirFormatter) -> fmt::Result { 538 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
426 HirDisplay::hir_fmt(*self, f) 539 HirDisplay::hir_fmt(*self, f)
427 } 540 }
428} 541}
429 542
430impl HirDisplay for GenericPredicate { 543impl HirDisplay for GenericPredicate {
431 fn hir_fmt(&self, f: &mut HirFormatter) -> fmt::Result { 544 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
432 if f.should_truncate() { 545 if f.should_truncate() {
433 return write!(f, "{}", TYPE_HINT_TRUNCATION); 546 return write!(f, "{}", TYPE_HINT_TRUNCATION);
434 } 547 }
@@ -452,15 +565,15 @@ impl HirDisplay for GenericPredicate {
452} 565}
453 566
454impl HirDisplay for Obligation { 567impl HirDisplay for Obligation {
455 fn hir_fmt(&self, f: &mut HirFormatter) -> fmt::Result { 568 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
456 match self { 569 Ok(match self {
457 Obligation::Trait(tr) => write!(f, "Implements({})", tr.display(f.db)), 570 Obligation::Trait(tr) => write!(f, "Implements({})", tr.display(f.db))?,
458 Obligation::Projection(proj) => write!( 571 Obligation::Projection(proj) => write!(
459 f, 572 f,
460 "Normalize({} => {})", 573 "Normalize({} => {})",
461 proj.projection_ty.display(f.db), 574 proj.projection_ty.display(f.db),
462 proj.ty.display(f.db) 575 proj.ty.display(f.db)
463 ), 576 )?,
464 } 577 })
465 } 578 }
466} 579}
diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs
index bd4ef69a0..dc77e88e5 100644
--- a/crates/ra_hir_ty/src/infer.rs
+++ b/crates/ra_hir_ty/src/infer.rs
@@ -22,13 +22,14 @@ use rustc_hash::FxHashMap;
22 22
23use hir_def::{ 23use hir_def::{
24 body::Body, 24 body::Body,
25 data::{ConstData, FunctionData}, 25 data::{ConstData, FunctionData, StaticData},
26 expr::{BindingAnnotation, ExprId, PatId}, 26 expr::{BindingAnnotation, ExprId, PatId},
27 lang_item::LangItemTarget, 27 lang_item::LangItemTarget,
28 path::{path, Path}, 28 path::{path, Path},
29 resolver::{HasResolver, Resolver, TypeNs}, 29 resolver::{HasResolver, Resolver, TypeNs},
30 type_ref::{Mutability, TypeRef}, 30 type_ref::{Mutability, TypeRef},
31 AdtId, AssocItemId, DefWithBodyId, FieldId, FunctionId, TraitId, TypeAliasId, VariantId, 31 AdtId, AssocItemId, DefWithBodyId, EnumVariantId, FieldId, FunctionId, TraitId, TypeAliasId,
32 VariantId,
32}; 33};
33use hir_expand::{diagnostics::DiagnosticSink, name::name}; 34use hir_expand::{diagnostics::DiagnosticSink, name::name};
34use ra_arena::map::ArenaMap; 35use ra_arena::map::ArenaMap;
@@ -71,7 +72,7 @@ pub(crate) fn infer_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc<Infer
71 match def { 72 match def {
72 DefWithBodyId::ConstId(c) => ctx.collect_const(&db.const_data(c)), 73 DefWithBodyId::ConstId(c) => ctx.collect_const(&db.const_data(c)),
73 DefWithBodyId::FunctionId(f) => ctx.collect_fn(&db.function_data(f)), 74 DefWithBodyId::FunctionId(f) => ctx.collect_fn(&db.function_data(f)),
74 DefWithBodyId::StaticId(s) => ctx.collect_const(&db.static_data(s)), 75 DefWithBodyId::StaticId(s) => ctx.collect_static(&db.static_data(s)),
75 } 76 }
76 77
77 ctx.infer_body(); 78 ctx.infer_body();
@@ -210,6 +211,25 @@ struct InferenceContext<'a> {
210 /// closures, but currently this is the only field that will change there, 211 /// closures, but currently this is the only field that will change there,
211 /// so it doesn't make sense. 212 /// so it doesn't make sense.
212 return_ty: Ty, 213 return_ty: Ty,
214 diverges: Diverges,
215 breakables: Vec<BreakableContext>,
216}
217
218#[derive(Clone, Debug)]
219struct BreakableContext {
220 pub may_break: bool,
221 pub break_ty: Ty,
222 pub label: Option<name::Name>,
223}
224
225fn find_breakable<'c>(
226 ctxs: &'c mut [BreakableContext],
227 label: Option<&name::Name>,
228) -> Option<&'c mut BreakableContext> {
229 match label {
230 Some(_) => ctxs.iter_mut().rev().find(|ctx| ctx.label.as_ref() == label),
231 None => ctxs.last_mut(),
232 }
213} 233}
214 234
215impl<'a> InferenceContext<'a> { 235impl<'a> InferenceContext<'a> {
@@ -224,6 +244,8 @@ impl<'a> InferenceContext<'a> {
224 owner, 244 owner,
225 body: db.body(owner), 245 body: db.body(owner),
226 resolver, 246 resolver,
247 diverges: Diverges::Maybe,
248 breakables: Vec::new(),
227 } 249 }
228 } 250 }
229 251
@@ -429,43 +451,95 @@ impl<'a> InferenceContext<'a> {
429 let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver); 451 let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver);
430 // FIXME: this should resolve assoc items as well, see this example: 452 // FIXME: this should resolve assoc items as well, see this example:
431 // https://play.rust-lang.org/?gist=087992e9e22495446c01c0d4e2d69521 453 // https://play.rust-lang.org/?gist=087992e9e22495446c01c0d4e2d69521
432 return match resolver.resolve_path_in_type_ns_fully(self.db.upcast(), path.mod_path()) { 454 let (resolution, unresolved) =
433 Some(TypeNs::AdtId(AdtId::StructId(strukt))) => { 455 match resolver.resolve_path_in_type_ns(self.db.upcast(), path.mod_path()) {
456 Some(it) => it,
457 None => return (Ty::Unknown, None),
458 };
459 return match resolution {
460 TypeNs::AdtId(AdtId::StructId(strukt)) => {
434 let substs = Ty::substs_from_path(&ctx, path, strukt.into()); 461 let substs = Ty::substs_from_path(&ctx, path, strukt.into());
435 let ty = self.db.ty(strukt.into()); 462 let ty = self.db.ty(strukt.into());
436 let ty = self.insert_type_vars(ty.subst(&substs)); 463 let ty = self.insert_type_vars(ty.subst(&substs));
437 (ty, Some(strukt.into())) 464 forbid_unresolved_segments((ty, Some(strukt.into())), unresolved)
438 } 465 }
439 Some(TypeNs::EnumVariantId(var)) => { 466 TypeNs::EnumVariantId(var) => {
440 let substs = Ty::substs_from_path(&ctx, path, var.into()); 467 let substs = Ty::substs_from_path(&ctx, path, var.into());
441 let ty = self.db.ty(var.parent.into()); 468 let ty = self.db.ty(var.parent.into());
442 let ty = self.insert_type_vars(ty.subst(&substs)); 469 let ty = self.insert_type_vars(ty.subst(&substs));
443 (ty, Some(var.into())) 470 forbid_unresolved_segments((ty, Some(var.into())), unresolved)
444 } 471 }
445 Some(TypeNs::SelfType(impl_id)) => { 472 TypeNs::SelfType(impl_id) => {
446 let generics = crate::utils::generics(self.db.upcast(), impl_id.into()); 473 let generics = crate::utils::generics(self.db.upcast(), impl_id.into());
447 let substs = Substs::type_params_for_generics(&generics); 474 let substs = Substs::type_params_for_generics(&generics);
448 let ty = self.db.impl_self_ty(impl_id).subst(&substs); 475 let ty = self.db.impl_self_ty(impl_id).subst(&substs);
449 let variant = ty_variant(&ty); 476 match unresolved {
450 (ty, variant) 477 None => {
478 let variant = ty_variant(&ty);
479 (ty, variant)
480 }
481 Some(1) => {
482 let segment = path.mod_path().segments.last().unwrap();
483 // this could be an enum variant or associated type
484 if let Some((AdtId::EnumId(enum_id), _)) = ty.as_adt() {
485 let enum_data = self.db.enum_data(enum_id);
486 if let Some(local_id) = enum_data.variant(segment) {
487 let variant = EnumVariantId { parent: enum_id, local_id };
488 return (ty, Some(variant.into()));
489 }
490 }
491 // FIXME potentially resolve assoc type
492 (Ty::Unknown, None)
493 }
494 Some(_) => {
495 // FIXME diagnostic
496 (Ty::Unknown, None)
497 }
498 }
451 } 499 }
452 Some(TypeNs::TypeAliasId(it)) => { 500 TypeNs::TypeAliasId(it) => {
453 let substs = Substs::build_for_def(self.db, it) 501 let substs = Substs::build_for_def(self.db, it)
454 .fill(std::iter::repeat_with(|| self.table.new_type_var())) 502 .fill(std::iter::repeat_with(|| self.table.new_type_var()))
455 .build(); 503 .build();
456 let ty = self.db.ty(it.into()).subst(&substs); 504 let ty = self.db.ty(it.into()).subst(&substs);
457 let variant = ty_variant(&ty); 505 let variant = ty_variant(&ty);
458 (ty, variant) 506 forbid_unresolved_segments((ty, variant), unresolved)
507 }
508 TypeNs::AdtSelfType(_) => {
509 // FIXME this could happen in array size expressions, once we're checking them
510 (Ty::Unknown, None)
511 }
512 TypeNs::GenericParam(_) => {
513 // FIXME potentially resolve assoc type
514 (Ty::Unknown, None)
515 }
516 TypeNs::AdtId(AdtId::EnumId(_))
517 | TypeNs::AdtId(AdtId::UnionId(_))
518 | TypeNs::BuiltinType(_)
519 | TypeNs::TraitId(_) => {
520 // FIXME diagnostic
521 (Ty::Unknown, None)
459 } 522 }
460 Some(_) | None => (Ty::Unknown, None),
461 }; 523 };
462 524
525 fn forbid_unresolved_segments(
526 result: (Ty, Option<VariantId>),
527 unresolved: Option<usize>,
528 ) -> (Ty, Option<VariantId>) {
529 if unresolved.is_none() {
530 result
531 } else {
532 // FIXME diagnostic
533 (Ty::Unknown, None)
534 }
535 }
536
463 fn ty_variant(ty: &Ty) -> Option<VariantId> { 537 fn ty_variant(ty: &Ty) -> Option<VariantId> {
464 ty.as_adt().and_then(|(adt_id, _)| match adt_id { 538 ty.as_adt().and_then(|(adt_id, _)| match adt_id {
465 AdtId::StructId(s) => Some(VariantId::StructId(s)), 539 AdtId::StructId(s) => Some(VariantId::StructId(s)),
466 AdtId::UnionId(u) => Some(VariantId::UnionId(u)), 540 AdtId::UnionId(u) => Some(VariantId::UnionId(u)),
467 AdtId::EnumId(_) => { 541 AdtId::EnumId(_) => {
468 // Error E0071, expected struct, variant or union type, found enum `Foo` 542 // FIXME Error E0071, expected struct, variant or union type, found enum `Foo`
469 None 543 None
470 } 544 }
471 }) 545 })
@@ -476,6 +550,10 @@ impl<'a> InferenceContext<'a> {
476 self.return_ty = self.make_ty(&data.type_ref); 550 self.return_ty = self.make_ty(&data.type_ref);
477 } 551 }
478 552
553 fn collect_static(&mut self, data: &StaticData) {
554 self.return_ty = self.make_ty(&data.type_ref);
555 }
556
479 fn collect_fn(&mut self, data: &FunctionData) { 557 fn collect_fn(&mut self, data: &FunctionData) {
480 let body = Arc::clone(&self.body); // avoid borrow checker problem 558 let body = Arc::clone(&self.body); // avoid borrow checker problem
481 let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver) 559 let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver)
@@ -666,15 +744,57 @@ impl Expectation {
666 } 744 }
667} 745}
668 746
747#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
748enum Diverges {
749 Maybe,
750 Always,
751}
752
753impl Diverges {
754 fn is_always(self) -> bool {
755 self == Diverges::Always
756 }
757}
758
759impl std::ops::BitAnd for Diverges {
760 type Output = Self;
761 fn bitand(self, other: Self) -> Self {
762 std::cmp::min(self, other)
763 }
764}
765
766impl std::ops::BitOr for Diverges {
767 type Output = Self;
768 fn bitor(self, other: Self) -> Self {
769 std::cmp::max(self, other)
770 }
771}
772
773impl std::ops::BitAndAssign for Diverges {
774 fn bitand_assign(&mut self, other: Self) {
775 *self = *self & other;
776 }
777}
778
779impl std::ops::BitOrAssign for Diverges {
780 fn bitor_assign(&mut self, other: Self) {
781 *self = *self | other;
782 }
783}
784
669mod diagnostics { 785mod diagnostics {
670 use hir_def::{expr::ExprId, FunctionId}; 786 use hir_def::{expr::ExprId, FunctionId};
671 use hir_expand::diagnostics::DiagnosticSink; 787 use hir_expand::diagnostics::DiagnosticSink;
672 788
673 use crate::{db::HirDatabase, diagnostics::NoSuchField}; 789 use crate::{
790 db::HirDatabase,
791 diagnostics::{BreakOutsideOfLoop, NoSuchField},
792 };
674 793
675 #[derive(Debug, PartialEq, Eq, Clone)] 794 #[derive(Debug, PartialEq, Eq, Clone)]
676 pub(super) enum InferenceDiagnostic { 795 pub(super) enum InferenceDiagnostic {
677 NoSuchField { expr: ExprId, field: usize }, 796 NoSuchField { expr: ExprId, field: usize },
797 BreakOutsideOfLoop { expr: ExprId },
678 } 798 }
679 799
680 impl InferenceDiagnostic { 800 impl InferenceDiagnostic {
@@ -690,6 +810,13 @@ mod diagnostics {
690 let field = source_map.field_syntax(*expr, *field); 810 let field = source_map.field_syntax(*expr, *field);
691 sink.push(NoSuchField { file: field.file_id, field: field.value }) 811 sink.push(NoSuchField { file: field.file_id, field: field.value })
692 } 812 }
813 InferenceDiagnostic::BreakOutsideOfLoop { expr } => {
814 let (_, source_map) = db.body_with_source_map(owner.into());
815 let ptr = source_map
816 .expr_syntax(*expr)
817 .expect("break outside of loop in synthetic syntax");
818 sink.push(BreakOutsideOfLoop { file: ptr.file_id, expr: ptr.value })
819 }
693 } 820 }
694 } 821 }
695 } 822 }
diff --git a/crates/ra_hir_ty/src/infer/coerce.rs b/crates/ra_hir_ty/src/infer/coerce.rs
index 89200255a..32c7c57cd 100644
--- a/crates/ra_hir_ty/src/infer/coerce.rs
+++ b/crates/ra_hir_ty/src/infer/coerce.rs
@@ -5,7 +5,7 @@
5//! See: https://doc.rust-lang.org/nomicon/coercions.html 5//! See: https://doc.rust-lang.org/nomicon/coercions.html
6 6
7use hir_def::{lang_item::LangItemTarget, type_ref::Mutability}; 7use hir_def::{lang_item::LangItemTarget, type_ref::Mutability};
8use test_utils::tested_by; 8use test_utils::mark;
9 9
10use crate::{autoderef, traits::Solution, Obligation, Substs, TraitRef, Ty, TypeCtor}; 10use crate::{autoderef, traits::Solution, Obligation, Substs, TraitRef, Ty, TypeCtor};
11 11
@@ -20,21 +20,33 @@ impl<'a> InferenceContext<'a> {
20 self.coerce_inner(from_ty, &to_ty) 20 self.coerce_inner(from_ty, &to_ty)
21 } 21 }
22 22
23 /// Merge two types from different branches, with possible implicit coerce. 23 /// Merge two types from different branches, with possible coercion.
24 /// 24 ///
25 /// Note that it is only possible that one type are coerced to another. 25 /// Mostly this means trying to coerce one to the other, but
26 /// Coercing both types to another least upper bound type is not possible in rustc, 26 /// - if we have two function types for different functions, we need to
27 /// which will simply result in "incompatible types" error. 27 /// coerce both to function pointers;
28 /// - if we were concerned with lifetime subtyping, we'd need to look for a
29 /// least upper bound.
28 pub(super) fn coerce_merge_branch(&mut self, ty1: &Ty, ty2: &Ty) -> Ty { 30 pub(super) fn coerce_merge_branch(&mut self, ty1: &Ty, ty2: &Ty) -> Ty {
29 if self.coerce(ty1, ty2) { 31 if self.coerce(ty1, ty2) {
30 ty2.clone() 32 ty2.clone()
31 } else if self.coerce(ty2, ty1) { 33 } else if self.coerce(ty2, ty1) {
32 ty1.clone() 34 ty1.clone()
33 } else { 35 } else {
34 tested_by!(coerce_merge_fail_fallback); 36 if let (ty_app!(TypeCtor::FnDef(_)), ty_app!(TypeCtor::FnDef(_))) = (ty1, ty2) {
35 // For incompatible types, we use the latter one as result 37 mark::hit!(coerce_fn_reification);
36 // to be better recovery for `if` without `else`. 38 // Special case: two function types. Try to coerce both to
37 ty2.clone() 39 // pointers to have a chance at getting a match. See
40 // https://github.com/rust-lang/rust/blob/7b805396bf46dce972692a6846ce2ad8481c5f85/src/librustc_typeck/check/coercion.rs#L877-L916
41 let sig1 = ty1.callable_sig(self.db).expect("FnDef without callable sig");
42 let sig2 = ty2.callable_sig(self.db).expect("FnDef without callable sig");
43 let ptr_ty1 = Ty::fn_ptr(sig1);
44 let ptr_ty2 = Ty::fn_ptr(sig2);
45 self.coerce_merge_branch(&ptr_ty1, &ptr_ty2)
46 } else {
47 mark::hit!(coerce_merge_fail_fallback);
48 ty1.clone()
49 }
38 } 50 }
39 } 51 }
40 52
@@ -84,9 +96,7 @@ impl<'a> InferenceContext<'a> {
84 match from_ty.callable_sig(self.db) { 96 match from_ty.callable_sig(self.db) {
85 None => return false, 97 None => return false,
86 Some(sig) => { 98 Some(sig) => {
87 let num_args = sig.params_and_return.len() as u16 - 1; 99 from_ty = Ty::fn_ptr(sig);
88 from_ty =
89 Ty::apply(TypeCtor::FnPtr { num_args }, Substs(sig.params_and_return));
90 } 100 }
91 } 101 }
92 } 102 }
diff --git a/crates/ra_hir_ty/src/infer/expr.rs b/crates/ra_hir_ty/src/infer/expr.rs
index efc60986b..4a98e2deb 100644
--- a/crates/ra_hir_ty/src/infer/expr.rs
+++ b/crates/ra_hir_ty/src/infer/expr.rs
@@ -1,7 +1,7 @@
1//! Type inference for expressions. 1//! Type inference for expressions.
2 2
3use std::iter::{repeat, repeat_with}; 3use std::iter::{repeat, repeat_with};
4use std::sync::Arc; 4use std::{mem, sync::Arc};
5 5
6use hir_def::{ 6use hir_def::{
7 builtin_type::Signedness, 7 builtin_type::Signedness,
@@ -17,15 +17,22 @@ use crate::{
17 autoderef, method_resolution, op, 17 autoderef, method_resolution, op,
18 traits::InEnvironment, 18 traits::InEnvironment,
19 utils::{generics, variant_data, Generics}, 19 utils::{generics, variant_data, Generics},
20 ApplicationTy, Binders, CallableDef, InferTy, IntTy, Mutability, Obligation, Substs, TraitRef, 20 ApplicationTy, Binders, CallableDef, InferTy, IntTy, Mutability, Obligation, Rawness, Substs,
21 Ty, TypeCtor, Uncertain, 21 TraitRef, Ty, TypeCtor, Uncertain,
22}; 22};
23 23
24use super::{BindingMode, Expectation, InferenceContext, InferenceDiagnostic, TypeMismatch}; 24use super::{
25 find_breakable, BindingMode, BreakableContext, Diverges, Expectation, InferenceContext,
26 InferenceDiagnostic, TypeMismatch,
27};
25 28
26impl<'a> InferenceContext<'a> { 29impl<'a> InferenceContext<'a> {
27 pub(super) fn infer_expr(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty { 30 pub(super) fn infer_expr(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty {
28 let ty = self.infer_expr_inner(tgt_expr, expected); 31 let ty = self.infer_expr_inner(tgt_expr, expected);
32 if ty.is_never() {
33 // Any expression that produces a value of type `!` must have diverged
34 self.diverges = Diverges::Always;
35 }
29 let could_unify = self.unify(&ty, &expected.ty); 36 let could_unify = self.unify(&ty, &expected.ty);
30 if !could_unify { 37 if !could_unify {
31 self.result.type_mismatches.insert( 38 self.result.type_mismatches.insert(
@@ -64,34 +71,80 @@ impl<'a> InferenceContext<'a> {
64 // if let is desugared to match, so this is always simple if 71 // if let is desugared to match, so this is always simple if
65 self.infer_expr(*condition, &Expectation::has_type(Ty::simple(TypeCtor::Bool))); 72 self.infer_expr(*condition, &Expectation::has_type(Ty::simple(TypeCtor::Bool)));
66 73
74 let condition_diverges = mem::replace(&mut self.diverges, Diverges::Maybe);
75 let mut both_arms_diverge = Diverges::Always;
76
67 let then_ty = self.infer_expr_inner(*then_branch, &expected); 77 let then_ty = self.infer_expr_inner(*then_branch, &expected);
78 both_arms_diverge &= mem::replace(&mut self.diverges, Diverges::Maybe);
68 let else_ty = match else_branch { 79 let else_ty = match else_branch {
69 Some(else_branch) => self.infer_expr_inner(*else_branch, &expected), 80 Some(else_branch) => self.infer_expr_inner(*else_branch, &expected),
70 None => Ty::unit(), 81 None => Ty::unit(),
71 }; 82 };
83 both_arms_diverge &= self.diverges;
84
85 self.diverges = condition_diverges | both_arms_diverge;
72 86
73 self.coerce_merge_branch(&then_ty, &else_ty) 87 self.coerce_merge_branch(&then_ty, &else_ty)
74 } 88 }
75 Expr::Block { statements, tail } => self.infer_block(statements, *tail, expected), 89 Expr::Block { statements, tail, .. } => {
76 Expr::Loop { body } => { 90 // FIXME: Breakable block inference
91 self.infer_block(statements, *tail, expected)
92 }
93 Expr::TryBlock { body } => {
94 let _inner = self.infer_expr(*body, expected);
95 // FIXME should be std::result::Result<{inner}, _>
96 Ty::Unknown
97 }
98 Expr::Loop { body, label } => {
99 self.breakables.push(BreakableContext {
100 may_break: false,
101 break_ty: self.table.new_type_var(),
102 label: label.clone(),
103 });
77 self.infer_expr(*body, &Expectation::has_type(Ty::unit())); 104 self.infer_expr(*body, &Expectation::has_type(Ty::unit()));
78 // FIXME handle break with value 105
79 Ty::simple(TypeCtor::Never) 106 let ctxt = self.breakables.pop().expect("breakable stack broken");
107 if ctxt.may_break {
108 self.diverges = Diverges::Maybe;
109 }
110
111 if ctxt.may_break {
112 ctxt.break_ty
113 } else {
114 Ty::simple(TypeCtor::Never)
115 }
80 } 116 }
81 Expr::While { condition, body } => { 117 Expr::While { condition, body, label } => {
118 self.breakables.push(BreakableContext {
119 may_break: false,
120 break_ty: Ty::Unknown,
121 label: label.clone(),
122 });
82 // while let is desugared to a match loop, so this is always simple while 123 // while let is desugared to a match loop, so this is always simple while
83 self.infer_expr(*condition, &Expectation::has_type(Ty::simple(TypeCtor::Bool))); 124 self.infer_expr(*condition, &Expectation::has_type(Ty::simple(TypeCtor::Bool)));
84 self.infer_expr(*body, &Expectation::has_type(Ty::unit())); 125 self.infer_expr(*body, &Expectation::has_type(Ty::unit()));
126 let _ctxt = self.breakables.pop().expect("breakable stack broken");
127 // the body may not run, so it diverging doesn't mean we diverge
128 self.diverges = Diverges::Maybe;
85 Ty::unit() 129 Ty::unit()
86 } 130 }
87 Expr::For { iterable, body, pat } => { 131 Expr::For { iterable, body, pat, label } => {
88 let iterable_ty = self.infer_expr(*iterable, &Expectation::none()); 132 let iterable_ty = self.infer_expr(*iterable, &Expectation::none());
89 133
134 self.breakables.push(BreakableContext {
135 may_break: false,
136 break_ty: Ty::Unknown,
137 label: label.clone(),
138 });
90 let pat_ty = 139 let pat_ty =
91 self.resolve_associated_type(iterable_ty, self.resolve_into_iter_item()); 140 self.resolve_associated_type(iterable_ty, self.resolve_into_iter_item());
92 141
93 self.infer_pat(*pat, &pat_ty, BindingMode::default()); 142 self.infer_pat(*pat, &pat_ty, BindingMode::default());
143
94 self.infer_expr(*body, &Expectation::has_type(Ty::unit())); 144 self.infer_expr(*body, &Expectation::has_type(Ty::unit()));
145 let _ctxt = self.breakables.pop().expect("breakable stack broken");
146 // the body may not run, so it diverging doesn't mean we diverge
147 self.diverges = Diverges::Maybe;
95 Ty::unit() 148 Ty::unit()
96 } 149 }
97 Expr::Lambda { body, args, ret_type, arg_types } => { 150 Expr::Lambda { body, args, ret_type, arg_types } => {
@@ -99,13 +152,13 @@ impl<'a> InferenceContext<'a> {
99 152
100 let mut sig_tys = Vec::new(); 153 let mut sig_tys = Vec::new();
101 154
102 for (arg_pat, arg_type) in args.iter().zip(arg_types.iter()) { 155 // collect explicitly written argument types
103 let expected = if let Some(type_ref) = arg_type { 156 for arg_type in arg_types.iter() {
157 let arg_ty = if let Some(type_ref) = arg_type {
104 self.make_ty(type_ref) 158 self.make_ty(type_ref)
105 } else { 159 } else {
106 Ty::Unknown 160 self.table.new_type_var()
107 }; 161 };
108 let arg_ty = self.infer_pat(*arg_pat, &expected, BindingMode::default());
109 sig_tys.push(arg_ty); 162 sig_tys.push(arg_ty);
110 } 163 }
111 164
@@ -117,7 +170,7 @@ impl<'a> InferenceContext<'a> {
117 sig_tys.push(ret_ty.clone()); 170 sig_tys.push(ret_ty.clone());
118 let sig_ty = Ty::apply( 171 let sig_ty = Ty::apply(
119 TypeCtor::FnPtr { num_args: sig_tys.len() as u16 - 1 }, 172 TypeCtor::FnPtr { num_args: sig_tys.len() as u16 - 1 },
120 Substs(sig_tys.into()), 173 Substs(sig_tys.clone().into()),
121 ); 174 );
122 let closure_ty = 175 let closure_ty =
123 Ty::apply_one(TypeCtor::Closure { def: self.owner, expr: tgt_expr }, sig_ty); 176 Ty::apply_one(TypeCtor::Closure { def: self.owner, expr: tgt_expr }, sig_ty);
@@ -127,10 +180,18 @@ impl<'a> InferenceContext<'a> {
127 // infer the body. 180 // infer the body.
128 self.coerce(&closure_ty, &expected.ty); 181 self.coerce(&closure_ty, &expected.ty);
129 182
130 let prev_ret_ty = std::mem::replace(&mut self.return_ty, ret_ty.clone()); 183 // Now go through the argument patterns
184 for (arg_pat, arg_ty) in args.iter().zip(sig_tys) {
185 let resolved = self.resolve_ty_as_possible(arg_ty);
186 self.infer_pat(*arg_pat, &resolved, BindingMode::default());
187 }
188
189 let prev_diverges = mem::replace(&mut self.diverges, Diverges::Maybe);
190 let prev_ret_ty = mem::replace(&mut self.return_ty, ret_ty.clone());
131 191
132 self.infer_expr_coerce(*body, &Expectation::has_type(ret_ty)); 192 self.infer_expr_coerce(*body, &Expectation::has_type(ret_ty));
133 193
194 self.diverges = prev_diverges;
134 self.return_ty = prev_ret_ty; 195 self.return_ty = prev_ret_ty;
135 196
136 closure_ty 197 closure_ty
@@ -160,7 +221,11 @@ impl<'a> InferenceContext<'a> {
160 self.table.new_type_var() 221 self.table.new_type_var()
161 }; 222 };
162 223
224 let matchee_diverges = self.diverges;
225 let mut all_arms_diverge = Diverges::Always;
226
163 for arm in arms { 227 for arm in arms {
228 self.diverges = Diverges::Maybe;
164 let _pat_ty = self.infer_pat(arm.pat, &input_ty, BindingMode::default()); 229 let _pat_ty = self.infer_pat(arm.pat, &input_ty, BindingMode::default());
165 if let Some(guard_expr) = arm.guard { 230 if let Some(guard_expr) = arm.guard {
166 self.infer_expr( 231 self.infer_expr(
@@ -170,9 +235,12 @@ impl<'a> InferenceContext<'a> {
170 } 235 }
171 236
172 let arm_ty = self.infer_expr_inner(arm.expr, &expected); 237 let arm_ty = self.infer_expr_inner(arm.expr, &expected);
238 all_arms_diverge &= self.diverges;
173 result_ty = self.coerce_merge_branch(&result_ty, &arm_ty); 239 result_ty = self.coerce_merge_branch(&result_ty, &arm_ty);
174 } 240 }
175 241
242 self.diverges = matchee_diverges | all_arms_diverge;
243
176 result_ty 244 result_ty
177 } 245 }
178 Expr::Path(p) => { 246 Expr::Path(p) => {
@@ -180,12 +248,32 @@ impl<'a> InferenceContext<'a> {
180 let resolver = resolver_for_expr(self.db.upcast(), self.owner, tgt_expr); 248 let resolver = resolver_for_expr(self.db.upcast(), self.owner, tgt_expr);
181 self.infer_path(&resolver, p, tgt_expr.into()).unwrap_or(Ty::Unknown) 249 self.infer_path(&resolver, p, tgt_expr.into()).unwrap_or(Ty::Unknown)
182 } 250 }
183 Expr::Continue => Ty::simple(TypeCtor::Never), 251 Expr::Continue { .. } => Ty::simple(TypeCtor::Never),
184 Expr::Break { expr } => { 252 Expr::Break { expr, label } => {
185 if let Some(expr) = expr { 253 let val_ty = if let Some(expr) = expr {
186 // FIXME handle break with value 254 self.infer_expr(*expr, &Expectation::none())
187 self.infer_expr(*expr, &Expectation::none()); 255 } else {
256 Ty::unit()
257 };
258
259 let last_ty =
260 if let Some(ctxt) = find_breakable(&mut self.breakables, label.as_ref()) {
261 ctxt.break_ty.clone()
262 } else {
263 Ty::Unknown
264 };
265
266 let merged_type = self.coerce_merge_branch(&last_ty, &val_ty);
267
268 if let Some(ctxt) = find_breakable(&mut self.breakables, label.as_ref()) {
269 ctxt.break_ty = merged_type;
270 ctxt.may_break = true;
271 } else {
272 self.push_diagnostic(InferenceDiagnostic::BreakOutsideOfLoop {
273 expr: tgt_expr,
274 });
188 } 275 }
276
189 Ty::simple(TypeCtor::Never) 277 Ty::simple(TypeCtor::Never)
190 } 278 }
191 Expr::Return { expr } => { 279 Expr::Return { expr } => {
@@ -281,19 +369,28 @@ impl<'a> InferenceContext<'a> {
281 // FIXME check the cast... 369 // FIXME check the cast...
282 cast_ty 370 cast_ty
283 } 371 }
284 Expr::Ref { expr, mutability } => { 372 Expr::Ref { expr, rawness, mutability } => {
285 let expectation = 373 let expectation = if let Some((exp_inner, exp_rawness, exp_mutability)) =
286 if let Some((exp_inner, exp_mutability)) = &expected.ty.as_reference() { 374 &expected.ty.as_reference_or_ptr()
287 if *exp_mutability == Mutability::Mut && *mutability == Mutability::Shared { 375 {
288 // FIXME: throw type error - expected mut reference but found shared ref, 376 if *exp_mutability == Mutability::Mut && *mutability == Mutability::Shared {
289 // which cannot be coerced 377 // FIXME: throw type error - expected mut reference but found shared ref,
290 } 378 // which cannot be coerced
291 Expectation::rvalue_hint(Ty::clone(exp_inner)) 379 }
292 } else { 380 if *exp_rawness == Rawness::Ref && *rawness == Rawness::RawPtr {
293 Expectation::none() 381 // FIXME: throw type error - expected reference but found ptr,
294 }; 382 // which cannot be coerced
383 }
384 Expectation::rvalue_hint(Ty::clone(exp_inner))
385 } else {
386 Expectation::none()
387 };
295 let inner_ty = self.infer_expr_inner(*expr, &expectation); 388 let inner_ty = self.infer_expr_inner(*expr, &expectation);
296 Ty::apply_one(TypeCtor::Ref(*mutability), inner_ty) 389 let ty = match rawness {
390 Rawness::RawPtr => TypeCtor::RawPtr(*mutability),
391 Rawness::Ref => TypeCtor::Ref(*mutability),
392 };
393 Ty::apply_one(ty, inner_ty)
297 } 394 }
298 Expr::Box { expr } => { 395 Expr::Box { expr } => {
299 let inner_ty = self.infer_expr_inner(*expr, &Expectation::none()); 396 let inner_ty = self.infer_expr_inner(*expr, &Expectation::none());
@@ -496,8 +593,8 @@ impl<'a> InferenceContext<'a> {
496 } 593 }
497 Literal::ByteString(..) => { 594 Literal::ByteString(..) => {
498 let byte_type = Ty::simple(TypeCtor::Int(Uncertain::Known(IntTy::u8()))); 595 let byte_type = Ty::simple(TypeCtor::Int(Uncertain::Known(IntTy::u8())));
499 let slice_type = Ty::apply_one(TypeCtor::Slice, byte_type); 596 let array_type = Ty::apply_one(TypeCtor::Array, byte_type);
500 Ty::apply_one(TypeCtor::Ref(Mutability::Shared), slice_type) 597 Ty::apply_one(TypeCtor::Ref(Mutability::Shared), array_type)
501 } 598 }
502 Literal::Char(..) => Ty::simple(TypeCtor::Char), 599 Literal::Char(..) => Ty::simple(TypeCtor::Char),
503 Literal::Int(_v, ty) => Ty::simple(TypeCtor::Int((*ty).into())), 600 Literal::Int(_v, ty) => Ty::simple(TypeCtor::Int((*ty).into())),
@@ -517,7 +614,6 @@ impl<'a> InferenceContext<'a> {
517 tail: Option<ExprId>, 614 tail: Option<ExprId>,
518 expected: &Expectation, 615 expected: &Expectation,
519 ) -> Ty { 616 ) -> Ty {
520 let mut diverges = false;
521 for stmt in statements { 617 for stmt in statements {
522 match stmt { 618 match stmt {
523 Statement::Let { pat, type_ref, initializer } => { 619 Statement::Let { pat, type_ref, initializer } => {
@@ -539,9 +635,7 @@ impl<'a> InferenceContext<'a> {
539 self.infer_pat(*pat, &ty, BindingMode::default()); 635 self.infer_pat(*pat, &ty, BindingMode::default());
540 } 636 }
541 Statement::Expr(expr) => { 637 Statement::Expr(expr) => {
542 if let ty_app!(TypeCtor::Never) = self.infer_expr(*expr, &Expectation::none()) { 638 self.infer_expr(*expr, &Expectation::none());
543 diverges = true;
544 }
545 } 639 }
546 } 640 }
547 } 641 }
@@ -549,14 +643,22 @@ impl<'a> InferenceContext<'a> {
549 let ty = if let Some(expr) = tail { 643 let ty = if let Some(expr) = tail {
550 self.infer_expr_coerce(expr, expected) 644 self.infer_expr_coerce(expr, expected)
551 } else { 645 } else {
552 self.coerce(&Ty::unit(), expected.coercion_target()); 646 // Citing rustc: if there is no explicit tail expression,
553 Ty::unit() 647 // that is typically equivalent to a tail expression
648 // of `()` -- except if the block diverges. In that
649 // case, there is no value supplied from the tail
650 // expression (assuming there are no other breaks,
651 // this implies that the type of the block will be
652 // `!`).
653 if self.diverges.is_always() {
654 // we don't even make an attempt at coercion
655 self.table.new_maybe_never_type_var()
656 } else {
657 self.coerce(&Ty::unit(), expected.coercion_target());
658 Ty::unit()
659 }
554 }; 660 };
555 if diverges { 661 ty
556 Ty::simple(TypeCtor::Never)
557 } else {
558 ty
559 }
560 } 662 }
561 663
562 fn infer_method_call( 664 fn infer_method_call(
diff --git a/crates/ra_hir_ty/src/infer/pat.rs b/crates/ra_hir_ty/src/infer/pat.rs
index 54ec870df..4006f595d 100644
--- a/crates/ra_hir_ty/src/infer/pat.rs
+++ b/crates/ra_hir_ty/src/infer/pat.rs
@@ -10,7 +10,7 @@ use hir_def::{
10 FieldId, 10 FieldId,
11}; 11};
12use hir_expand::name::Name; 12use hir_expand::name::Name;
13use test_utils::tested_by; 13use test_utils::mark;
14 14
15use super::{BindingMode, Expectation, InferenceContext}; 15use super::{BindingMode, Expectation, InferenceContext};
16use crate::{utils::variant_data, Substs, Ty, TypeCtor}; 16use crate::{utils::variant_data, Substs, Ty, TypeCtor};
@@ -111,7 +111,7 @@ impl<'a> InferenceContext<'a> {
111 } 111 }
112 } 112 }
113 } else if let Pat::Ref { .. } = &body[pat] { 113 } else if let Pat::Ref { .. } = &body[pat] {
114 tested_by!(match_ergonomics_ref); 114 mark::hit!(match_ergonomics_ref);
115 // When you encounter a `&pat` pattern, reset to Move. 115 // When you encounter a `&pat` pattern, reset to Move.
116 // This is so that `w` is by value: `let (_, &w) = &(1, &2);` 116 // This is so that `w` is by value: `let (_, &w) = &(1, &2);`
117 default_bm = BindingMode::Move; 117 default_bm = BindingMode::Move;
diff --git a/crates/ra_hir_ty/src/infer/path.rs b/crates/ra_hir_ty/src/infer/path.rs
index 2b6bc0f79..1c2e56fb0 100644
--- a/crates/ra_hir_ty/src/infer/path.rs
+++ b/crates/ra_hir_ty/src/infer/path.rs
@@ -5,7 +5,7 @@ use std::iter;
5use hir_def::{ 5use hir_def::{
6 path::{Path, PathSegment}, 6 path::{Path, PathSegment},
7 resolver::{ResolveValueResult, Resolver, TypeNs, ValueNs}, 7 resolver::{ResolveValueResult, Resolver, TypeNs, ValueNs},
8 AssocContainerId, AssocItemId, Lookup, 8 AdtId, AssocContainerId, AssocItemId, EnumVariantId, Lookup,
9}; 9};
10use hir_expand::name::Name; 10use hir_expand::name::Name;
11 11
@@ -77,6 +77,18 @@ impl<'a> InferenceContext<'a> {
77 77
78 it.into() 78 it.into()
79 } 79 }
80 ValueNs::ImplSelf(impl_id) => {
81 let generics = crate::utils::generics(self.db.upcast(), impl_id.into());
82 let substs = Substs::type_params_for_generics(&generics);
83 let ty = self.db.impl_self_ty(impl_id).subst(&substs);
84 if let Some((AdtId::StructId(struct_id), _)) = ty.as_adt() {
85 let ty = self.db.value_ty(struct_id.into()).subst(&substs);
86 return Some(ty);
87 } else {
88 // FIXME: diagnostic, invalid Self reference
89 return None;
90 }
91 }
80 }; 92 };
81 93
82 let ty = self.db.value_ty(typable); 94 let ty = self.db.value_ty(typable);
@@ -199,6 +211,10 @@ impl<'a> InferenceContext<'a> {
199 return None; 211 return None;
200 } 212 }
201 213
214 if let Some(result) = self.resolve_enum_variant_on_ty(&ty, name, id) {
215 return Some(result);
216 }
217
202 let canonical_ty = self.canonicalizer().canonicalize_ty(ty.clone()); 218 let canonical_ty = self.canonicalizer().canonicalize_ty(ty.clone());
203 let krate = self.resolver.krate()?; 219 let krate = self.resolver.krate()?;
204 let traits_in_scope = self.resolver.traits_in_scope(self.db.upcast()); 220 let traits_in_scope = self.resolver.traits_in_scope(self.db.upcast());
@@ -250,4 +266,21 @@ impl<'a> InferenceContext<'a> {
250 }, 266 },
251 ) 267 )
252 } 268 }
269
270 fn resolve_enum_variant_on_ty(
271 &mut self,
272 ty: &Ty,
273 name: &Name,
274 id: ExprOrPatId,
275 ) -> Option<(ValueNs, Option<Substs>)> {
276 let (enum_id, subst) = match ty.as_adt() {
277 Some((AdtId::EnumId(e), subst)) => (e, subst),
278 _ => return None,
279 };
280 let enum_data = self.db.enum_data(enum_id);
281 let local_id = enum_data.variant(name)?;
282 let variant = EnumVariantId { parent: enum_id, local_id };
283 self.write_variant_resolution(id, variant.into());
284 Some((ValueNs::EnumVariantId(variant), Some(subst.clone())))
285 }
253} 286}
diff --git a/crates/ra_hir_ty/src/infer/unify.rs b/crates/ra_hir_ty/src/infer/unify.rs
index ab0bc8b70..269495ca0 100644
--- a/crates/ra_hir_ty/src/infer/unify.rs
+++ b/crates/ra_hir_ty/src/infer/unify.rs
@@ -4,7 +4,7 @@ use std::borrow::Cow;
4 4
5use ena::unify::{InPlaceUnificationTable, NoError, UnifyKey, UnifyValue}; 5use ena::unify::{InPlaceUnificationTable, NoError, UnifyKey, UnifyValue};
6 6
7use test_utils::tested_by; 7use test_utils::mark;
8 8
9use super::{InferenceContext, Obligation}; 9use super::{InferenceContext, Obligation};
10use crate::{ 10use crate::{
@@ -313,7 +313,7 @@ impl InferenceTable {
313 // more than once 313 // more than once
314 for i in 0..3 { 314 for i in 0..3 {
315 if i > 0 { 315 if i > 0 {
316 tested_by!(type_var_resolves_to_int_var); 316 mark::hit!(type_var_resolves_to_int_var);
317 } 317 }
318 match &*ty { 318 match &*ty {
319 Ty::Infer(tv) => { 319 Ty::Infer(tv) => {
@@ -342,7 +342,7 @@ impl InferenceTable {
342 Ty::Infer(tv) => { 342 Ty::Infer(tv) => {
343 let inner = tv.to_inner(); 343 let inner = tv.to_inner();
344 if tv_stack.contains(&inner) { 344 if tv_stack.contains(&inner) {
345 tested_by!(type_var_cycles_resolve_as_possible); 345 mark::hit!(type_var_cycles_resolve_as_possible);
346 // recursive type 346 // recursive type
347 return tv.fallback_value(); 347 return tv.fallback_value();
348 } 348 }
@@ -369,7 +369,7 @@ impl InferenceTable {
369 Ty::Infer(tv) => { 369 Ty::Infer(tv) => {
370 let inner = tv.to_inner(); 370 let inner = tv.to_inner();
371 if tv_stack.contains(&inner) { 371 if tv_stack.contains(&inner) {
372 tested_by!(type_var_cycles_resolve_completely); 372 mark::hit!(type_var_cycles_resolve_completely);
373 // recursive type 373 // recursive type
374 return tv.fallback_value(); 374 return tv.fallback_value();
375 } 375 }
diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs
index a6f56c661..9fa8d3bdc 100644
--- a/crates/ra_hir_ty/src/lib.rs
+++ b/crates/ra_hir_ty/src/lib.rs
@@ -42,7 +42,6 @@ pub mod expr;
42mod tests; 42mod tests;
43#[cfg(test)] 43#[cfg(test)]
44mod test_db; 44mod test_db;
45mod marks;
46mod _match; 45mod _match;
47 46
48use std::ops::Deref; 47use std::ops::Deref;
@@ -50,8 +49,10 @@ use std::sync::Arc;
50use std::{iter, mem}; 49use std::{iter, mem};
51 50
52use hir_def::{ 51use hir_def::{
53 expr::ExprId, type_ref::Mutability, AdtId, AssocContainerId, DefWithBodyId, GenericDefId, 52 expr::ExprId,
54 HasModule, Lookup, TraitId, TypeAliasId, TypeParamId, 53 type_ref::{Mutability, Rawness},
54 AdtId, AssocContainerId, DefWithBodyId, GenericDefId, HasModule, Lookup, TraitId, TypeAliasId,
55 TypeParamId,
55}; 56};
56use ra_db::{impl_intern_key, salsa, CrateId}; 57use ra_db::{impl_intern_key, salsa, CrateId};
57 58
@@ -156,10 +157,16 @@ pub enum TypeCtor {
156/// This exists just for Chalk, because Chalk just has a single `StructId` where 157/// This exists just for Chalk, because Chalk just has a single `StructId` where
157/// we have different kinds of ADTs, primitive types and special type 158/// we have different kinds of ADTs, primitive types and special type
158/// constructors like tuples and function pointers. 159/// constructors like tuples and function pointers.
159#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 160#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
160pub struct TypeCtorId(salsa::InternId); 161pub struct TypeCtorId(salsa::InternId);
161impl_intern_key!(TypeCtorId); 162impl_intern_key!(TypeCtorId);
162 163
164/// This exists just for Chalk, because Chalk just has a single `FnDefId` where
165/// we have different IDs for struct and enum variant constructors.
166#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
167pub struct CallableDefId(salsa::InternId);
168impl_intern_key!(CallableDefId);
169
163impl TypeCtor { 170impl TypeCtor {
164 pub fn num_ty_params(self, db: &dyn HirDatabase) -> usize { 171 pub fn num_ty_params(self, db: &dyn HirDatabase) -> usize {
165 match self { 172 match self {
@@ -427,6 +434,11 @@ impl Substs {
427 } 434 }
428} 435}
429 436
437/// Return an index of a parameter in the generic type parameter list by it's id.
438pub fn param_idx(db: &dyn HirDatabase, id: TypeParamId) -> Option<usize> {
439 generics(db.upcast(), id.parent).param_idx(id)
440}
441
430#[derive(Debug, Clone)] 442#[derive(Debug, Clone)]
431pub struct SubstsBuilder { 443pub struct SubstsBuilder {
432 vec: Vec<Ty>, 444 vec: Vec<Ty>,
@@ -683,6 +695,12 @@ impl Ty {
683 pub fn unit() -> Self { 695 pub fn unit() -> Self {
684 Ty::apply(TypeCtor::Tuple { cardinality: 0 }, Substs::empty()) 696 Ty::apply(TypeCtor::Tuple { cardinality: 0 }, Substs::empty())
685 } 697 }
698 pub fn fn_ptr(sig: FnSig) -> Self {
699 Ty::apply(
700 TypeCtor::FnPtr { num_args: sig.params().len() as u16 },
701 Substs(sig.params_and_return),
702 )
703 }
686 704
687 pub fn as_reference(&self) -> Option<(&Ty, Mutability)> { 705 pub fn as_reference(&self) -> Option<(&Ty, Mutability)> {
688 match self { 706 match self {
@@ -693,6 +711,18 @@ impl Ty {
693 } 711 }
694 } 712 }
695 713
714 pub fn as_reference_or_ptr(&self) -> Option<(&Ty, Rawness, Mutability)> {
715 match self {
716 Ty::Apply(ApplicationTy { ctor: TypeCtor::Ref(mutability), parameters }) => {
717 Some((parameters.as_single(), Rawness::Ref, *mutability))
718 }
719 Ty::Apply(ApplicationTy { ctor: TypeCtor::RawPtr(mutability), parameters }) => {
720 Some((parameters.as_single(), Rawness::RawPtr, *mutability))
721 }
722 _ => None,
723 }
724 }
725
696 pub fn strip_references(&self) -> &Ty { 726 pub fn strip_references(&self) -> &Ty {
697 let mut t: &Ty = self; 727 let mut t: &Ty = self;
698 728
@@ -730,6 +760,10 @@ impl Ty {
730 } 760 }
731 } 761 }
732 762
763 pub fn is_never(&self) -> bool {
764 matches!(self, Ty::Apply(ApplicationTy { ctor: TypeCtor::Never, .. }))
765 }
766
733 /// If this is a `dyn Trait` type, this returns the `Trait` part. 767 /// If this is a `dyn Trait` type, this returns the `Trait` part.
734 pub fn dyn_trait_ref(&self) -> Option<&TraitRef> { 768 pub fn dyn_trait_ref(&self) -> Option<&TraitRef> {
735 match self { 769 match self {
@@ -793,15 +827,13 @@ impl Ty {
793 } 827 }
794 } 828 }
795 829
796 /// If this is an `impl Trait` or `dyn Trait`, returns that trait. 830 /// If this is a `dyn Trait`, returns that trait.
797 pub fn inherent_trait(&self) -> Option<TraitId> { 831 pub fn dyn_trait(&self) -> Option<TraitId> {
798 match self { 832 match self {
799 Ty::Dyn(predicates) | Ty::Opaque(predicates) => { 833 Ty::Dyn(predicates) => predicates.iter().find_map(|pred| match pred {
800 predicates.iter().find_map(|pred| match pred { 834 GenericPredicate::Implemented(tr) => Some(tr.trait_),
801 GenericPredicate::Implemented(tr) => Some(tr.trait_), 835 _ => None,
802 _ => None, 836 }),
803 })
804 }
805 _ => None, 837 _ => None,
806 } 838 }
807 } 839 }
diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs
index 9ad6dbe07..35ac86a46 100644
--- a/crates/ra_hir_ty/src/lower.rs
+++ b/crates/ra_hir_ty/src/lower.rs
@@ -812,7 +812,7 @@ impl TraitEnvironment {
812 // add `Self: Trait<T1, T2, ...>` to the environment in trait 812 // add `Self: Trait<T1, T2, ...>` to the environment in trait
813 // function default implementations (and hypothetical code 813 // function default implementations (and hypothetical code
814 // inside consts or type aliases) 814 // inside consts or type aliases)
815 test_utils::tested_by!(trait_self_implements_self); 815 test_utils::mark::hit!(trait_self_implements_self);
816 let substs = Substs::type_params(db, trait_id); 816 let substs = Substs::type_params(db, trait_id);
817 let trait_ref = TraitRef { trait_: trait_id, substs }; 817 let trait_ref = TraitRef { trait_: trait_id, substs };
818 let pred = GenericPredicate::Implemented(trait_ref); 818 let pred = GenericPredicate::Implemented(trait_ref);
diff --git a/crates/ra_hir_ty/src/marks.rs b/crates/ra_hir_ty/src/marks.rs
deleted file mode 100644
index de5cb1d6b..000000000
--- a/crates/ra_hir_ty/src/marks.rs
+++ /dev/null
@@ -1,11 +0,0 @@
1//! See test_utils/src/marks.rs
2
3test_utils::marks!(
4 type_var_cycles_resolve_completely
5 type_var_cycles_resolve_as_possible
6 type_var_resolves_to_int_var
7 impl_self_type_match_without_receiver
8 match_ergonomics_ref
9 coerce_merge_fail_fallback
10 trait_self_implements_self
11);
diff --git a/crates/ra_hir_ty/src/method_resolution.rs b/crates/ra_hir_ty/src/method_resolution.rs
index 657284fd0..e19628fdf 100644
--- a/crates/ra_hir_ty/src/method_resolution.rs
+++ b/crates/ra_hir_ty/src/method_resolution.rs
@@ -408,8 +408,9 @@ fn iterate_trait_method_candidates<T>(
408 receiver_ty: Option<&Canonical<Ty>>, 408 receiver_ty: Option<&Canonical<Ty>>,
409 mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>, 409 mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>,
410) -> Option<T> { 410) -> Option<T> {
411 // if ty is `impl Trait` or `dyn Trait`, the trait doesn't need to be in scope 411 // if ty is `dyn Trait`, the trait doesn't need to be in scope
412 let inherent_trait = self_ty.value.inherent_trait().into_iter(); 412 let inherent_trait =
413 self_ty.value.dyn_trait().into_iter().flat_map(|t| all_super_traits(db.upcast(), t));
413 let env_traits = if let Ty::Placeholder(_) = self_ty.value { 414 let env_traits = if let Ty::Placeholder(_) = self_ty.value {
414 // if we have `T: Trait` in the param env, the trait doesn't need to be in scope 415 // if we have `T: Trait` in the param env, the trait doesn't need to be in scope
415 env.trait_predicates_for_self_ty(&self_ty.value) 416 env.trait_predicates_for_self_ty(&self_ty.value)
@@ -468,7 +469,7 @@ fn iterate_inherent_methods<T>(
468 // already happens in `is_valid_candidate` above; if not, we 469 // already happens in `is_valid_candidate` above; if not, we
469 // check it here 470 // check it here
470 if receiver_ty.is_none() && inherent_impl_substs(db, impl_def, self_ty).is_none() { 471 if receiver_ty.is_none() && inherent_impl_substs(db, impl_def, self_ty).is_none() {
471 test_utils::tested_by!(impl_self_type_match_without_receiver); 472 test_utils::mark::hit!(impl_self_type_match_without_receiver);
472 continue; 473 continue;
473 } 474 }
474 if let Some(result) = callback(&self_ty.value, item) { 475 if let Some(result) = callback(&self_ty.value, item) {
@@ -601,11 +602,6 @@ pub fn implements_trait(
601 krate: CrateId, 602 krate: CrateId,
602 trait_: TraitId, 603 trait_: TraitId,
603) -> bool { 604) -> bool {
604 if ty.value.inherent_trait() == Some(trait_) {
605 // FIXME this is a bit of a hack, since Chalk should say the same thing
606 // anyway, but currently Chalk doesn't implement `dyn/impl Trait` yet
607 return true;
608 }
609 let goal = generic_implements_goal(db, env, trait_, ty.clone()); 605 let goal = generic_implements_goal(db, env, trait_, ty.clone());
610 let solution = db.trait_solve(krate, goal); 606 let solution = db.trait_solve(krate, goal);
611 607
diff --git a/crates/ra_hir_ty/src/op.rs b/crates/ra_hir_ty/src/op.rs
index 54e2bd05a..0870874fc 100644
--- a/crates/ra_hir_ty/src/op.rs
+++ b/crates/ra_hir_ty/src/op.rs
@@ -30,7 +30,8 @@ pub(super) fn binary_op_return_ty(op: BinaryOp, lhs_ty: Ty, rhs_ty: Ty) -> Ty {
30pub(super) fn binary_op_rhs_expectation(op: BinaryOp, lhs_ty: Ty) -> Ty { 30pub(super) fn binary_op_rhs_expectation(op: BinaryOp, lhs_ty: Ty) -> Ty {
31 match op { 31 match op {
32 BinaryOp::LogicOp(..) => Ty::simple(TypeCtor::Bool), 32 BinaryOp::LogicOp(..) => Ty::simple(TypeCtor::Bool),
33 BinaryOp::Assignment { op: None } | BinaryOp::CmpOp(CmpOp::Eq { .. }) => match lhs_ty { 33 BinaryOp::Assignment { op: None } => lhs_ty,
34 BinaryOp::CmpOp(CmpOp::Eq { .. }) => match lhs_ty {
34 Ty::Apply(ApplicationTy { ctor, .. }) => match ctor { 35 Ty::Apply(ApplicationTy { ctor, .. }) => match ctor {
35 TypeCtor::Int(..) 36 TypeCtor::Int(..)
36 | TypeCtor::Float(..) 37 | TypeCtor::Float(..)
diff --git a/crates/ra_hir_ty/src/tests.rs b/crates/ra_hir_ty/src/tests.rs
index 588d81282..1fe05c70c 100644
--- a/crates/ra_hir_ty/src/tests.rs
+++ b/crates/ra_hir_ty/src/tests.rs
@@ -6,6 +6,7 @@ mod patterns;
6mod traits; 6mod traits;
7mod method_resolution; 7mod method_resolution;
8mod macros; 8mod macros;
9mod display_source_code;
9 10
10use std::sync::Arc; 11use std::sync::Arc;
11 12
@@ -16,7 +17,7 @@ use hir_def::{
16 item_scope::ItemScope, 17 item_scope::ItemScope,
17 keys, 18 keys,
18 nameres::CrateDefMap, 19 nameres::CrateDefMap,
19 AssocItemId, DefWithBodyId, LocalModuleId, Lookup, ModuleDefId, 20 AssocItemId, DefWithBodyId, LocalModuleId, Lookup, ModuleDefId, ModuleId,
20}; 21};
21use hir_expand::{db::AstDatabase, InFile}; 22use hir_expand::{db::AstDatabase, InFile};
22use insta::assert_snapshot; 23use insta::assert_snapshot;
@@ -37,6 +38,18 @@ use crate::{
37// update the snapshots. 38// update the snapshots.
38 39
39fn type_at_pos(db: &TestDB, pos: FilePosition) -> String { 40fn type_at_pos(db: &TestDB, pos: FilePosition) -> String {
41 type_at_pos_displayed(db, pos, |ty, _| ty.display(db).to_string())
42}
43
44fn displayed_source_at_pos(db: &TestDB, pos: FilePosition) -> String {
45 type_at_pos_displayed(db, pos, |ty, module_id| ty.display_source_code(db, module_id).unwrap())
46}
47
48fn type_at_pos_displayed(
49 db: &TestDB,
50 pos: FilePosition,
51 display_fn: impl FnOnce(&Ty, ModuleId) -> String,
52) -> String {
40 let file = db.parse(pos.file_id).ok().unwrap(); 53 let file = db.parse(pos.file_id).ok().unwrap();
41 let expr = algo::find_node_at_offset::<ast::Expr>(file.syntax(), pos.offset).unwrap(); 54 let expr = algo::find_node_at_offset::<ast::Expr>(file.syntax(), pos.offset).unwrap();
42 let fn_def = expr.syntax().ancestors().find_map(ast::FnDef::cast).unwrap(); 55 let fn_def = expr.syntax().ancestors().find_map(ast::FnDef::cast).unwrap();
@@ -49,7 +62,7 @@ fn type_at_pos(db: &TestDB, pos: FilePosition) -> String {
49 if let Some(expr_id) = source_map.node_expr(InFile::new(pos.file_id.into(), &expr)) { 62 if let Some(expr_id) = source_map.node_expr(InFile::new(pos.file_id.into(), &expr)) {
50 let infer = db.infer(func.into()); 63 let infer = db.infer(func.into());
51 let ty = &infer[expr_id]; 64 let ty = &infer[expr_id];
52 return ty.display(db).to_string(); 65 return display_fn(ty, module);
53 } 66 }
54 panic!("Can't find expression") 67 panic!("Can't find expression")
55} 68}
@@ -361,6 +374,33 @@ fn no_such_field_with_feature_flag_diagnostics() {
361} 374}
362 375
363#[test] 376#[test]
377fn no_such_field_enum_with_feature_flag_diagnostics() {
378 let diagnostics = TestDB::with_files(
379 r#"
380 //- /lib.rs crate:foo cfg:feature=foo
381 enum Foo {
382 #[cfg(not(feature = "foo"))]
383 Buz,
384 #[cfg(feature = "foo")]
385 Bar,
386 Baz
387 }
388
389 fn test_fn(f: Foo) {
390 match f {
391 Foo::Bar => {},
392 Foo::Baz => {},
393 }
394 }
395 "#,
396 )
397 .diagnostics()
398 .0;
399
400 assert_snapshot!(diagnostics, @r###""###);
401}
402
403#[test]
364fn no_such_field_with_feature_flag_diagnostics_on_struct_lit() { 404fn no_such_field_with_feature_flag_diagnostics_on_struct_lit() {
365 let diagnostics = TestDB::with_files( 405 let diagnostics = TestDB::with_files(
366 r#" 406 r#"
@@ -491,3 +531,21 @@ fn missing_record_pat_field_no_diagnostic_if_not_exhaustive() {
491 531
492 assert_snapshot!(diagnostics, @""); 532 assert_snapshot!(diagnostics, @"");
493} 533}
534
535#[test]
536fn break_outside_of_loop() {
537 let diagnostics = TestDB::with_files(
538 r"
539 //- /lib.rs
540 fn foo() {
541 break;
542 }
543 ",
544 )
545 .diagnostics()
546 .0;
547
548 assert_snapshot!(diagnostics, @r###""break": break outside of loop
549 "###
550 );
551}
diff --git a/crates/ra_hir_ty/src/tests/coercion.rs b/crates/ra_hir_ty/src/tests/coercion.rs
index e6fb3e123..6f777ed8c 100644
--- a/crates/ra_hir_ty/src/tests/coercion.rs
+++ b/crates/ra_hir_ty/src/tests/coercion.rs
@@ -1,6 +1,6 @@
1use super::infer_with_mismatches; 1use super::infer_with_mismatches;
2use insta::assert_snapshot; 2use insta::assert_snapshot;
3use test_utils::covers; 3use test_utils::mark;
4 4
5// Infer with some common definitions and impls. 5// Infer with some common definitions and impls.
6fn infer(source: &str) -> String { 6fn infer(source: &str) -> String {
@@ -116,15 +116,20 @@ fn infer_let_stmt_coerce() {
116 assert_snapshot!( 116 assert_snapshot!(
117 infer(r#" 117 infer(r#"
118fn test() { 118fn test() {
119 let x: &[i32] = &[1]; 119 let x: &[isize] = &[1];
120 let x: *const [isize] = &[1];
120} 121}
121"#), 122"#),
122 @r###" 123 @r###"
123 11..40 '{ ...[1]; }': () 124 11..76 '{ ...[1]; }': ()
124 21..22 'x': &[i32] 125 21..22 'x': &[isize]
125 33..37 '&[1]': &[i32; _] 126 35..39 '&[1]': &[isize; _]
126 34..37 '[1]': [i32; _] 127 36..39 '[1]': [isize; _]
127 35..36 '1': i32 128 37..38 '1': isize
129 49..50 'x': *const [isize]
130 69..73 '&[1]': &[isize; _]
131 70..73 '[1]': [isize; _]
132 71..72 '1': isize
128 "###); 133 "###);
129} 134}
130 135
@@ -339,7 +344,7 @@ fn test(i: i32) {
339 344
340#[test] 345#[test]
341fn coerce_merge_one_by_one1() { 346fn coerce_merge_one_by_one1() {
342 covers!(coerce_merge_fail_fallback); 347 mark::check!(coerce_merge_fail_fallback);
343 348
344 assert_snapshot!( 349 assert_snapshot!(
345 infer(r#" 350 infer(r#"
@@ -384,7 +389,7 @@ fn foo() -> u32 {
384} 389}
385"#, true), 390"#, true),
386 @r###" 391 @r###"
387 17..40 '{ ...own; }': ! 392 17..40 '{ ...own; }': u32
388 23..37 'return unknown': ! 393 23..37 'return unknown': !
389 30..37 'unknown': u32 394 30..37 'unknown': u32
390 "### 395 "###
@@ -514,7 +519,7 @@ fn foo() {
514 27..103 '{ ... }': &u32 519 27..103 '{ ... }': &u32
515 37..82 'if tru... }': () 520 37..82 'if tru... }': ()
516 40..44 'true': bool 521 40..44 'true': bool
517 45..82 '{ ... }': ! 522 45..82 '{ ... }': ()
518 59..71 'return &1u32': ! 523 59..71 'return &1u32': !
519 66..71 '&1u32': &u32 524 66..71 '&1u32': &u32
520 67..71 '1u32': u32 525 67..71 '1u32': u32
@@ -546,6 +551,48 @@ fn test() {
546} 551}
547 552
548#[test] 553#[test]
554fn coerce_fn_items_in_match_arms() {
555 mark::check!(coerce_fn_reification);
556 assert_snapshot!(
557 infer_with_mismatches(r#"
558fn foo1(x: u32) -> isize { 1 }
559fn foo2(x: u32) -> isize { 2 }
560fn foo3(x: u32) -> isize { 3 }
561fn test() {
562 let x = match 1 {
563 1 => foo1,
564 2 => foo2,
565 _ => foo3,
566 };
567}
568"#, true),
569 @r###"
570 9..10 'x': u32
571 26..31 '{ 1 }': isize
572 28..29 '1': isize
573 40..41 'x': u32
574 57..62 '{ 2 }': isize
575 59..60 '2': isize
576 71..72 'x': u32
577 88..93 '{ 3 }': isize
578 90..91 '3': isize
579 104..193 '{ ... }; }': ()
580 114..115 'x': fn(u32) -> isize
581 118..190 'match ... }': fn(u32) -> isize
582 124..125 '1': i32
583 136..137 '1': i32
584 136..137 '1': i32
585 141..145 'foo1': fn foo1(u32) -> isize
586 155..156 '2': i32
587 155..156 '2': i32
588 160..164 'foo2': fn foo2(u32) -> isize
589 174..175 '_': i32
590 179..183 'foo3': fn foo3(u32) -> isize
591 "###
592 );
593}
594
595#[test]
549fn coerce_closure_to_fn_ptr() { 596fn coerce_closure_to_fn_ptr() {
550 assert_snapshot!( 597 assert_snapshot!(
551 infer_with_mismatches(r#" 598 infer_with_mismatches(r#"
diff --git a/crates/ra_hir_ty/src/tests/display_source_code.rs b/crates/ra_hir_ty/src/tests/display_source_code.rs
new file mode 100644
index 000000000..4088b1d22
--- /dev/null
+++ b/crates/ra_hir_ty/src/tests/display_source_code.rs
@@ -0,0 +1,50 @@
1use super::displayed_source_at_pos;
2use crate::test_db::TestDB;
3use ra_db::fixture::WithFixture;
4
5#[test]
6fn qualify_path_to_submodule() {
7 let (db, pos) = TestDB::with_position(
8 r#"
9//- /main.rs
10
11mod foo {
12 pub struct Foo;
13}
14
15fn bar() {
16 let foo: foo::Foo = foo::Foo;
17 foo<|>
18}
19
20"#,
21 );
22 assert_eq!("foo::Foo", displayed_source_at_pos(&db, pos));
23}
24
25#[test]
26fn omit_default_type_parameters() {
27 let (db, pos) = TestDB::with_position(
28 r"
29 //- /main.rs
30 struct Foo<T = u8> { t: T }
31 fn main() {
32 let foo = Foo { t: 5 };
33 foo<|>;
34 }
35 ",
36 );
37 assert_eq!("Foo", displayed_source_at_pos(&db, pos));
38
39 let (db, pos) = TestDB::with_position(
40 r"
41 //- /main.rs
42 struct Foo<K, T = u8> { k: K, t: T }
43 fn main() {
44 let foo = Foo { k: 400, t: 5 };
45 foo<|>;
46 }
47 ",
48 );
49 assert_eq!("Foo<i32>", displayed_source_at_pos(&db, pos));
50}
diff --git a/crates/ra_hir_ty/src/tests/macros.rs b/crates/ra_hir_ty/src/tests/macros.rs
index 5ddecbdc6..4c6099aa2 100644
--- a/crates/ra_hir_ty/src/tests/macros.rs
+++ b/crates/ra_hir_ty/src/tests/macros.rs
@@ -197,7 +197,7 @@ fn spam() {
197 !0..6 '1isize': isize 197 !0..6 '1isize': isize
198 !0..6 '1isize': isize 198 !0..6 '1isize': isize
199 !0..6 '1isize': isize 199 !0..6 '1isize': isize
200 54..457 '{ ...!(); }': ! 200 54..457 '{ ...!(); }': ()
201 88..109 'spam!(...am!())': {unknown} 201 88..109 'spam!(...am!())': {unknown}
202 115..134 'for _ ...!() {}': () 202 115..134 'for _ ...!() {}': ()
203 119..120 '_': {unknown} 203 119..120 '_': {unknown}
@@ -269,7 +269,7 @@ fn test() { S.foo()<|>; }
269} 269}
270 270
271#[test] 271#[test]
272fn infer_impl_items_generated_by_macros() { 272fn infer_assoc_items_generated_by_macros() {
273 let t = type_at( 273 let t = type_at(
274 r#" 274 r#"
275//- /main.rs 275//- /main.rs
@@ -288,7 +288,7 @@ fn test() { S.foo()<|>; }
288} 288}
289 289
290#[test] 290#[test]
291fn infer_impl_items_generated_by_macros_chain() { 291fn infer_assoc_items_generated_by_macros_chain() {
292 let t = type_at( 292 let t = type_at(
293 r#" 293 r#"
294//- /main.rs 294//- /main.rs
@@ -339,6 +339,46 @@ pub fn baz() -> usize { 31usize }
339} 339}
340 340
341#[test] 341#[test]
342fn infer_macro_with_dollar_crate_is_correct_in_trait_associate_type() {
343 let (db, pos) = TestDB::with_position(
344 r#"
345//- /main.rs crate:main deps:foo
346use foo::Trait;
347
348fn test() {
349 let msg = foo::Message(foo::MessageRef);
350 let r = msg.deref();
351 r<|>;
352}
353
354//- /lib.rs crate:foo
355pub struct MessageRef;
356pub struct Message(MessageRef);
357
358pub trait Trait {
359 type Target;
360 fn deref(&self) -> &Self::Target;
361}
362
363#[macro_export]
364macro_rules! expand {
365 () => {
366 impl Trait for Message {
367 type Target = $crate::MessageRef;
368 fn deref(&self) -> &Self::Target {
369 &self.0
370 }
371 }
372 }
373}
374
375expand!();
376"#,
377 );
378 assert_eq!("&MessageRef", type_at_pos(&db, pos));
379}
380
381#[test]
342fn infer_type_value_non_legacy_macro_use_as() { 382fn infer_type_value_non_legacy_macro_use_as() {
343 assert_snapshot!( 383 assert_snapshot!(
344 infer(r#" 384 infer(r#"
@@ -388,6 +428,32 @@ fn main() {
388} 428}
389 429
390#[test] 430#[test]
431fn infer_local_inner_macros() {
432 let (db, pos) = TestDB::with_position(
433 r#"
434//- /main.rs crate:main deps:foo
435fn test() {
436 let x = foo::foo!(1);
437 x<|>;
438}
439
440//- /lib.rs crate:foo
441#[macro_export(local_inner_macros)]
442macro_rules! foo {
443 (1) => { bar!() };
444}
445
446#[macro_export]
447macro_rules! bar {
448 () => { 42 }
449}
450
451"#,
452 );
453 assert_eq!("i32", type_at_pos(&db, pos));
454}
455
456#[test]
391fn infer_builtin_macros_line() { 457fn infer_builtin_macros_line() {
392 assert_snapshot!( 458 assert_snapshot!(
393 infer(r#" 459 infer(r#"
diff --git a/crates/ra_hir_ty/src/tests/method_resolution.rs b/crates/ra_hir_ty/src/tests/method_resolution.rs
index ab87f598a..558a70022 100644
--- a/crates/ra_hir_ty/src/tests/method_resolution.rs
+++ b/crates/ra_hir_ty/src/tests/method_resolution.rs
@@ -17,8 +17,8 @@ impl<T> [T] {
17#[lang = "slice_alloc"] 17#[lang = "slice_alloc"]
18impl<T> [T] {} 18impl<T> [T] {}
19 19
20fn test() { 20fn test(x: &[u8]) {
21 <[_]>::foo(b"foo"); 21 <[_]>::foo(x);
22} 22}
23"#), 23"#),
24 @r###" 24 @r###"
@@ -26,10 +26,11 @@ fn test() {
26 56..79 '{ ... }': T 26 56..79 '{ ... }': T
27 66..73 'loop {}': ! 27 66..73 'loop {}': !
28 71..73 '{}': () 28 71..73 '{}': ()
29 133..160 '{ ...o"); }': () 29 131..132 'x': &[u8]
30 139..149 '<[_]>::foo': fn foo<u8>(&[u8]) -> u8 30 141..163 '{ ...(x); }': ()
31 139..157 '<[_]>:..."foo")': u8 31 147..157 '<[_]>::foo': fn foo<u8>(&[u8]) -> u8
32 150..156 'b"foo"': &[u8] 32 147..160 '<[_]>::foo(x)': u8
33 158..159 'x': &[u8]
33 "### 34 "###
34 ); 35 );
35} 36}
@@ -983,7 +984,7 @@ fn test() { S2.into()<|>; }
983 984
984#[test] 985#[test]
985fn method_resolution_overloaded_method() { 986fn method_resolution_overloaded_method() {
986 test_utils::covers!(impl_self_type_match_without_receiver); 987 test_utils::mark::check!(impl_self_type_match_without_receiver);
987 let t = type_at( 988 let t = type_at(
988 r#" 989 r#"
989//- main.rs 990//- main.rs
@@ -1095,3 +1096,34 @@ fn test() { (S {}).method()<|>; }
1095 ); 1096 );
1096 assert_eq!(t, "()"); 1097 assert_eq!(t, "()");
1097} 1098}
1099
1100#[test]
1101fn dyn_trait_super_trait_not_in_scope() {
1102 assert_snapshot!(
1103 infer(r#"
1104mod m {
1105 pub trait SuperTrait {
1106 fn foo(&self) -> u32 { 0 }
1107 }
1108}
1109trait Trait: m::SuperTrait {}
1110
1111struct S;
1112impl m::SuperTrait for S {}
1113impl Trait for S {}
1114
1115fn test(d: &dyn Trait) {
1116 d.foo();
1117}
1118"#),
1119 @r###"
1120 52..56 'self': &Self
1121 65..70 '{ 0 }': u32
1122 67..68 '0': u32
1123 177..178 'd': &dyn Trait
1124 192..208 '{ ...o(); }': ()
1125 198..199 'd': &dyn Trait
1126 198..205 'd.foo()': u32
1127 "###
1128 );
1129}
diff --git a/crates/ra_hir_ty/src/tests/never_type.rs b/crates/ra_hir_ty/src/tests/never_type.rs
index a77209480..082c47208 100644
--- a/crates/ra_hir_ty/src/tests/never_type.rs
+++ b/crates/ra_hir_ty/src/tests/never_type.rs
@@ -1,4 +1,6 @@
1use super::type_at; 1use insta::assert_snapshot;
2
3use super::{infer_with_mismatches, type_at};
2 4
3#[test] 5#[test]
4fn infer_never1() { 6fn infer_never1() {
@@ -261,3 +263,176 @@ fn test(a: i32) {
261 ); 263 );
262 assert_eq!(t, "f64"); 264 assert_eq!(t, "f64");
263} 265}
266
267#[test]
268fn diverging_expression_1() {
269 let t = infer_with_mismatches(
270 r#"
271//- /main.rs
272fn test1() {
273 let x: u32 = return;
274}
275fn test2() {
276 let x: u32 = { return; };
277}
278fn test3() {
279 let x: u32 = loop {};
280}
281fn test4() {
282 let x: u32 = { loop {} };
283}
284fn test5() {
285 let x: u32 = { if true { loop {}; } else { loop {}; } };
286}
287fn test6() {
288 let x: u32 = { let y: u32 = { loop {}; }; };
289}
290"#,
291 true,
292 );
293 assert_snapshot!(t, @r###"
294 25..53 '{ ...urn; }': ()
295 35..36 'x': u32
296 44..50 'return': !
297 65..98 '{ ...; }; }': ()
298 75..76 'x': u32
299 84..95 '{ return; }': u32
300 86..92 'return': !
301 110..139 '{ ... {}; }': ()
302 120..121 'x': u32
303 129..136 'loop {}': !
304 134..136 '{}': ()
305 151..184 '{ ...} }; }': ()
306 161..162 'x': u32
307 170..181 '{ loop {} }': u32
308 172..179 'loop {}': !
309 177..179 '{}': ()
310 196..260 '{ ...} }; }': ()
311 206..207 'x': u32
312 215..257 '{ if t...}; } }': u32
313 217..255 'if tru... {}; }': u32
314 220..224 'true': bool
315 225..237 '{ loop {}; }': u32
316 227..234 'loop {}': !
317 232..234 '{}': ()
318 243..255 '{ loop {}; }': u32
319 245..252 'loop {}': !
320 250..252 '{}': ()
321 272..324 '{ ...; }; }': ()
322 282..283 'x': u32
323 291..321 '{ let ...; }; }': u32
324 297..298 'y': u32
325 306..318 '{ loop {}; }': u32
326 308..315 'loop {}': !
327 313..315 '{}': ()
328 "###);
329}
330
331#[test]
332fn diverging_expression_2() {
333 let t = infer_with_mismatches(
334 r#"
335//- /main.rs
336fn test1() {
337 // should give type mismatch
338 let x: u32 = { loop {}; "foo" };
339}
340"#,
341 true,
342 );
343 assert_snapshot!(t, @r###"
344 25..98 '{ ..." }; }': ()
345 68..69 'x': u32
346 77..95 '{ loop...foo" }': &str
347 79..86 'loop {}': !
348 84..86 '{}': ()
349 88..93 '"foo"': &str
350 77..95: expected u32, got &str
351 88..93: expected u32, got &str
352 "###);
353}
354
355#[test]
356fn diverging_expression_3_break() {
357 let t = infer_with_mismatches(
358 r#"
359//- /main.rs
360fn test1() {
361 // should give type mismatch
362 let x: u32 = { loop { break; } };
363}
364fn test2() {
365 // should give type mismatch
366 let x: u32 = { for a in b { break; }; };
367 // should give type mismatch as well
368 let x: u32 = { for a in b {}; };
369 // should give type mismatch as well
370 let x: u32 = { for a in b { return; }; };
371}
372fn test3() {
373 // should give type mismatch
374 let x: u32 = { while true { break; }; };
375 // should give type mismatch as well -- there's an implicit break, even if it's never hit
376 let x: u32 = { while true {}; };
377 // should give type mismatch as well
378 let x: u32 = { while true { return; }; };
379}
380"#,
381 true,
382 );
383 assert_snapshot!(t, @r###"
384 25..99 '{ ...} }; }': ()
385 68..69 'x': u32
386 77..96 '{ loop...k; } }': ()
387 79..94 'loop { break; }': ()
388 84..94 '{ break; }': ()
389 86..91 'break': !
390 77..96: expected u32, got ()
391 79..94: expected u32, got ()
392 111..357 '{ ...; }; }': ()
393 154..155 'x': u32
394 163..189 '{ for ...; }; }': ()
395 165..186 'for a ...eak; }': ()
396 169..170 'a': {unknown}
397 174..175 'b': {unknown}
398 176..186 '{ break; }': ()
399 178..183 'break': !
400 240..241 'x': u32
401 249..267 '{ for ... {}; }': ()
402 251..264 'for a in b {}': ()
403 255..256 'a': {unknown}
404 260..261 'b': {unknown}
405 262..264 '{}': ()
406 318..319 'x': u32
407 327..354 '{ for ...; }; }': ()
408 329..351 'for a ...urn; }': ()
409 333..334 'a': {unknown}
410 338..339 'b': {unknown}
411 340..351 '{ return; }': ()
412 342..348 'return': !
413 163..189: expected u32, got ()
414 249..267: expected u32, got ()
415 327..354: expected u32, got ()
416 369..668 '{ ...; }; }': ()
417 412..413 'x': u32
418 421..447 '{ whil...; }; }': ()
419 423..444 'while ...eak; }': ()
420 429..433 'true': bool
421 434..444 '{ break; }': ()
422 436..441 'break': !
423 551..552 'x': u32
424 560..578 '{ whil... {}; }': ()
425 562..575 'while true {}': ()
426 568..572 'true': bool
427 573..575 '{}': ()
428 629..630 'x': u32
429 638..665 '{ whil...; }; }': ()
430 640..662 'while ...urn; }': ()
431 646..650 'true': bool
432 651..662 '{ return; }': ()
433 653..659 'return': !
434 421..447: expected u32, got ()
435 560..578: expected u32, got ()
436 638..665: expected u32, got ()
437 "###);
438}
diff --git a/crates/ra_hir_ty/src/tests/patterns.rs b/crates/ra_hir_ty/src/tests/patterns.rs
index af291092d..fe62587c0 100644
--- a/crates/ra_hir_ty/src/tests/patterns.rs
+++ b/crates/ra_hir_ty/src/tests/patterns.rs
@@ -1,5 +1,5 @@
1use insta::assert_snapshot; 1use insta::assert_snapshot;
2use test_utils::covers; 2use test_utils::mark;
3 3
4use super::{infer, infer_with_mismatches}; 4use super::{infer, infer_with_mismatches};
5 5
@@ -197,7 +197,7 @@ fn test() {
197 197
198#[test] 198#[test]
199fn infer_pattern_match_ergonomics_ref() { 199fn infer_pattern_match_ergonomics_ref() {
200 covers!(match_ergonomics_ref); 200 mark::check!(match_ergonomics_ref);
201 assert_snapshot!( 201 assert_snapshot!(
202 infer(r#" 202 infer(r#"
203fn test() { 203fn test() {
@@ -369,6 +369,45 @@ fn test() {
369} 369}
370 370
371#[test] 371#[test]
372fn enum_variant_through_self_in_pattern() {
373 assert_snapshot!(
374 infer(r#"
375enum E {
376 A { x: usize },
377 B(usize),
378 C
379}
380
381impl E {
382 fn test() {
383 match (loop {}) {
384 Self::A { x } => { x; },
385 Self::B(x) => { x; },
386 Self::C => {},
387 };
388 }
389}
390"#),
391 @r###"
392 76..218 '{ ... }': ()
393 86..211 'match ... }': ()
394 93..100 'loop {}': !
395 98..100 '{}': ()
396 116..129 'Self::A { x }': E
397 126..127 'x': usize
398 133..139 '{ x; }': ()
399 135..136 'x': usize
400 153..163 'Self::B(x)': E
401 161..162 'x': usize
402 167..173 '{ x; }': ()
403 169..170 'x': usize
404 187..194 'Self::C': E
405 198..200 '{}': ()
406 "###
407 );
408}
409
410#[test]
372fn infer_generics_in_patterns() { 411fn infer_generics_in_patterns() {
373 assert_snapshot!( 412 assert_snapshot!(
374 infer(r#" 413 infer(r#"
@@ -481,3 +520,53 @@ fn main() {
481 105..107 '()': () 520 105..107 '()': ()
482 ") 521 ")
483} 522}
523
524#[test]
525fn match_ergonomics_in_closure_params() {
526 assert_snapshot!(
527 infer(r#"
528#[lang = "fn_once"]
529trait FnOnce<Args> {
530 type Output;
531}
532
533fn foo<T, U, F: FnOnce(T) -> U>(t: T, f: F) -> U { loop {} }
534
535fn test() {
536 foo(&(1, "a"), |&(x, y)| x); // normal, no match ergonomics
537 foo(&(1, "a"), |(x, y)| x);
538}
539"#),
540 @r###"
541 94..95 't': T
542 100..101 'f': F
543 111..122 '{ loop {} }': U
544 113..120 'loop {}': !
545 118..120 '{}': ()
546 134..233 '{ ... x); }': ()
547 140..143 'foo': fn foo<&(i32, &str), i32, |&(i32, &str)| -> i32>(&(i32, &str), |&(i32, &str)| -> i32) -> i32
548 140..167 'foo(&(...y)| x)': i32
549 144..153 '&(1, "a")': &(i32, &str)
550 145..153 '(1, "a")': (i32, &str)
551 146..147 '1': i32
552 149..152 '"a"': &str
553 155..166 '|&(x, y)| x': |&(i32, &str)| -> i32
554 156..163 '&(x, y)': &(i32, &str)
555 157..163 '(x, y)': (i32, &str)
556 158..159 'x': i32
557 161..162 'y': &str
558 165..166 'x': i32
559 204..207 'foo': fn foo<&(i32, &str), &i32, |&(i32, &str)| -> &i32>(&(i32, &str), |&(i32, &str)| -> &i32) -> &i32
560 204..230 'foo(&(...y)| x)': &i32
561 208..217 '&(1, "a")': &(i32, &str)
562 209..217 '(1, "a")': (i32, &str)
563 210..211 '1': i32
564 213..216 '"a"': &str
565 219..229 '|(x, y)| x': |&(i32, &str)| -> &i32
566 220..226 '(x, y)': (i32, &str)
567 221..222 'x': &i32
568 224..225 'y': &&str
569 228..229 'x': &i32
570 "###
571 );
572}
diff --git a/crates/ra_hir_ty/src/tests/regression.rs b/crates/ra_hir_ty/src/tests/regression.rs
index 8a1292c7a..1f004bd63 100644
--- a/crates/ra_hir_ty/src/tests/regression.rs
+++ b/crates/ra_hir_ty/src/tests/regression.rs
@@ -1,9 +1,10 @@
1use insta::assert_snapshot; 1use insta::assert_snapshot;
2use test_utils::covers; 2use ra_db::fixture::WithFixture;
3use test_utils::mark;
3 4
4use super::infer;
5use crate::test_db::TestDB; 5use crate::test_db::TestDB;
6use ra_db::fixture::WithFixture; 6
7use super::infer;
7 8
8#[test] 9#[test]
9fn bug_484() { 10fn bug_484() {
@@ -89,8 +90,8 @@ fn quux() {
89 90
90#[test] 91#[test]
91fn recursive_vars() { 92fn recursive_vars() {
92 covers!(type_var_cycles_resolve_completely); 93 mark::check!(type_var_cycles_resolve_completely);
93 covers!(type_var_cycles_resolve_as_possible); 94 mark::check!(type_var_cycles_resolve_as_possible);
94 assert_snapshot!( 95 assert_snapshot!(
95 infer(r#" 96 infer(r#"
96fn test() { 97fn test() {
@@ -112,8 +113,6 @@ fn test() {
112 113
113#[test] 114#[test]
114fn recursive_vars_2() { 115fn recursive_vars_2() {
115 covers!(type_var_cycles_resolve_completely);
116 covers!(type_var_cycles_resolve_as_possible);
117 assert_snapshot!( 116 assert_snapshot!(
118 infer(r#" 117 infer(r#"
119fn test() { 118fn test() {
@@ -170,7 +169,7 @@ fn write() {
170 169
171#[test] 170#[test]
172fn infer_std_crash_2() { 171fn infer_std_crash_2() {
173 covers!(type_var_resolves_to_int_var); 172 mark::check!(type_var_resolves_to_int_var);
174 // caused "equating two type variables, ...", taken from std 173 // caused "equating two type variables, ...", taken from std
175 assert_snapshot!( 174 assert_snapshot!(
176 infer(r#" 175 infer(r#"
@@ -535,6 +534,66 @@ fn foo(b: Bar) {
535} 534}
536 535
537#[test] 536#[test]
537fn issue_4235_name_conflicts() {
538 assert_snapshot!(
539 infer(r#"
540struct FOO {}
541static FOO:FOO = FOO {};
542
543impl FOO {
544 fn foo(&self) {}
545}
546
547fn main() {
548 let a = &FOO;
549 a.foo();
550}
551"#), @r###"
552 32..38 'FOO {}': FOO
553 64..68 'self': &FOO
554 70..72 '{}': ()
555 86..120 '{ ...o(); }': ()
556 96..97 'a': &FOO
557 100..104 '&FOO': &FOO
558 101..104 'FOO': FOO
559 110..111 'a': &FOO
560 110..117 'a.foo()': ()
561"###
562 );
563}
564
565#[test]
566fn issue_4465_dollar_crate_at_type() {
567 assert_snapshot!(
568 infer(r#"
569pub struct Foo {}
570pub fn anything<T>() -> T {
571 loop {}
572}
573macro_rules! foo {
574 () => {{
575 let r: $crate::Foo = anything();
576 r
577 }};
578}
579fn main() {
580 let _a = foo!();
581}
582"#), @r###"
583 45..60 '{ loop {} }': T
584 51..58 'loop {}': !
585 56..58 '{}': ()
586 !0..31 '{letr:...g();r}': Foo
587 !4..5 'r': Foo
588 !18..26 'anything': fn anything<Foo>() -> Foo
589 !18..28 'anything()': Foo
590 !29..30 'r': Foo
591 164..188 '{ ...!(); }': ()
592 174..176 '_a': Foo
593"###);
594}
595
596#[test]
538fn issue_4053_diesel_where_clauses() { 597fn issue_4053_diesel_where_clauses() {
539 assert_snapshot!( 598 assert_snapshot!(
540 infer(r#" 599 infer(r#"
diff --git a/crates/ra_hir_ty/src/tests/simple.rs b/crates/ra_hir_ty/src/tests/simple.rs
index 56abc65b8..88309157b 100644
--- a/crates/ra_hir_ty/src/tests/simple.rs
+++ b/crates/ra_hir_ty/src/tests/simple.rs
@@ -179,7 +179,7 @@ fn test(a: u32, b: isize, c: !, d: &str) {
179 17..18 'b': isize 179 17..18 'b': isize
180 27..28 'c': ! 180 27..28 'c': !
181 33..34 'd': &str 181 33..34 'd': &str
182 42..121 '{ ...f32; }': ! 182 42..121 '{ ...f32; }': ()
183 48..49 'a': u32 183 48..49 'a': u32
184 55..56 'b': isize 184 55..56 'b': isize
185 62..63 'c': ! 185 62..63 'c': !
@@ -385,6 +385,26 @@ fn test(a: &u32, b: &mut u32, c: *const u32, d: *mut u32) {
385} 385}
386 386
387#[test] 387#[test]
388fn infer_raw_ref() {
389 assert_snapshot!(
390 infer(r#"
391fn test(a: i32) {
392 &raw mut a;
393 &raw const a;
394}
395"#),
396 @r###"
397 9..10 'a': i32
398 17..54 '{ ...t a; }': ()
399 23..33 '&raw mut a': *mut i32
400 32..33 'a': i32
401 39..51 '&raw const a': *const i32
402 50..51 'a': i32
403 "###
404 );
405}
406
407#[test]
388fn infer_literals() { 408fn infer_literals() {
389 assert_snapshot!( 409 assert_snapshot!(
390 infer(r##" 410 infer(r##"
@@ -414,7 +434,7 @@ fn test() {
414 27..31 '5f32': f32 434 27..31 '5f32': f32
415 37..41 '5f64': f64 435 37..41 '5f64': f64
416 47..54 '"hello"': &str 436 47..54 '"hello"': &str
417 60..68 'b"bytes"': &[u8] 437 60..68 'b"bytes"': &[u8; _]
418 74..77 ''c'': char 438 74..77 ''c'': char
419 83..87 'b'b'': u8 439 83..87 'b'b'': u8
420 93..97 '3.14': f64 440 93..97 '3.14': f64
@@ -422,7 +442,7 @@ fn test() {
422 113..118 'false': bool 442 113..118 'false': bool
423 124..128 'true': bool 443 124..128 'true': bool
424 134..202 'r#" ... "#': &str 444 134..202 'r#" ... "#': &str
425 208..218 'br#"yolo"#': &[u8] 445 208..218 'br#"yolo"#': &[u8; _]
426 "### 446 "###
427 ); 447 );
428} 448}
@@ -576,6 +596,50 @@ impl S {
576} 596}
577 597
578#[test] 598#[test]
599fn infer_self_as_path() {
600 assert_snapshot!(
601 infer(r#"
602struct S1;
603struct S2(isize);
604enum E {
605 V1,
606 V2(u32),
607}
608
609impl S1 {
610 fn test() {
611 Self;
612 }
613}
614impl S2 {
615 fn test() {
616 Self(1);
617 }
618}
619impl E {
620 fn test() {
621 Self::V1;
622 Self::V2(1);
623 }
624}
625"#),
626 @r###"
627 87..108 '{ ... }': ()
628 97..101 'Self': S1
629 135..159 '{ ... }': ()
630 145..149 'Self': S2(isize) -> S2
631 145..152 'Self(1)': S2
632 150..151 '1': isize
633 185..231 '{ ... }': ()
634 195..203 'Self::V1': E
635 213..221 'Self::V2': V2(u32) -> E
636 213..224 'Self::V2(1)': E
637 222..223 '1': u32
638 "###
639 );
640}
641
642#[test]
579fn infer_binary_op() { 643fn infer_binary_op() {
580 assert_snapshot!( 644 assert_snapshot!(
581 infer(r#" 645 infer(r#"
@@ -893,7 +957,7 @@ fn main(foo: Foo) {
893 51..107 'if tru... }': () 957 51..107 'if tru... }': ()
894 54..58 'true': bool 958 54..58 'true': bool
895 59..67 '{ }': () 959 59..67 '{ }': ()
896 73..107 'if fal... }': () 960 73..107 'if fal... }': i32
897 76..81 'false': bool 961 76..81 'false': bool
898 82..107 '{ ... }': i32 962 82..107 '{ ... }': i32
899 92..95 'foo': Foo 963 92..95 'foo': Foo
@@ -935,7 +999,7 @@ fn foo() {
935 29..33 'true': bool 999 29..33 'true': bool
936 34..51 '{ ... }': i32 1000 34..51 '{ ... }': i32
937 44..45 '1': i32 1001 44..45 '1': i32
938 57..80 '{ ... }': ! 1002 57..80 '{ ... }': i32
939 67..73 'return': ! 1003 67..73 'return': !
940 90..93 '_x2': i32 1004 90..93 '_x2': i32
941 96..149 'if tru... }': i32 1005 96..149 'if tru... }': i32
@@ -951,7 +1015,7 @@ fn foo() {
951 186..190 'true': bool 1015 186..190 'true': bool
952 194..195 '3': i32 1016 194..195 '3': i32
953 205..206 '_': bool 1017 205..206 '_': bool
954 210..241 '{ ... }': ! 1018 210..241 '{ ... }': i32
955 224..230 'return': ! 1019 224..230 'return': !
956 257..260 '_x4': i32 1020 257..260 '_x4': i32
957 263..320 'match ... }': i32 1021 263..320 'match ... }': i32
@@ -1687,7 +1751,7 @@ fn foo() -> u32 {
1687 17..59 '{ ...; }; }': () 1751 17..59 '{ ...; }; }': ()
1688 27..28 'x': || -> usize 1752 27..28 'x': || -> usize
1689 31..56 '|| -> ...n 1; }': || -> usize 1753 31..56 '|| -> ...n 1; }': || -> usize
1690 43..56 '{ return 1; }': ! 1754 43..56 '{ return 1; }': usize
1691 45..53 'return 1': ! 1755 45..53 'return 1': !
1692 52..53 '1': usize 1756 52..53 '1': usize
1693 "### 1757 "###
@@ -1706,7 +1770,7 @@ fn foo() -> u32 {
1706 17..48 '{ ...; }; }': () 1770 17..48 '{ ...; }; }': ()
1707 27..28 'x': || -> () 1771 27..28 'x': || -> ()
1708 31..45 '|| { return; }': || -> () 1772 31..45 '|| { return; }': || -> ()
1709 34..45 '{ return; }': ! 1773 34..45 '{ return; }': ()
1710 36..42 'return': ! 1774 36..42 'return': !
1711 "### 1775 "###
1712 ); 1776 );
@@ -1755,3 +1819,181 @@ fn main() {
1755 "### 1819 "###
1756 ); 1820 );
1757} 1821}
1822
1823#[test]
1824fn effects_smoke_test() {
1825 assert_snapshot!(
1826 infer(r#"
1827fn main() {
1828 let x = unsafe { 92 };
1829 let y = async { async { () }.await };
1830 let z = try { () };
1831 let t = 'a: { 92 };
1832}
1833"#),
1834 @r###"
1835 11..131 '{ ...2 }; }': ()
1836 21..22 'x': i32
1837 32..38 '{ 92 }': i32
1838 34..36 '92': i32
1839 48..49 'y': {unknown}
1840 58..80 '{ asyn...wait }': {unknown}
1841 60..78 'async ....await': {unknown}
1842 66..72 '{ () }': ()
1843 68..70 '()': ()
1844 90..91 'z': {unknown}
1845 94..104 'try { () }': {unknown}
1846 98..104 '{ () }': ()
1847 100..102 '()': ()
1848 114..115 't': i32
1849 122..128 '{ 92 }': i32
1850 124..126 '92': i32
1851 "###
1852 )
1853}
1854
1855#[test]
1856fn infer_generic_from_later_assignment() {
1857 assert_snapshot!(
1858 infer(r#"
1859enum Option<T> { Some(T), None }
1860use Option::*;
1861
1862fn test() {
1863 let mut end = None;
1864 loop {
1865 end = Some(true);
1866 }
1867}
1868"#),
1869 @r###"
1870 60..130 '{ ... } }': ()
1871 70..77 'mut end': Option<bool>
1872 80..84 'None': Option<bool>
1873 90..128 'loop {... }': !
1874 95..128 '{ ... }': ()
1875 105..108 'end': Option<bool>
1876 105..121 'end = ...(true)': ()
1877 111..115 'Some': Some<bool>(bool) -> Option<bool>
1878 111..121 'Some(true)': Option<bool>
1879 116..120 'true': bool
1880 "###
1881 );
1882}
1883
1884#[test]
1885fn infer_loop_break_with_val() {
1886 assert_snapshot!(
1887 infer(r#"
1888enum Option<T> { Some(T), None }
1889use Option::*;
1890
1891fn test() {
1892 let x = loop {
1893 if false {
1894 break None;
1895 }
1896
1897 break Some(true);
1898 };
1899}
1900"#),
1901 @r###"
1902 60..169 '{ ... }; }': ()
1903 70..71 'x': Option<bool>
1904 74..166 'loop {... }': Option<bool>
1905 79..166 '{ ... }': ()
1906 89..133 'if fal... }': ()
1907 92..97 'false': bool
1908 98..133 '{ ... }': ()
1909 112..122 'break None': !
1910 118..122 'None': Option<bool>
1911 143..159 'break ...(true)': !
1912 149..153 'Some': Some<bool>(bool) -> Option<bool>
1913 149..159 'Some(true)': Option<bool>
1914 154..158 'true': bool
1915 "###
1916 );
1917}
1918
1919#[test]
1920fn infer_loop_break_without_val() {
1921 assert_snapshot!(
1922 infer(r#"
1923enum Option<T> { Some(T), None }
1924use Option::*;
1925
1926fn test() {
1927 let x = loop {
1928 if false {
1929 break;
1930 }
1931 };
1932}
1933"#),
1934 @r###"
1935 60..137 '{ ... }; }': ()
1936 70..71 'x': ()
1937 74..134 'loop {... }': ()
1938 79..134 '{ ... }': ()
1939 89..128 'if fal... }': ()
1940 92..97 'false': bool
1941 98..128 '{ ... }': ()
1942 112..117 'break': !
1943 "###
1944 );
1945}
1946
1947#[test]
1948fn infer_labelled_break_with_val() {
1949 assert_snapshot!(
1950 infer(r#"
1951fn foo() {
1952 let _x = || 'outer: loop {
1953 let inner = 'inner: loop {
1954 let i = Default::default();
1955 if (break 'outer i) {
1956 loop { break 'inner 5i8; };
1957 } else if true {
1958 break 'inner 6;
1959 }
1960 break 7;
1961 };
1962 break inner < 8;
1963 };
1964}
1965"#),
1966 @r###"
1967 10..336 '{ ... }; }': ()
1968 20..22 '_x': || -> bool
1969 25..333 '|| 'ou... }': || -> bool
1970 28..333 ''outer... }': bool
1971 41..333 '{ ... }': ()
1972 55..60 'inner': i8
1973 63..301 ''inner... }': i8
1974 76..301 '{ ... }': ()
1975 94..95 'i': bool
1976 98..114 'Defaul...efault': {unknown}
1977 98..116 'Defaul...ault()': bool
1978 130..270 'if (br... }': ()
1979 134..148 'break 'outer i': !
1980 147..148 'i': bool
1981 150..209 '{ ... }': ()
1982 168..194 'loop {...5i8; }': !
1983 173..194 '{ brea...5i8; }': ()
1984 175..191 'break ...er 5i8': !
1985 188..191 '5i8': i8
1986 215..270 'if tru... }': ()
1987 218..222 'true': bool
1988 223..270 '{ ... }': ()
1989 241..255 'break 'inner 6': !
1990 254..255 '6': i8
1991 283..290 'break 7': !
1992 289..290 '7': i8
1993 311..326 'break inner < 8': !
1994 317..322 'inner': i8
1995 317..326 'inner < 8': bool
1996 325..326 '8': i8
1997 "###
1998 );
1999}
diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs
index e555c879a..e8778d419 100644
--- a/crates/ra_hir_ty/src/tests/traits.rs
+++ b/crates/ra_hir_ty/src/tests/traits.rs
@@ -1,10 +1,11 @@
1use insta::assert_snapshot; 1use insta::assert_snapshot;
2
3use ra_db::fixture::WithFixture; 2use ra_db::fixture::WithFixture;
3use test_utils::mark;
4 4
5use super::{infer, infer_with_mismatches, type_at, type_at_pos};
6use crate::test_db::TestDB; 5use crate::test_db::TestDB;
7 6
7use super::{infer, infer_with_mismatches, type_at, type_at_pos};
8
8#[test] 9#[test]
9fn infer_await() { 10fn infer_await() {
10 let (db, pos) = TestDB::with_position( 11 let (db, pos) = TestDB::with_position(
@@ -301,7 +302,7 @@ fn test() {
301 302
302#[test] 303#[test]
303fn trait_default_method_self_bound_implements_trait() { 304fn trait_default_method_self_bound_implements_trait() {
304 test_utils::covers!(trait_self_implements_self); 305 mark::check!(trait_self_implements_self);
305 assert_snapshot!( 306 assert_snapshot!(
306 infer(r#" 307 infer(r#"
307trait Trait { 308trait Trait {
@@ -324,7 +325,6 @@ trait Trait {
324 325
325#[test] 326#[test]
326fn trait_default_method_self_bound_implements_super_trait() { 327fn trait_default_method_self_bound_implements_super_trait() {
327 test_utils::covers!(trait_self_implements_self);
328 assert_snapshot!( 328 assert_snapshot!(
329 infer(r#" 329 infer(r#"
330trait SuperTrait { 330trait SuperTrait {
@@ -1617,6 +1617,138 @@ fn test<F: FnOnce(u32, u64) -> u128>(f: F) {
1617} 1617}
1618 1618
1619#[test] 1619#[test]
1620fn fn_ptr_and_item() {
1621 assert_snapshot!(
1622 infer(r#"
1623#[lang="fn_once"]
1624trait FnOnce<Args> {
1625 type Output;
1626
1627 fn call_once(self, args: Args) -> Self::Output;
1628}
1629
1630trait Foo<T> {
1631 fn foo(&self) -> T;
1632}
1633
1634struct Bar<T>(T);
1635
1636impl<A1, R, F: FnOnce(A1) -> R> Foo<(A1, R)> for Bar<F> {
1637 fn foo(&self) -> (A1, R) {}
1638}
1639
1640enum Opt<T> { None, Some(T) }
1641impl<T> Opt<T> {
1642 fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Opt<U> {}
1643}
1644
1645fn test() {
1646 let bar: Bar<fn(u8) -> u32>;
1647 bar.foo();
1648
1649 let opt: Opt<u8>;
1650 let f: fn(u8) -> u32;
1651 opt.map(f);
1652}
1653"#),
1654 @r###"
165575..79 'self': Self
165681..85 'args': Args
1657140..144 'self': &Self
1658244..248 'self': &Bar<F>
1659261..263 '{}': ()
1660347..351 'self': Opt<T>
1661353..354 'f': F
1662369..371 '{}': ()
1663385..501 '{ ...(f); }': ()
1664395..398 'bar': Bar<fn(u8) -> u32>
1665424..427 'bar': Bar<fn(u8) -> u32>
1666424..433 'bar.foo()': {unknown}
1667444..447 'opt': Opt<u8>
1668466..467 'f': fn(u8) -> u32
1669488..491 'opt': Opt<u8>
1670488..498 'opt.map(f)': Opt<FnOnce::Output<fn(u8) -> u32, (u8,)>>
1671496..497 'f': fn(u8) -> u32
1672"###
1673 );
1674}
1675
1676#[test]
1677fn fn_trait_deref_with_ty_default() {
1678 assert_snapshot!(
1679 infer(r#"
1680#[lang = "deref"]
1681trait Deref {
1682 type Target;
1683
1684 fn deref(&self) -> &Self::Target;
1685}
1686
1687#[lang="fn_once"]
1688trait FnOnce<Args> {
1689 type Output;
1690
1691 fn call_once(self, args: Args) -> Self::Output;
1692}
1693
1694struct Foo;
1695
1696impl Foo {
1697 fn foo(&self) -> usize {}
1698}
1699
1700struct Lazy<T, F = fn() -> T>(F);
1701
1702impl<T, F> Lazy<T, F> {
1703 pub fn new(f: F) -> Lazy<T, F> {}
1704}
1705
1706impl<T, F: FnOnce() -> T> Deref for Lazy<T, F> {
1707 type Target = T;
1708}
1709
1710fn test() {
1711 let lazy1: Lazy<Foo, _> = Lazy::new(|| Foo);
1712 let r1 = lazy1.foo();
1713
1714 fn make_foo_fn() -> Foo {}
1715 let make_foo_fn_ptr: fn() -> Foo = make_foo_fn;
1716 let lazy2: Lazy<Foo, _> = Lazy::new(make_foo_fn_ptr);
1717 let r2 = lazy2.foo();
1718}
1719"#),
1720 @r###"
172165..69 'self': &Self
1722166..170 'self': Self
1723172..176 'args': Args
1724240..244 'self': &Foo
1725255..257 '{}': ()
1726335..336 'f': F
1727355..357 '{}': ()
1728444..690 '{ ...o(); }': ()
1729454..459 'lazy1': Lazy<Foo, fn() -> T>
1730476..485 'Lazy::new': fn new<Foo, fn() -> T>(fn() -> T) -> Lazy<Foo, fn() -> T>
1731476..493 'Lazy::...| Foo)': Lazy<Foo, fn() -> T>
1732486..492 '|| Foo': || -> T
1733489..492 'Foo': Foo
1734503..505 'r1': {unknown}
1735508..513 'lazy1': Lazy<Foo, fn() -> T>
1736508..519 'lazy1.foo()': {unknown}
1737561..576 'make_foo_fn_ptr': fn() -> Foo
1738592..603 'make_foo_fn': fn make_foo_fn() -> Foo
1739613..618 'lazy2': Lazy<Foo, fn() -> T>
1740635..644 'Lazy::new': fn new<Foo, fn() -> T>(fn() -> T) -> Lazy<Foo, fn() -> T>
1741635..661 'Lazy::...n_ptr)': Lazy<Foo, fn() -> T>
1742645..660 'make_foo_fn_ptr': fn() -> Foo
1743671..673 'r2': {unknown}
1744676..681 'lazy2': Lazy<Foo, fn() -> T>
1745676..687 'lazy2.foo()': {unknown}
1746550..552 '{}': ()
1747"###
1748 );
1749}
1750
1751#[test]
1620fn closure_1() { 1752fn closure_1() {
1621 assert_snapshot!( 1753 assert_snapshot!(
1622 infer(r#" 1754 infer(r#"
@@ -2055,7 +2187,7 @@ fn test<I: Iterator<Item: Iterator<Item = u32>>>() {
2055#[test] 2187#[test]
2056fn proc_macro_server_types() { 2188fn proc_macro_server_types() {
2057 assert_snapshot!( 2189 assert_snapshot!(
2058 infer_with_mismatches(r#" 2190 infer(r#"
2059macro_rules! with_api { 2191macro_rules! with_api {
2060 ($S:ident, $self:ident, $m:ident) => { 2192 ($S:ident, $self:ident, $m:ident) => {
2061 $m! { 2193 $m! {
@@ -2069,9 +2201,9 @@ macro_rules! with_api {
2069} 2201}
2070macro_rules! associated_item { 2202macro_rules! associated_item {
2071 (type TokenStream) => 2203 (type TokenStream) =>
2072 (type TokenStream: 'static + Clone;); 2204 (type TokenStream: 'static;);
2073 (type Group) => 2205 (type Group) =>
2074 (type Group: 'static + Clone;); 2206 (type Group: 'static;);
2075 ($($item:tt)*) => ($($item)*;) 2207 ($($item:tt)*) => ($($item)*;)
2076} 2208}
2077macro_rules! declare_server_traits { 2209macro_rules! declare_server_traits {
@@ -2083,21 +2215,23 @@ macro_rules! declare_server_traits {
2083 } 2215 }
2084 2216
2085 $(pub trait $name: Types { 2217 $(pub trait $name: Types {
2086 $(associated_item!(fn $method(&mut self, $($arg: $arg_ty),*) $(-> $ret_ty)?);)* 2218 $(associated_item!(fn $method($($arg: $arg_ty),*) $(-> $ret_ty)?);)*
2087 })* 2219 })*
2088 2220
2089 pub trait Server: Types $(+ $name)* {} 2221 pub trait Server: Types $(+ $name)* {}
2090 impl<S: Types $(+ $name)*> Server for S {} 2222 impl<S: Types $(+ $name)*> Server for S {}
2091 } 2223 }
2092} 2224}
2225
2093with_api!(Self, self_, declare_server_traits); 2226with_api!(Self, self_, declare_server_traits);
2094struct Group {} 2227struct G {}
2095struct TokenStream {} 2228struct T {}
2096struct Rustc; 2229struct Rustc;
2097impl Types for Rustc { 2230impl Types for Rustc {
2098 type TokenStream = TokenStream; 2231 type TokenStream = T;
2099 type Group = Group; 2232 type Group = G;
2100} 2233}
2234
2101fn make<T>() -> T { loop {} } 2235fn make<T>() -> T { loop {} }
2102impl TokenStream for Rustc { 2236impl TokenStream for Rustc {
2103 fn new() -> Self::TokenStream { 2237 fn new() -> Self::TokenStream {
@@ -2105,17 +2239,17 @@ impl TokenStream for Rustc {
2105 make() 2239 make()
2106 } 2240 }
2107} 2241}
2108"#, true), 2242"#),
2109 @r###" 2243 @r###"
2110 1115..1126 '{ loop {} }': T 2244 1062..1073 '{ loop {} }': T
2111 1117..1124 'loop {}': ! 2245 1064..1071 'loop {}': !
2112 1122..1124 '{}': () 2246 1069..1071 '{}': ()
2113 1190..1253 '{ ... }': {unknown} 2247 1137..1200 '{ ... }': T
2114 1204..1209 'group': {unknown} 2248 1151..1156 'group': G
2115 1225..1229 'make': fn make<{unknown}>() -> {unknown} 2249 1172..1176 'make': fn make<G>() -> G
2116 1225..1231 'make()': {unknown} 2250 1172..1178 'make()': G
2117 1241..1245 'make': fn make<{unknown}>() -> {unknown} 2251 1188..1192 'make': fn make<T>() -> T
2118 1241..1247 'make()': {unknown} 2252 1188..1194 'make()': T
2119 "### 2253 "###
2120 ); 2254 );
2121} 2255}
@@ -2468,3 +2602,199 @@ fn test(x: &dyn Foo) {
2468 "### 2602 "###
2469 ); 2603 );
2470} 2604}
2605
2606#[test]
2607fn builtin_copy() {
2608 assert_snapshot!(
2609 infer_with_mismatches(r#"
2610#[lang = "copy"]
2611trait Copy {}
2612
2613struct IsCopy;
2614impl Copy for IsCopy {}
2615struct NotCopy;
2616
2617trait Test { fn test(&self) -> bool; }
2618impl<T: Copy> Test for T {}
2619
2620fn test() {
2621 IsCopy.test();
2622 NotCopy.test();
2623 (IsCopy, IsCopy).test();
2624 (IsCopy, NotCopy).test();
2625}
2626"#, true),
2627 @r###"
2628 111..115 'self': &Self
2629 167..268 '{ ...t(); }': ()
2630 173..179 'IsCopy': IsCopy
2631 173..186 'IsCopy.test()': bool
2632 192..199 'NotCopy': NotCopy
2633 192..206 'NotCopy.test()': {unknown}
2634 212..228 '(IsCop...sCopy)': (IsCopy, IsCopy)
2635 212..235 '(IsCop...test()': bool
2636 213..219 'IsCopy': IsCopy
2637 221..227 'IsCopy': IsCopy
2638 241..258 '(IsCop...tCopy)': (IsCopy, NotCopy)
2639 241..265 '(IsCop...test()': {unknown}
2640 242..248 'IsCopy': IsCopy
2641 250..257 'NotCopy': NotCopy
2642 "###
2643 );
2644}
2645
2646#[test]
2647fn builtin_fn_def_copy() {
2648 assert_snapshot!(
2649 infer_with_mismatches(r#"
2650#[lang = "copy"]
2651trait Copy {}
2652
2653fn foo() {}
2654fn bar<T: Copy>(T) -> T {}
2655struct Struct(usize);
2656enum Enum { Variant(usize) }
2657
2658trait Test { fn test(&self) -> bool; }
2659impl<T: Copy> Test for T {}
2660
2661fn test() {
2662 foo.test();
2663 bar.test();
2664 Struct.test();
2665 Enum::Variant.test();
2666}
2667"#, true),
2668 @r###"
2669 42..44 '{}': ()
2670 61..62 'T': {unknown}
2671 69..71 '{}': ()
2672 69..71: expected T, got ()
2673 146..150 'self': &Self
2674 202..282 '{ ...t(); }': ()
2675 208..211 'foo': fn foo()
2676 208..218 'foo.test()': bool
2677 224..227 'bar': fn bar<{unknown}>({unknown}) -> {unknown}
2678 224..234 'bar.test()': bool
2679 240..246 'Struct': Struct(usize) -> Struct
2680 240..253 'Struct.test()': bool
2681 259..272 'Enum::Variant': Variant(usize) -> Enum
2682 259..279 'Enum::...test()': bool
2683 "###
2684 );
2685}
2686
2687#[test]
2688fn builtin_fn_ptr_copy() {
2689 assert_snapshot!(
2690 infer_with_mismatches(r#"
2691#[lang = "copy"]
2692trait Copy {}
2693
2694trait Test { fn test(&self) -> bool; }
2695impl<T: Copy> Test for T {}
2696
2697fn test(f1: fn(), f2: fn(usize) -> u8, f3: fn(u8, u8) -> &u8) {
2698 f1.test();
2699 f2.test();
2700 f3.test();
2701}
2702"#, true),
2703 @r###"
2704 55..59 'self': &Self
2705 109..111 'f1': fn()
2706 119..121 'f2': fn(usize) -> u8
2707 140..142 'f3': fn(u8, u8) -> &u8
2708 163..211 '{ ...t(); }': ()
2709 169..171 'f1': fn()
2710 169..178 'f1.test()': bool
2711 184..186 'f2': fn(usize) -> u8
2712 184..193 'f2.test()': bool
2713 199..201 'f3': fn(u8, u8) -> &u8
2714 199..208 'f3.test()': bool
2715 "###
2716 );
2717}
2718
2719#[test]
2720fn builtin_sized() {
2721 assert_snapshot!(
2722 infer_with_mismatches(r#"
2723#[lang = "sized"]
2724trait Sized {}
2725
2726trait Test { fn test(&self) -> bool; }
2727impl<T: Sized> Test for T {}
2728
2729fn test() {
2730 1u8.test();
2731 (*"foo").test(); // not Sized
2732 (1u8, 1u8).test();
2733 (1u8, *"foo").test(); // not Sized
2734}
2735"#, true),
2736 @r###"
2737 57..61 'self': &Self
2738 114..229 '{ ...ized }': ()
2739 120..123 '1u8': u8
2740 120..130 '1u8.test()': bool
2741 136..151 '(*"foo").test()': {unknown}
2742 137..143 '*"foo"': str
2743 138..143 '"foo"': &str
2744 170..180 '(1u8, 1u8)': (u8, u8)
2745 170..187 '(1u8, ...test()': bool
2746 171..174 '1u8': u8
2747 176..179 '1u8': u8
2748 193..206 '(1u8, *"foo")': (u8, str)
2749 193..213 '(1u8, ...test()': {unknown}
2750 194..197 '1u8': u8
2751 199..205 '*"foo"': str
2752 200..205 '"foo"': &str
2753 "###
2754 );
2755}
2756
2757#[test]
2758fn integer_range_iterate() {
2759 let t = type_at(
2760 r#"
2761//- /main.rs crate:main deps:std
2762fn test() {
2763 for x in 0..100 { x<|>; }
2764}
2765
2766//- /std.rs crate:std
2767pub mod ops {
2768 pub struct Range<Idx> {
2769 pub start: Idx,
2770 pub end: Idx,
2771 }
2772}
2773
2774pub mod iter {
2775 pub trait Iterator {
2776 type Item;
2777 }
2778
2779 pub trait IntoIterator {
2780 type Item;
2781 type IntoIter: Iterator<Item = Self::Item>;
2782 }
2783
2784 impl<T> IntoIterator for T where T: Iterator {
2785 type Item = <T as Iterator>::Item;
2786 type IntoIter = Self;
2787 }
2788}
2789
2790trait Step {}
2791impl Step for i32 {}
2792impl Step for i64 {}
2793
2794impl<A: Step> iter::Iterator for ops::Range<A> {
2795 type Item = A;
2796}
2797"#,
2798 );
2799 assert_eq!(t, "i32");
2800}
diff --git a/crates/ra_hir_ty/src/traits/builtin.rs b/crates/ra_hir_ty/src/traits/builtin.rs
index ccab246bf..88a422d2c 100644
--- a/crates/ra_hir_ty/src/traits/builtin.rs
+++ b/crates/ra_hir_ty/src/traits/builtin.rs
@@ -290,8 +290,7 @@ fn trait_object_unsize_impl_datum(
290 let self_trait_ref = TraitRef { trait_, substs: self_substs }; 290 let self_trait_ref = TraitRef { trait_, substs: self_substs };
291 let where_clauses = vec![GenericPredicate::Implemented(self_trait_ref)]; 291 let where_clauses = vec![GenericPredicate::Implemented(self_trait_ref)];
292 292
293 let impl_substs = 293 let impl_substs = Substs::builder(2).push(self_ty).push(Ty::Dyn(target_bounds.into())).build();
294 Substs::builder(2).push(self_ty).push(Ty::Dyn(target_bounds.clone().into())).build();
295 294
296 let trait_ref = TraitRef { trait_: unsize_trait, substs: impl_substs }; 295 let trait_ref = TraitRef { trait_: unsize_trait, substs: impl_substs };
297 296
diff --git a/crates/ra_hir_ty/src/traits/chalk.rs b/crates/ra_hir_ty/src/traits/chalk.rs
index 1ccb7c3b4..61de3cc30 100644
--- a/crates/ra_hir_ty/src/traits/chalk.rs
+++ b/crates/ra_hir_ty/src/traits/chalk.rs
@@ -1,298 +1,29 @@
1//! Conversion code from/to Chalk. 1//! Conversion code from/to Chalk.
2use std::{fmt, sync::Arc}; 2use std::sync::Arc;
3 3
4use log::debug; 4use log::debug;
5 5
6use chalk_ir::{ 6use chalk_ir::{fold::shift::Shift, GenericArg, TypeName};
7 cast::Cast, fold::shift::Shift, interner::HasInterner, Goal, GoalData, Parameter, 7use chalk_solve::rust_ir::{self, WellKnownTrait};
8 PlaceholderIndex, TypeName, UniverseIndex,
9};
10 8
11use hir_def::{AssocContainerId, AssocItemId, GenericDefId, HasModule, Lookup, TypeAliasId}; 9use hir_def::{
12use ra_db::{ 10 lang_item::{lang_attr, LangItemTarget},
13 salsa::{InternId, InternKey}, 11 AssocContainerId, AssocItemId, HasModule, Lookup, TypeAliasId,
14 CrateId,
15}; 12};
13use ra_db::{salsa::InternKey, CrateId};
16 14
17use super::{builtin, AssocTyValue, Canonical, ChalkContext, Impl, Obligation}; 15use super::{builtin, AssocTyValue, ChalkContext, Impl};
18use crate::{ 16use crate::{
19 db::HirDatabase, display::HirDisplay, method_resolution::TyFingerprint, utils::generics, 17 db::HirDatabase, display::HirDisplay, method_resolution::TyFingerprint, utils::generics,
20 ApplicationTy, DebruijnIndex, GenericPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor, 18 CallableDef, DebruijnIndex, GenericPredicate, Substs, Ty, TypeCtor,
21}; 19};
20use mapping::{convert_where_clauses, generic_predicate_to_inline_bound, make_binders};
22 21
23pub(super) mod tls; 22pub use self::interner::*;
24
25#[derive(Debug, Copy, Clone, Hash, PartialOrd, Ord, PartialEq, Eq)]
26pub struct Interner;
27
28impl chalk_ir::interner::Interner for Interner {
29 type InternedType = Box<chalk_ir::TyData<Self>>;
30 type InternedLifetime = chalk_ir::LifetimeData<Self>;
31 type InternedParameter = chalk_ir::ParameterData<Self>;
32 type InternedGoal = Arc<GoalData<Self>>;
33 type InternedGoals = Vec<Goal<Self>>;
34 type InternedSubstitution = Vec<Parameter<Self>>;
35 type InternedProgramClause = chalk_ir::ProgramClauseData<Self>;
36 type InternedProgramClauses = Arc<[chalk_ir::ProgramClause<Self>]>;
37 type InternedQuantifiedWhereClauses = Vec<chalk_ir::QuantifiedWhereClause<Self>>;
38 type InternedParameterKinds = Vec<chalk_ir::ParameterKind<()>>;
39 type InternedCanonicalVarKinds = Vec<chalk_ir::ParameterKind<UniverseIndex>>;
40 type Identifier = TypeAliasId;
41 type DefId = InternId;
42
43 fn debug_struct_id(
44 type_kind_id: StructId,
45 fmt: &mut fmt::Formatter<'_>,
46 ) -> Option<fmt::Result> {
47 tls::with_current_program(|prog| Some(prog?.debug_struct_id(type_kind_id, fmt)))
48 }
49
50 fn debug_trait_id(type_kind_id: TraitId, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> {
51 tls::with_current_program(|prog| Some(prog?.debug_trait_id(type_kind_id, fmt)))
52 }
53
54 fn debug_assoc_type_id(id: AssocTypeId, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> {
55 tls::with_current_program(|prog| Some(prog?.debug_assoc_type_id(id, fmt)))
56 }
57
58 fn debug_alias(
59 alias: &chalk_ir::AliasTy<Interner>,
60 fmt: &mut fmt::Formatter<'_>,
61 ) -> Option<fmt::Result> {
62 tls::with_current_program(|prog| Some(prog?.debug_alias(alias, fmt)))
63 }
64
65 fn debug_projection_ty(
66 proj: &chalk_ir::ProjectionTy<Interner>,
67 fmt: &mut fmt::Formatter<'_>,
68 ) -> Option<fmt::Result> {
69 tls::with_current_program(|prog| Some(prog?.debug_projection_ty(proj, fmt)))
70 }
71
72 fn debug_opaque_ty(
73 opaque_ty: &chalk_ir::OpaqueTy<Interner>,
74 fmt: &mut fmt::Formatter<'_>,
75 ) -> Option<fmt::Result> {
76 tls::with_current_program(|prog| Some(prog?.debug_opaque_ty(opaque_ty, fmt)))
77 }
78
79 fn debug_opaque_ty_id(
80 opaque_ty_id: chalk_ir::OpaqueTyId<Self>,
81 fmt: &mut fmt::Formatter<'_>,
82 ) -> Option<fmt::Result> {
83 tls::with_current_program(|prog| Some(prog?.debug_opaque_ty_id(opaque_ty_id, fmt)))
84 }
85
86 fn debug_ty(ty: &chalk_ir::Ty<Interner>, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> {
87 tls::with_current_program(|prog| Some(prog?.debug_ty(ty, fmt)))
88 }
89
90 fn debug_lifetime(
91 lifetime: &chalk_ir::Lifetime<Interner>,
92 fmt: &mut fmt::Formatter<'_>,
93 ) -> Option<fmt::Result> {
94 tls::with_current_program(|prog| Some(prog?.debug_lifetime(lifetime, fmt)))
95 }
96
97 fn debug_parameter(
98 parameter: &Parameter<Interner>,
99 fmt: &mut fmt::Formatter<'_>,
100 ) -> Option<fmt::Result> {
101 tls::with_current_program(|prog| Some(prog?.debug_parameter(parameter, fmt)))
102 }
103
104 fn debug_goal(goal: &Goal<Interner>, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> {
105 tls::with_current_program(|prog| Some(prog?.debug_goal(goal, fmt)))
106 }
107
108 fn debug_goals(
109 goals: &chalk_ir::Goals<Interner>,
110 fmt: &mut fmt::Formatter<'_>,
111 ) -> Option<fmt::Result> {
112 tls::with_current_program(|prog| Some(prog?.debug_goals(goals, fmt)))
113 }
114
115 fn debug_program_clause_implication(
116 pci: &chalk_ir::ProgramClauseImplication<Interner>,
117 fmt: &mut fmt::Formatter<'_>,
118 ) -> Option<fmt::Result> {
119 tls::with_current_program(|prog| Some(prog?.debug_program_clause_implication(pci, fmt)))
120 }
121
122 fn debug_application_ty(
123 application_ty: &chalk_ir::ApplicationTy<Interner>,
124 fmt: &mut fmt::Formatter<'_>,
125 ) -> Option<fmt::Result> {
126 tls::with_current_program(|prog| Some(prog?.debug_application_ty(application_ty, fmt)))
127 }
128 23
129 fn debug_substitution( 24pub(super) mod tls;
130 substitution: &chalk_ir::Substitution<Interner>, 25mod interner;
131 fmt: &mut fmt::Formatter<'_>, 26mod mapping;
132 ) -> Option<fmt::Result> {
133 tls::with_current_program(|prog| Some(prog?.debug_substitution(substitution, fmt)))
134 }
135
136 fn debug_separator_trait_ref(
137 separator_trait_ref: &chalk_ir::SeparatorTraitRef<Interner>,
138 fmt: &mut fmt::Formatter<'_>,
139 ) -> Option<fmt::Result> {
140 tls::with_current_program(|prog| {
141 Some(prog?.debug_separator_trait_ref(separator_trait_ref, fmt))
142 })
143 }
144
145 fn intern_ty(&self, ty: chalk_ir::TyData<Self>) -> Box<chalk_ir::TyData<Self>> {
146 Box::new(ty)
147 }
148
149 fn ty_data<'a>(&self, ty: &'a Box<chalk_ir::TyData<Self>>) -> &'a chalk_ir::TyData<Self> {
150 ty
151 }
152
153 fn intern_lifetime(
154 &self,
155 lifetime: chalk_ir::LifetimeData<Self>,
156 ) -> chalk_ir::LifetimeData<Self> {
157 lifetime
158 }
159
160 fn lifetime_data<'a>(
161 &self,
162 lifetime: &'a chalk_ir::LifetimeData<Self>,
163 ) -> &'a chalk_ir::LifetimeData<Self> {
164 lifetime
165 }
166
167 fn intern_parameter(
168 &self,
169 parameter: chalk_ir::ParameterData<Self>,
170 ) -> chalk_ir::ParameterData<Self> {
171 parameter
172 }
173
174 fn parameter_data<'a>(
175 &self,
176 parameter: &'a chalk_ir::ParameterData<Self>,
177 ) -> &'a chalk_ir::ParameterData<Self> {
178 parameter
179 }
180
181 fn intern_goal(&self, goal: GoalData<Self>) -> Arc<GoalData<Self>> {
182 Arc::new(goal)
183 }
184
185 fn intern_goals(&self, data: impl IntoIterator<Item = Goal<Self>>) -> Self::InternedGoals {
186 data.into_iter().collect()
187 }
188
189 fn goal_data<'a>(&self, goal: &'a Arc<GoalData<Self>>) -> &'a GoalData<Self> {
190 goal
191 }
192
193 fn goals_data<'a>(&self, goals: &'a Vec<Goal<Interner>>) -> &'a [Goal<Interner>] {
194 goals
195 }
196
197 fn intern_substitution<E>(
198 &self,
199 data: impl IntoIterator<Item = Result<Parameter<Self>, E>>,
200 ) -> Result<Vec<Parameter<Self>>, E> {
201 data.into_iter().collect()
202 }
203
204 fn substitution_data<'a>(
205 &self,
206 substitution: &'a Vec<Parameter<Self>>,
207 ) -> &'a [Parameter<Self>] {
208 substitution
209 }
210
211 fn intern_program_clause(
212 &self,
213 data: chalk_ir::ProgramClauseData<Self>,
214 ) -> chalk_ir::ProgramClauseData<Self> {
215 data
216 }
217
218 fn program_clause_data<'a>(
219 &self,
220 clause: &'a chalk_ir::ProgramClauseData<Self>,
221 ) -> &'a chalk_ir::ProgramClauseData<Self> {
222 clause
223 }
224
225 fn intern_program_clauses(
226 &self,
227 data: impl IntoIterator<Item = chalk_ir::ProgramClause<Self>>,
228 ) -> Arc<[chalk_ir::ProgramClause<Self>]> {
229 data.into_iter().collect()
230 }
231
232 fn program_clauses_data<'a>(
233 &self,
234 clauses: &'a Arc<[chalk_ir::ProgramClause<Self>]>,
235 ) -> &'a [chalk_ir::ProgramClause<Self>] {
236 &clauses
237 }
238
239 fn intern_quantified_where_clauses(
240 &self,
241 data: impl IntoIterator<Item = chalk_ir::QuantifiedWhereClause<Self>>,
242 ) -> Self::InternedQuantifiedWhereClauses {
243 data.into_iter().collect()
244 }
245
246 fn quantified_where_clauses_data<'a>(
247 &self,
248 clauses: &'a Self::InternedQuantifiedWhereClauses,
249 ) -> &'a [chalk_ir::QuantifiedWhereClause<Self>] {
250 clauses
251 }
252
253 fn intern_parameter_kinds(
254 &self,
255 data: impl IntoIterator<Item = chalk_ir::ParameterKind<()>>,
256 ) -> Self::InternedParameterKinds {
257 data.into_iter().collect()
258 }
259
260 fn parameter_kinds_data<'a>(
261 &self,
262 parameter_kinds: &'a Self::InternedParameterKinds,
263 ) -> &'a [chalk_ir::ParameterKind<()>] {
264 &parameter_kinds
265 }
266
267 fn intern_canonical_var_kinds(
268 &self,
269 data: impl IntoIterator<Item = chalk_ir::ParameterKind<UniverseIndex>>,
270 ) -> Self::InternedCanonicalVarKinds {
271 data.into_iter().collect()
272 }
273
274 fn canonical_var_kinds_data<'a>(
275 &self,
276 canonical_var_kinds: &'a Self::InternedCanonicalVarKinds,
277 ) -> &'a [chalk_ir::ParameterKind<UniverseIndex>] {
278 &canonical_var_kinds
279 }
280}
281
282impl chalk_ir::interner::HasInterner for Interner {
283 type Interner = Self;
284}
285
286pub type AssocTypeId = chalk_ir::AssocTypeId<Interner>;
287pub type AssociatedTyDatum = chalk_rust_ir::AssociatedTyDatum<Interner>;
288pub type TraitId = chalk_ir::TraitId<Interner>;
289pub type TraitDatum = chalk_rust_ir::TraitDatum<Interner>;
290pub type StructId = chalk_ir::StructId<Interner>;
291pub type StructDatum = chalk_rust_ir::StructDatum<Interner>;
292pub type ImplId = chalk_ir::ImplId<Interner>;
293pub type ImplDatum = chalk_rust_ir::ImplDatum<Interner>;
294pub type AssociatedTyValueId = chalk_rust_ir::AssociatedTyValueId<Interner>;
295pub type AssociatedTyValue = chalk_rust_ir::AssociatedTyValue<Interner>;
296 27
297pub(super) trait ToChalk { 28pub(super) trait ToChalk {
298 type Chalk; 29 type Chalk;
@@ -307,500 +38,6 @@ where
307 T::from_chalk(db, chalk) 38 T::from_chalk(db, chalk)
308} 39}
309 40
310impl ToChalk for Ty {
311 type Chalk = chalk_ir::Ty<Interner>;
312 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Ty<Interner> {
313 match self {
314 Ty::Apply(apply_ty) => {
315 let name = apply_ty.ctor.to_chalk(db);
316 let substitution = apply_ty.parameters.to_chalk(db);
317 chalk_ir::ApplicationTy { name, substitution }.cast(&Interner).intern(&Interner)
318 }
319 Ty::Projection(proj_ty) => {
320 let associated_ty_id = proj_ty.associated_ty.to_chalk(db);
321 let substitution = proj_ty.parameters.to_chalk(db);
322 chalk_ir::AliasTy::Projection(chalk_ir::ProjectionTy {
323 associated_ty_id,
324 substitution,
325 })
326 .cast(&Interner)
327 .intern(&Interner)
328 }
329 Ty::Placeholder(id) => {
330 let interned_id = db.intern_type_param_id(id);
331 PlaceholderIndex {
332 ui: UniverseIndex::ROOT,
333 idx: interned_id.as_intern_id().as_usize(),
334 }
335 .to_ty::<Interner>(&Interner)
336 }
337 Ty::Bound(idx) => chalk_ir::TyData::BoundVar(idx).intern(&Interner),
338 Ty::Infer(_infer_ty) => panic!("uncanonicalized infer ty"),
339 Ty::Dyn(predicates) => {
340 let where_clauses = chalk_ir::QuantifiedWhereClauses::from(
341 &Interner,
342 predicates.iter().filter(|p| !p.is_error()).cloned().map(|p| p.to_chalk(db)),
343 );
344 let bounded_ty = chalk_ir::DynTy { bounds: make_binders(where_clauses, 1) };
345 chalk_ir::TyData::Dyn(bounded_ty).intern(&Interner)
346 }
347 Ty::Opaque(_) | Ty::Unknown => {
348 let substitution = chalk_ir::Substitution::empty(&Interner);
349 let name = TypeName::Error;
350 chalk_ir::ApplicationTy { name, substitution }.cast(&Interner).intern(&Interner)
351 }
352 }
353 }
354 fn from_chalk(db: &dyn HirDatabase, chalk: chalk_ir::Ty<Interner>) -> Self {
355 match chalk.data(&Interner).clone() {
356 chalk_ir::TyData::Apply(apply_ty) => match apply_ty.name {
357 TypeName::Error => Ty::Unknown,
358 _ => {
359 let ctor = from_chalk(db, apply_ty.name);
360 let parameters = from_chalk(db, apply_ty.substitution);
361 Ty::Apply(ApplicationTy { ctor, parameters })
362 }
363 },
364 chalk_ir::TyData::Placeholder(idx) => {
365 assert_eq!(idx.ui, UniverseIndex::ROOT);
366 let interned_id = crate::db::GlobalTypeParamId::from_intern_id(
367 crate::salsa::InternId::from(idx.idx),
368 );
369 Ty::Placeholder(db.lookup_intern_type_param_id(interned_id))
370 }
371 chalk_ir::TyData::Alias(chalk_ir::AliasTy::Projection(proj)) => {
372 let associated_ty = from_chalk(db, proj.associated_ty_id);
373 let parameters = from_chalk(db, proj.substitution);
374 Ty::Projection(ProjectionTy { associated_ty, parameters })
375 }
376 chalk_ir::TyData::Alias(chalk_ir::AliasTy::Opaque(_)) => unimplemented!(),
377 chalk_ir::TyData::Function(_) => unimplemented!(),
378 chalk_ir::TyData::BoundVar(idx) => Ty::Bound(idx),
379 chalk_ir::TyData::InferenceVar(_iv) => Ty::Unknown,
380 chalk_ir::TyData::Dyn(where_clauses) => {
381 assert_eq!(where_clauses.bounds.binders.len(&Interner), 1);
382 let predicates = where_clauses
383 .bounds
384 .skip_binders()
385 .iter(&Interner)
386 .map(|c| from_chalk(db, c.clone()))
387 .collect();
388 Ty::Dyn(predicates)
389 }
390 }
391 }
392}
393
394impl ToChalk for Substs {
395 type Chalk = chalk_ir::Substitution<Interner>;
396
397 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Substitution<Interner> {
398 chalk_ir::Substitution::from(&Interner, self.iter().map(|ty| ty.clone().to_chalk(db)))
399 }
400
401 fn from_chalk(db: &dyn HirDatabase, parameters: chalk_ir::Substitution<Interner>) -> Substs {
402 let tys = parameters
403 .iter(&Interner)
404 .map(|p| match p.ty(&Interner) {
405 Some(ty) => from_chalk(db, ty.clone()),
406 None => unimplemented!(),
407 })
408 .collect();
409 Substs(tys)
410 }
411}
412
413impl ToChalk for TraitRef {
414 type Chalk = chalk_ir::TraitRef<Interner>;
415
416 fn to_chalk(self: TraitRef, db: &dyn HirDatabase) -> chalk_ir::TraitRef<Interner> {
417 let trait_id = self.trait_.to_chalk(db);
418 let substitution = self.substs.to_chalk(db);
419 chalk_ir::TraitRef { trait_id, substitution }
420 }
421
422 fn from_chalk(db: &dyn HirDatabase, trait_ref: chalk_ir::TraitRef<Interner>) -> Self {
423 let trait_ = from_chalk(db, trait_ref.trait_id);
424 let substs = from_chalk(db, trait_ref.substitution);
425 TraitRef { trait_, substs }
426 }
427}
428
429impl ToChalk for hir_def::TraitId {
430 type Chalk = TraitId;
431
432 fn to_chalk(self, _db: &dyn HirDatabase) -> TraitId {
433 chalk_ir::TraitId(self.as_intern_id())
434 }
435
436 fn from_chalk(_db: &dyn HirDatabase, trait_id: TraitId) -> hir_def::TraitId {
437 InternKey::from_intern_id(trait_id.0)
438 }
439}
440
441impl ToChalk for TypeCtor {
442 type Chalk = TypeName<Interner>;
443
444 fn to_chalk(self, db: &dyn HirDatabase) -> TypeName<Interner> {
445 match self {
446 TypeCtor::AssociatedType(type_alias) => {
447 let type_id = type_alias.to_chalk(db);
448 TypeName::AssociatedType(type_id)
449 }
450 _ => {
451 // other TypeCtors get interned and turned into a chalk StructId
452 let struct_id = db.intern_type_ctor(self).into();
453 TypeName::Struct(struct_id)
454 }
455 }
456 }
457
458 fn from_chalk(db: &dyn HirDatabase, type_name: TypeName<Interner>) -> TypeCtor {
459 match type_name {
460 TypeName::Struct(struct_id) => db.lookup_intern_type_ctor(struct_id.into()),
461 TypeName::AssociatedType(type_id) => TypeCtor::AssociatedType(from_chalk(db, type_id)),
462 TypeName::OpaqueType(_) => unreachable!(),
463 TypeName::Error => {
464 // this should not be reached, since we don't represent TypeName::Error with TypeCtor
465 unreachable!()
466 }
467 }
468 }
469}
470
471impl ToChalk for Impl {
472 type Chalk = ImplId;
473
474 fn to_chalk(self, db: &dyn HirDatabase) -> ImplId {
475 db.intern_chalk_impl(self).into()
476 }
477
478 fn from_chalk(db: &dyn HirDatabase, impl_id: ImplId) -> Impl {
479 db.lookup_intern_chalk_impl(impl_id.into())
480 }
481}
482
483impl ToChalk for TypeAliasId {
484 type Chalk = AssocTypeId;
485
486 fn to_chalk(self, _db: &dyn HirDatabase) -> AssocTypeId {
487 chalk_ir::AssocTypeId(self.as_intern_id())
488 }
489
490 fn from_chalk(_db: &dyn HirDatabase, type_alias_id: AssocTypeId) -> TypeAliasId {
491 InternKey::from_intern_id(type_alias_id.0)
492 }
493}
494
495impl ToChalk for AssocTyValue {
496 type Chalk = AssociatedTyValueId;
497
498 fn to_chalk(self, db: &dyn HirDatabase) -> AssociatedTyValueId {
499 db.intern_assoc_ty_value(self).into()
500 }
501
502 fn from_chalk(db: &dyn HirDatabase, assoc_ty_value_id: AssociatedTyValueId) -> AssocTyValue {
503 db.lookup_intern_assoc_ty_value(assoc_ty_value_id.into())
504 }
505}
506
507impl ToChalk for GenericPredicate {
508 type Chalk = chalk_ir::QuantifiedWhereClause<Interner>;
509
510 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::QuantifiedWhereClause<Interner> {
511 match self {
512 GenericPredicate::Implemented(trait_ref) => {
513 let chalk_trait_ref = trait_ref.to_chalk(db);
514 let chalk_trait_ref = chalk_trait_ref.shifted_in(&Interner);
515 make_binders(chalk_ir::WhereClause::Implemented(chalk_trait_ref), 0)
516 }
517 GenericPredicate::Projection(projection_pred) => {
518 let ty = projection_pred.ty.to_chalk(db).shifted_in(&Interner);
519 let projection = projection_pred.projection_ty.to_chalk(db).shifted_in(&Interner);
520 let alias = chalk_ir::AliasTy::Projection(projection);
521 make_binders(chalk_ir::WhereClause::AliasEq(chalk_ir::AliasEq { alias, ty }), 0)
522 }
523 GenericPredicate::Error => panic!("tried passing GenericPredicate::Error to Chalk"),
524 }
525 }
526
527 fn from_chalk(
528 db: &dyn HirDatabase,
529 where_clause: chalk_ir::QuantifiedWhereClause<Interner>,
530 ) -> GenericPredicate {
531 // we don't produce any where clauses with binders and can't currently deal with them
532 match where_clause
533 .skip_binders()
534 .shifted_out(&Interner)
535 .expect("unexpected bound vars in where clause")
536 {
537 chalk_ir::WhereClause::Implemented(tr) => {
538 GenericPredicate::Implemented(from_chalk(db, tr))
539 }
540 chalk_ir::WhereClause::AliasEq(projection_eq) => {
541 let projection_ty = from_chalk(
542 db,
543 match projection_eq.alias {
544 chalk_ir::AliasTy::Projection(p) => p,
545 _ => unimplemented!(),
546 },
547 );
548 let ty = from_chalk(db, projection_eq.ty);
549 GenericPredicate::Projection(super::ProjectionPredicate { projection_ty, ty })
550 }
551 }
552 }
553}
554
555impl ToChalk for ProjectionTy {
556 type Chalk = chalk_ir::ProjectionTy<Interner>;
557
558 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::ProjectionTy<Interner> {
559 chalk_ir::ProjectionTy {
560 associated_ty_id: self.associated_ty.to_chalk(db),
561 substitution: self.parameters.to_chalk(db),
562 }
563 }
564
565 fn from_chalk(
566 db: &dyn HirDatabase,
567 projection_ty: chalk_ir::ProjectionTy<Interner>,
568 ) -> ProjectionTy {
569 ProjectionTy {
570 associated_ty: from_chalk(db, projection_ty.associated_ty_id),
571 parameters: from_chalk(db, projection_ty.substitution),
572 }
573 }
574}
575
576impl ToChalk for super::ProjectionPredicate {
577 type Chalk = chalk_ir::AliasEq<Interner>;
578
579 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::AliasEq<Interner> {
580 chalk_ir::AliasEq {
581 alias: chalk_ir::AliasTy::Projection(self.projection_ty.to_chalk(db)),
582 ty: self.ty.to_chalk(db),
583 }
584 }
585
586 fn from_chalk(_db: &dyn HirDatabase, _normalize: chalk_ir::AliasEq<Interner>) -> Self {
587 unimplemented!()
588 }
589}
590
591impl ToChalk for Obligation {
592 type Chalk = chalk_ir::DomainGoal<Interner>;
593
594 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::DomainGoal<Interner> {
595 match self {
596 Obligation::Trait(tr) => tr.to_chalk(db).cast(&Interner),
597 Obligation::Projection(pr) => pr.to_chalk(db).cast(&Interner),
598 }
599 }
600
601 fn from_chalk(_db: &dyn HirDatabase, _goal: chalk_ir::DomainGoal<Interner>) -> Self {
602 unimplemented!()
603 }
604}
605
606impl<T> ToChalk for Canonical<T>
607where
608 T: ToChalk,
609 T::Chalk: HasInterner<Interner = Interner>,
610{
611 type Chalk = chalk_ir::Canonical<T::Chalk>;
612
613 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Canonical<T::Chalk> {
614 let parameter = chalk_ir::ParameterKind::Ty(chalk_ir::UniverseIndex::ROOT);
615 let value = self.value.to_chalk(db);
616 chalk_ir::Canonical {
617 value,
618 binders: chalk_ir::CanonicalVarKinds::from(&Interner, vec![parameter; self.num_vars]),
619 }
620 }
621
622 fn from_chalk(db: &dyn HirDatabase, canonical: chalk_ir::Canonical<T::Chalk>) -> Canonical<T> {
623 Canonical {
624 num_vars: canonical.binders.len(&Interner),
625 value: from_chalk(db, canonical.value),
626 }
627 }
628}
629
630impl ToChalk for Arc<super::TraitEnvironment> {
631 type Chalk = chalk_ir::Environment<Interner>;
632
633 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Environment<Interner> {
634 let mut clauses = Vec::new();
635 for pred in &self.predicates {
636 if pred.is_error() {
637 // for env, we just ignore errors
638 continue;
639 }
640 let program_clause: chalk_ir::ProgramClause<Interner> =
641 pred.clone().to_chalk(db).cast(&Interner);
642 clauses.push(program_clause.into_from_env_clause(&Interner));
643 }
644 chalk_ir::Environment::new(&Interner).add_clauses(&Interner, clauses)
645 }
646
647 fn from_chalk(
648 _db: &dyn HirDatabase,
649 _env: chalk_ir::Environment<Interner>,
650 ) -> Arc<super::TraitEnvironment> {
651 unimplemented!()
652 }
653}
654
655impl<T: ToChalk> ToChalk for super::InEnvironment<T>
656where
657 T::Chalk: chalk_ir::interner::HasInterner<Interner = Interner>,
658{
659 type Chalk = chalk_ir::InEnvironment<T::Chalk>;
660
661 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::InEnvironment<T::Chalk> {
662 chalk_ir::InEnvironment {
663 environment: self.environment.to_chalk(db),
664 goal: self.value.to_chalk(db),
665 }
666 }
667
668 fn from_chalk(
669 db: &dyn HirDatabase,
670 in_env: chalk_ir::InEnvironment<T::Chalk>,
671 ) -> super::InEnvironment<T> {
672 super::InEnvironment {
673 environment: from_chalk(db, in_env.environment),
674 value: from_chalk(db, in_env.goal),
675 }
676 }
677}
678
679impl ToChalk for builtin::BuiltinImplData {
680 type Chalk = ImplDatum;
681
682 fn to_chalk(self, db: &dyn HirDatabase) -> ImplDatum {
683 let impl_type = chalk_rust_ir::ImplType::External;
684 let where_clauses = self.where_clauses.into_iter().map(|w| w.to_chalk(db)).collect();
685
686 let impl_datum_bound =
687 chalk_rust_ir::ImplDatumBound { trait_ref: self.trait_ref.to_chalk(db), where_clauses };
688 let associated_ty_value_ids =
689 self.assoc_ty_values.into_iter().map(|v| v.to_chalk(db)).collect();
690 chalk_rust_ir::ImplDatum {
691 binders: make_binders(impl_datum_bound, self.num_vars),
692 impl_type,
693 polarity: chalk_rust_ir::Polarity::Positive,
694 associated_ty_value_ids,
695 }
696 }
697
698 fn from_chalk(_db: &dyn HirDatabase, _data: ImplDatum) -> Self {
699 unimplemented!()
700 }
701}
702
703impl ToChalk for builtin::BuiltinImplAssocTyValueData {
704 type Chalk = AssociatedTyValue;
705
706 fn to_chalk(self, db: &dyn HirDatabase) -> AssociatedTyValue {
707 let ty = self.value.to_chalk(db);
708 let value_bound = chalk_rust_ir::AssociatedTyValueBound { ty };
709
710 chalk_rust_ir::AssociatedTyValue {
711 associated_ty_id: self.assoc_ty_id.to_chalk(db),
712 impl_id: self.impl_.to_chalk(db),
713 value: make_binders(value_bound, self.num_vars),
714 }
715 }
716
717 fn from_chalk(
718 _db: &dyn HirDatabase,
719 _data: AssociatedTyValue,
720 ) -> builtin::BuiltinImplAssocTyValueData {
721 unimplemented!()
722 }
723}
724
725fn make_binders<T>(value: T, num_vars: usize) -> chalk_ir::Binders<T>
726where
727 T: HasInterner<Interner = Interner>,
728{
729 chalk_ir::Binders::new(
730 chalk_ir::ParameterKinds::from(
731 &Interner,
732 std::iter::repeat(chalk_ir::ParameterKind::Ty(())).take(num_vars),
733 ),
734 value,
735 )
736}
737
738fn convert_where_clauses(
739 db: &dyn HirDatabase,
740 def: GenericDefId,
741 substs: &Substs,
742) -> Vec<chalk_ir::QuantifiedWhereClause<Interner>> {
743 let generic_predicates = db.generic_predicates(def);
744 let mut result = Vec::with_capacity(generic_predicates.len());
745 for pred in generic_predicates.iter() {
746 if pred.value.is_error() {
747 // skip errored predicates completely
748 continue;
749 }
750 result.push(pred.clone().subst(substs).to_chalk(db));
751 }
752 result
753}
754
755fn generic_predicate_to_inline_bound(
756 db: &dyn HirDatabase,
757 pred: &GenericPredicate,
758 self_ty: &Ty,
759) -> Option<chalk_rust_ir::InlineBound<Interner>> {
760 // An InlineBound is like a GenericPredicate, except the self type is left out.
761 // We don't have a special type for this, but Chalk does.
762 match pred {
763 GenericPredicate::Implemented(trait_ref) => {
764 if &trait_ref.substs[0] != self_ty {
765 // we can only convert predicates back to type bounds if they
766 // have the expected self type
767 return None;
768 }
769 let args_no_self = trait_ref.substs[1..]
770 .iter()
771 .map(|ty| ty.clone().to_chalk(db).cast(&Interner))
772 .collect();
773 let trait_bound =
774 chalk_rust_ir::TraitBound { trait_id: trait_ref.trait_.to_chalk(db), args_no_self };
775 Some(chalk_rust_ir::InlineBound::TraitBound(trait_bound))
776 }
777 GenericPredicate::Projection(proj) => {
778 if &proj.projection_ty.parameters[0] != self_ty {
779 return None;
780 }
781 let trait_ = match proj.projection_ty.associated_ty.lookup(db.upcast()).container {
782 AssocContainerId::TraitId(t) => t,
783 _ => panic!("associated type not in trait"),
784 };
785 let args_no_self = proj.projection_ty.parameters[1..]
786 .iter()
787 .map(|ty| ty.clone().to_chalk(db).cast(&Interner))
788 .collect();
789 let alias_eq_bound = chalk_rust_ir::AliasEqBound {
790 value: proj.ty.clone().to_chalk(db),
791 trait_bound: chalk_rust_ir::TraitBound {
792 trait_id: trait_.to_chalk(db),
793 args_no_self,
794 },
795 associated_ty_id: proj.projection_ty.associated_ty.to_chalk(db),
796 parameters: Vec::new(), // FIXME we don't support generic associated types yet
797 };
798 Some(chalk_rust_ir::InlineBound::AliasEqBound(alias_eq_bound))
799 }
800 GenericPredicate::Error => None,
801 }
802}
803
804impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> { 41impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
805 fn associated_ty_data(&self, id: AssocTypeId) -> Arc<AssociatedTyDatum> { 42 fn associated_ty_data(&self, id: AssocTypeId) -> Arc<AssociatedTyDatum> {
806 self.db.associated_ty_data(id) 43 self.db.associated_ty_data(id)
@@ -808,16 +45,24 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
808 fn trait_datum(&self, trait_id: TraitId) -> Arc<TraitDatum> { 45 fn trait_datum(&self, trait_id: TraitId) -> Arc<TraitDatum> {
809 self.db.trait_datum(self.krate, trait_id) 46 self.db.trait_datum(self.krate, trait_id)
810 } 47 }
811 fn struct_datum(&self, struct_id: StructId) -> Arc<StructDatum> { 48 fn adt_datum(&self, struct_id: AdtId) -> Arc<StructDatum> {
812 self.db.struct_datum(self.krate, struct_id) 49 self.db.struct_datum(self.krate, struct_id)
813 } 50 }
814 fn impl_datum(&self, impl_id: ImplId) -> Arc<ImplDatum> { 51 fn impl_datum(&self, impl_id: ImplId) -> Arc<ImplDatum> {
815 self.db.impl_datum(self.krate, impl_id) 52 self.db.impl_datum(self.krate, impl_id)
816 } 53 }
54
55 fn fn_def_datum(
56 &self,
57 fn_def_id: chalk_ir::FnDefId<Interner>,
58 ) -> Arc<rust_ir::FnDefDatum<Interner>> {
59 self.db.fn_def_datum(self.krate, fn_def_id)
60 }
61
817 fn impls_for_trait( 62 fn impls_for_trait(
818 &self, 63 &self,
819 trait_id: TraitId, 64 trait_id: TraitId,
820 parameters: &[Parameter<Interner>], 65 parameters: &[GenericArg<Interner>],
821 ) -> Vec<ImplId> { 66 ) -> Vec<ImplId> {
822 debug!("impls_for_trait {:?}", trait_id); 67 debug!("impls_for_trait {:?}", trait_id);
823 let trait_: hir_def::TraitId = from_chalk(self.db, trait_id); 68 let trait_: hir_def::TraitId = from_chalk(self.db, trait_id);
@@ -848,7 +93,7 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
848 debug!("impls_for_trait returned {} impls", result.len()); 93 debug!("impls_for_trait returned {} impls", result.len());
849 result 94 result
850 } 95 }
851 fn impl_provided_for(&self, auto_trait_id: TraitId, struct_id: StructId) -> bool { 96 fn impl_provided_for(&self, auto_trait_id: TraitId, struct_id: AdtId) -> bool {
852 debug!("impl_provided_for {:?}, {:?}", auto_trait_id, struct_id); 97 debug!("impl_provided_for {:?}, {:?}", auto_trait_id, struct_id);
853 false // FIXME 98 false // FIXME
854 } 99 }
@@ -862,21 +107,20 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
862 // We don't do coherence checking (yet) 107 // We don't do coherence checking (yet)
863 unimplemented!() 108 unimplemented!()
864 } 109 }
865 fn as_struct_id(&self, id: &TypeName<Interner>) -> Option<StructId> {
866 match id {
867 TypeName::Struct(struct_id) => Some(*struct_id),
868 _ => None,
869 }
870 }
871 fn interner(&self) -> &Interner { 110 fn interner(&self) -> &Interner {
872 &Interner 111 &Interner
873 } 112 }
874 fn well_known_trait_id( 113 fn well_known_trait_id(
875 &self, 114 &self,
876 _well_known_trait: chalk_rust_ir::WellKnownTrait, 115 well_known_trait: rust_ir::WellKnownTrait,
877 ) -> Option<chalk_ir::TraitId<Interner>> { 116 ) -> Option<chalk_ir::TraitId<Interner>> {
878 // FIXME tell Chalk about well-known traits (here and in trait_datum) 117 let lang_attr = lang_attr_from_well_known_trait(well_known_trait);
879 None 118 let lang_items = self.db.crate_lang_items(self.krate);
119 let trait_ = match lang_items.target(lang_attr) {
120 Some(LangItemTarget::TraitId(trait_)) => trait_,
121 _ => return None,
122 };
123 Some(trait_.to_chalk(self.db))
880 } 124 }
881 125
882 fn program_clauses_for_env( 126 fn program_clauses_for_env(
@@ -889,9 +133,27 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
889 fn opaque_ty_data( 133 fn opaque_ty_data(
890 &self, 134 &self,
891 _id: chalk_ir::OpaqueTyId<Interner>, 135 _id: chalk_ir::OpaqueTyId<Interner>,
892 ) -> Arc<chalk_rust_ir::OpaqueTyDatum<Interner>> { 136 ) -> Arc<rust_ir::OpaqueTyDatum<Interner>> {
893 unimplemented!() 137 unimplemented!()
894 } 138 }
139
140 fn force_impl_for(
141 &self,
142 _well_known: rust_ir::WellKnownTrait,
143 _ty: &chalk_ir::TyData<Interner>,
144 ) -> Option<bool> {
145 // this method is mostly for rustc
146 None
147 }
148
149 fn is_object_safe(&self, _trait_id: chalk_ir::TraitId<Interner>) -> bool {
150 // FIXME: implement actual object safety
151 true
152 }
153
154 fn hidden_opaque_type(&self, _id: chalk_ir::OpaqueTyId<Interner>) -> chalk_ir::Ty<Interner> {
155 Ty::Unknown.to_chalk(self.db)
156 }
895} 157}
896 158
897pub(crate) fn program_clauses_for_chalk_env_query( 159pub(crate) fn program_clauses_for_chalk_env_query(
@@ -930,7 +192,7 @@ pub(crate) fn associated_ty_data_query(
930 .collect(); 192 .collect();
931 193
932 let where_clauses = convert_where_clauses(db, type_alias.into(), &bound_vars); 194 let where_clauses = convert_where_clauses(db, type_alias.into(), &bound_vars);
933 let bound_data = chalk_rust_ir::AssociatedTyDatumBound { bounds, where_clauses }; 195 let bound_data = rust_ir::AssociatedTyDatumBound { bounds, where_clauses };
934 let datum = AssociatedTyDatum { 196 let datum = AssociatedTyDatum {
935 trait_id: trait_.to_chalk(db), 197 trait_id: trait_.to_chalk(db),
936 id, 198 id,
@@ -951,7 +213,7 @@ pub(crate) fn trait_datum_query(
951 debug!("trait {:?} = {:?}", trait_id, trait_data.name); 213 debug!("trait {:?} = {:?}", trait_id, trait_data.name);
952 let generic_params = generics(db.upcast(), trait_.into()); 214 let generic_params = generics(db.upcast(), trait_.into());
953 let bound_vars = Substs::bound_vars(&generic_params, DebruijnIndex::INNERMOST); 215 let bound_vars = Substs::bound_vars(&generic_params, DebruijnIndex::INNERMOST);
954 let flags = chalk_rust_ir::TraitFlags { 216 let flags = rust_ir::TraitFlags {
955 auto: trait_data.auto, 217 auto: trait_data.auto,
956 upstream: trait_.lookup(db.upcast()).container.module(db.upcast()).krate != krate, 218 upstream: trait_.lookup(db.upcast()).container.module(db.upcast()).krate != krate,
957 non_enumerable: true, 219 non_enumerable: true,
@@ -963,8 +225,9 @@ pub(crate) fn trait_datum_query(
963 let where_clauses = convert_where_clauses(db, trait_.into(), &bound_vars); 225 let where_clauses = convert_where_clauses(db, trait_.into(), &bound_vars);
964 let associated_ty_ids = 226 let associated_ty_ids =
965 trait_data.associated_types().map(|type_alias| type_alias.to_chalk(db)).collect(); 227 trait_data.associated_types().map(|type_alias| type_alias.to_chalk(db)).collect();
966 let trait_datum_bound = chalk_rust_ir::TraitDatumBound { where_clauses }; 228 let trait_datum_bound = rust_ir::TraitDatumBound { where_clauses };
967 let well_known = None; // FIXME set this (depending on lang items) 229 let well_known =
230 lang_attr(db.upcast(), trait_).and_then(|name| well_known_trait_from_lang_attr(&name));
968 let trait_datum = TraitDatum { 231 let trait_datum = TraitDatum {
969 id: trait_id, 232 id: trait_id,
970 binders: make_binders(trait_datum_bound, bound_vars.len()), 233 binders: make_binders(trait_datum_bound, bound_vars.len()),
@@ -975,13 +238,32 @@ pub(crate) fn trait_datum_query(
975 Arc::new(trait_datum) 238 Arc::new(trait_datum)
976} 239}
977 240
241fn well_known_trait_from_lang_attr(name: &str) -> Option<WellKnownTrait> {
242 Some(match name {
243 "sized" => WellKnownTrait::SizedTrait,
244 "copy" => WellKnownTrait::CopyTrait,
245 "clone" => WellKnownTrait::CloneTrait,
246 "drop" => WellKnownTrait::DropTrait,
247 _ => return None,
248 })
249}
250
251fn lang_attr_from_well_known_trait(attr: WellKnownTrait) -> &'static str {
252 match attr {
253 WellKnownTrait::SizedTrait => "sized",
254 WellKnownTrait::CopyTrait => "copy",
255 WellKnownTrait::CloneTrait => "clone",
256 WellKnownTrait::DropTrait => "drop",
257 }
258}
259
978pub(crate) fn struct_datum_query( 260pub(crate) fn struct_datum_query(
979 db: &dyn HirDatabase, 261 db: &dyn HirDatabase,
980 krate: CrateId, 262 krate: CrateId,
981 struct_id: StructId, 263 struct_id: AdtId,
982) -> Arc<StructDatum> { 264) -> Arc<StructDatum> {
983 debug!("struct_datum {:?}", struct_id); 265 debug!("struct_datum {:?}", struct_id);
984 let type_ctor: TypeCtor = from_chalk(db, TypeName::Struct(struct_id)); 266 let type_ctor: TypeCtor = from_chalk(db, TypeName::Adt(struct_id));
985 debug!("struct {:?} = {:?}", struct_id, type_ctor); 267 debug!("struct {:?} = {:?}", struct_id, type_ctor);
986 let num_params = type_ctor.num_ty_params(db); 268 let num_params = type_ctor.num_ty_params(db);
987 let upstream = type_ctor.krate(db) != Some(krate); 269 let upstream = type_ctor.krate(db) != Some(krate);
@@ -993,12 +275,12 @@ pub(crate) fn struct_datum_query(
993 convert_where_clauses(db, generic_def, &bound_vars) 275 convert_where_clauses(db, generic_def, &bound_vars)
994 }) 276 })
995 .unwrap_or_else(Vec::new); 277 .unwrap_or_else(Vec::new);
996 let flags = chalk_rust_ir::StructFlags { 278 let flags = rust_ir::AdtFlags {
997 upstream, 279 upstream,
998 // FIXME set fundamental flag correctly 280 // FIXME set fundamental flag correctly
999 fundamental: false, 281 fundamental: false,
1000 }; 282 };
1001 let struct_datum_bound = chalk_rust_ir::StructDatumBound { 283 let struct_datum_bound = rust_ir::AdtDatumBound {
1002 fields: Vec::new(), // FIXME add fields (only relevant for auto traits) 284 fields: Vec::new(), // FIXME add fields (only relevant for auto traits)
1003 where_clauses, 285 where_clauses,
1004 }; 286 };
@@ -1038,9 +320,9 @@ fn impl_def_datum(
1038 let bound_vars = Substs::bound_vars(&generic_params, DebruijnIndex::INNERMOST); 320 let bound_vars = Substs::bound_vars(&generic_params, DebruijnIndex::INNERMOST);
1039 let trait_ = trait_ref.trait_; 321 let trait_ = trait_ref.trait_;
1040 let impl_type = if impl_id.lookup(db.upcast()).container.module(db.upcast()).krate == krate { 322 let impl_type = if impl_id.lookup(db.upcast()).container.module(db.upcast()).krate == krate {
1041 chalk_rust_ir::ImplType::Local 323 rust_ir::ImplType::Local
1042 } else { 324 } else {
1043 chalk_rust_ir::ImplType::External 325 rust_ir::ImplType::External
1044 }; 326 };
1045 let where_clauses = convert_where_clauses(db, impl_id.into(), &bound_vars); 327 let where_clauses = convert_where_clauses(db, impl_id.into(), &bound_vars);
1046 let negative = impl_data.is_negative; 328 let negative = impl_data.is_negative;
@@ -1053,13 +335,9 @@ fn impl_def_datum(
1053 ); 335 );
1054 let trait_ref = trait_ref.to_chalk(db); 336 let trait_ref = trait_ref.to_chalk(db);
1055 337
1056 let polarity = if negative { 338 let polarity = if negative { rust_ir::Polarity::Negative } else { rust_ir::Polarity::Positive };
1057 chalk_rust_ir::Polarity::Negative
1058 } else {
1059 chalk_rust_ir::Polarity::Positive
1060 };
1061 339
1062 let impl_datum_bound = chalk_rust_ir::ImplDatumBound { trait_ref, where_clauses }; 340 let impl_datum_bound = rust_ir::ImplDatumBound { trait_ref, where_clauses };
1063 let trait_data = db.trait_data(trait_); 341 let trait_data = db.trait_data(trait_);
1064 let associated_ty_value_ids = impl_data 342 let associated_ty_value_ids = impl_data
1065 .items 343 .items
@@ -1117,8 +395,8 @@ fn type_alias_associated_ty_value(
1117 .associated_type_by_name(&type_alias_data.name) 395 .associated_type_by_name(&type_alias_data.name)
1118 .expect("assoc ty value should not exist"); // validated when building the impl data as well 396 .expect("assoc ty value should not exist"); // validated when building the impl data as well
1119 let ty = db.ty(type_alias.into()); 397 let ty = db.ty(type_alias.into());
1120 let value_bound = chalk_rust_ir::AssociatedTyValueBound { ty: ty.value.to_chalk(db) }; 398 let value_bound = rust_ir::AssociatedTyValueBound { ty: ty.value.to_chalk(db) };
1121 let value = chalk_rust_ir::AssociatedTyValue { 399 let value = rust_ir::AssociatedTyValue {
1122 impl_id: Impl::ImplDef(impl_id).to_chalk(db), 400 impl_id: Impl::ImplDef(impl_id).to_chalk(db),
1123 associated_ty_id: assoc_ty.to_chalk(db), 401 associated_ty_id: assoc_ty.to_chalk(db),
1124 value: make_binders(value_bound, ty.num_binders), 402 value: make_binders(value_bound, ty.num_binders),
@@ -1126,15 +404,47 @@ fn type_alias_associated_ty_value(
1126 Arc::new(value) 404 Arc::new(value)
1127} 405}
1128 406
1129impl From<StructId> for crate::TypeCtorId { 407pub(crate) fn fn_def_datum_query(
1130 fn from(struct_id: StructId) -> Self { 408 db: &dyn HirDatabase,
1131 InternKey::from_intern_id(struct_id.0) 409 _krate: CrateId,
410 fn_def_id: FnDefId,
411) -> Arc<FnDefDatum> {
412 let callable_def: CallableDef = from_chalk(db, fn_def_id);
413 let generic_params = generics(db.upcast(), callable_def.into());
414 let sig = db.callable_item_signature(callable_def);
415 let bound_vars = Substs::bound_vars(&generic_params, DebruijnIndex::INNERMOST);
416 let where_clauses = convert_where_clauses(db, callable_def.into(), &bound_vars);
417 let bound = rust_ir::FnDefDatumBound {
418 // Note: Chalk doesn't actually use this information yet as far as I am aware, but we provide it anyway
419 argument_types: sig.value.params().iter().map(|ty| ty.clone().to_chalk(db)).collect(),
420 return_type: sig.value.ret().clone().to_chalk(db),
421 where_clauses,
422 };
423 let datum = FnDefDatum { id: fn_def_id, binders: make_binders(bound, sig.num_binders) };
424 Arc::new(datum)
425}
426
427impl From<AdtId> for crate::TypeCtorId {
428 fn from(struct_id: AdtId) -> Self {
429 struct_id.0
1132 } 430 }
1133} 431}
1134 432
1135impl From<crate::TypeCtorId> for StructId { 433impl From<crate::TypeCtorId> for AdtId {
1136 fn from(type_ctor_id: crate::TypeCtorId) -> Self { 434 fn from(type_ctor_id: crate::TypeCtorId) -> Self {
1137 chalk_ir::StructId(type_ctor_id.as_intern_id()) 435 chalk_ir::AdtId(type_ctor_id)
436 }
437}
438
439impl From<FnDefId> for crate::CallableDefId {
440 fn from(fn_def_id: FnDefId) -> Self {
441 InternKey::from_intern_id(fn_def_id.0)
442 }
443}
444
445impl From<crate::CallableDefId> for FnDefId {
446 fn from(callable_def_id: crate::CallableDefId) -> Self {
447 chalk_ir::FnDefId(callable_def_id.as_intern_id())
1138 } 448 }
1139} 449}
1140 450
@@ -1150,14 +460,14 @@ impl From<crate::traits::GlobalImplId> for ImplId {
1150 } 460 }
1151} 461}
1152 462
1153impl From<chalk_rust_ir::AssociatedTyValueId<Interner>> for crate::traits::AssocTyValueId { 463impl From<rust_ir::AssociatedTyValueId<Interner>> for crate::traits::AssocTyValueId {
1154 fn from(id: chalk_rust_ir::AssociatedTyValueId<Interner>) -> Self { 464 fn from(id: rust_ir::AssociatedTyValueId<Interner>) -> Self {
1155 Self::from_intern_id(id.0) 465 Self::from_intern_id(id.0)
1156 } 466 }
1157} 467}
1158 468
1159impl From<crate::traits::AssocTyValueId> for chalk_rust_ir::AssociatedTyValueId<Interner> { 469impl From<crate::traits::AssocTyValueId> for rust_ir::AssociatedTyValueId<Interner> {
1160 fn from(assoc_ty_value_id: crate::traits::AssocTyValueId) -> Self { 470 fn from(assoc_ty_value_id: crate::traits::AssocTyValueId) -> Self {
1161 chalk_rust_ir::AssociatedTyValueId(assoc_ty_value_id.as_intern_id()) 471 rust_ir::AssociatedTyValueId(assoc_ty_value_id.as_intern_id())
1162 } 472 }
1163} 473}
diff --git a/crates/ra_hir_ty/src/traits/chalk/interner.rs b/crates/ra_hir_ty/src/traits/chalk/interner.rs
new file mode 100644
index 000000000..e27074ba6
--- /dev/null
+++ b/crates/ra_hir_ty/src/traits/chalk/interner.rs
@@ -0,0 +1,353 @@
1//! Implementation of the Chalk `Interner` trait, which allows customizing the
2//! representation of the various objects Chalk deals with (types, goals etc.).
3
4use super::tls;
5use chalk_ir::{GenericArg, Goal, GoalData};
6use hir_def::TypeAliasId;
7use ra_db::salsa::InternId;
8use std::{fmt, sync::Arc};
9
10#[derive(Debug, Copy, Clone, Hash, PartialOrd, Ord, PartialEq, Eq)]
11pub struct Interner;
12
13pub type AssocTypeId = chalk_ir::AssocTypeId<Interner>;
14pub type AssociatedTyDatum = chalk_solve::rust_ir::AssociatedTyDatum<Interner>;
15pub type TraitId = chalk_ir::TraitId<Interner>;
16pub type TraitDatum = chalk_solve::rust_ir::TraitDatum<Interner>;
17pub type AdtId = chalk_ir::AdtId<Interner>;
18pub type StructDatum = chalk_solve::rust_ir::AdtDatum<Interner>;
19pub type ImplId = chalk_ir::ImplId<Interner>;
20pub type ImplDatum = chalk_solve::rust_ir::ImplDatum<Interner>;
21pub type AssociatedTyValueId = chalk_solve::rust_ir::AssociatedTyValueId<Interner>;
22pub type AssociatedTyValue = chalk_solve::rust_ir::AssociatedTyValue<Interner>;
23pub type FnDefId = chalk_ir::FnDefId<Interner>;
24pub type FnDefDatum = chalk_solve::rust_ir::FnDefDatum<Interner>;
25
26impl chalk_ir::interner::Interner for Interner {
27 type InternedType = Box<chalk_ir::TyData<Self>>; // FIXME use Arc?
28 type InternedLifetime = chalk_ir::LifetimeData<Self>;
29 type InternedConst = Arc<chalk_ir::ConstData<Self>>;
30 type InternedConcreteConst = ();
31 type InternedGenericArg = chalk_ir::GenericArgData<Self>;
32 type InternedGoal = Arc<GoalData<Self>>;
33 type InternedGoals = Vec<Goal<Self>>;
34 type InternedSubstitution = Vec<GenericArg<Self>>;
35 type InternedProgramClause = chalk_ir::ProgramClauseData<Self>;
36 type InternedProgramClauses = Arc<[chalk_ir::ProgramClause<Self>]>;
37 type InternedQuantifiedWhereClauses = Vec<chalk_ir::QuantifiedWhereClause<Self>>;
38 type InternedVariableKinds = Vec<chalk_ir::VariableKind<Self>>;
39 type InternedCanonicalVarKinds = Vec<chalk_ir::CanonicalVarKind<Self>>;
40 type DefId = InternId;
41 type InternedAdtId = crate::TypeCtorId;
42 type Identifier = TypeAliasId;
43
44 fn debug_adt_id(type_kind_id: AdtId, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> {
45 tls::with_current_program(|prog| Some(prog?.debug_struct_id(type_kind_id, fmt)))
46 }
47
48 fn debug_trait_id(type_kind_id: TraitId, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> {
49 tls::with_current_program(|prog| Some(prog?.debug_trait_id(type_kind_id, fmt)))
50 }
51
52 fn debug_assoc_type_id(id: AssocTypeId, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> {
53 tls::with_current_program(|prog| Some(prog?.debug_assoc_type_id(id, fmt)))
54 }
55
56 fn debug_alias(
57 alias: &chalk_ir::AliasTy<Interner>,
58 fmt: &mut fmt::Formatter<'_>,
59 ) -> Option<fmt::Result> {
60 tls::with_current_program(|prog| Some(prog?.debug_alias(alias, fmt)))
61 }
62
63 fn debug_projection_ty(
64 proj: &chalk_ir::ProjectionTy<Interner>,
65 fmt: &mut fmt::Formatter<'_>,
66 ) -> Option<fmt::Result> {
67 tls::with_current_program(|prog| Some(prog?.debug_projection_ty(proj, fmt)))
68 }
69
70 fn debug_opaque_ty(
71 opaque_ty: &chalk_ir::OpaqueTy<Interner>,
72 fmt: &mut fmt::Formatter<'_>,
73 ) -> Option<fmt::Result> {
74 tls::with_current_program(|prog| Some(prog?.debug_opaque_ty(opaque_ty, fmt)))
75 }
76
77 fn debug_opaque_ty_id(
78 opaque_ty_id: chalk_ir::OpaqueTyId<Self>,
79 fmt: &mut fmt::Formatter<'_>,
80 ) -> Option<fmt::Result> {
81 tls::with_current_program(|prog| Some(prog?.debug_opaque_ty_id(opaque_ty_id, fmt)))
82 }
83
84 fn debug_ty(ty: &chalk_ir::Ty<Interner>, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> {
85 tls::with_current_program(|prog| Some(prog?.debug_ty(ty, fmt)))
86 }
87
88 fn debug_lifetime(
89 lifetime: &chalk_ir::Lifetime<Interner>,
90 fmt: &mut fmt::Formatter<'_>,
91 ) -> Option<fmt::Result> {
92 tls::with_current_program(|prog| Some(prog?.debug_lifetime(lifetime, fmt)))
93 }
94
95 fn debug_generic_arg(
96 parameter: &GenericArg<Interner>,
97 fmt: &mut fmt::Formatter<'_>,
98 ) -> Option<fmt::Result> {
99 tls::with_current_program(|prog| Some(prog?.debug_generic_arg(parameter, fmt)))
100 }
101
102 fn debug_goal(goal: &Goal<Interner>, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> {
103 tls::with_current_program(|prog| Some(prog?.debug_goal(goal, fmt)))
104 }
105
106 fn debug_goals(
107 goals: &chalk_ir::Goals<Interner>,
108 fmt: &mut fmt::Formatter<'_>,
109 ) -> Option<fmt::Result> {
110 tls::with_current_program(|prog| Some(prog?.debug_goals(goals, fmt)))
111 }
112
113 fn debug_program_clause_implication(
114 pci: &chalk_ir::ProgramClauseImplication<Interner>,
115 fmt: &mut fmt::Formatter<'_>,
116 ) -> Option<fmt::Result> {
117 tls::with_current_program(|prog| Some(prog?.debug_program_clause_implication(pci, fmt)))
118 }
119
120 fn debug_application_ty(
121 application_ty: &chalk_ir::ApplicationTy<Interner>,
122 fmt: &mut fmt::Formatter<'_>,
123 ) -> Option<fmt::Result> {
124 tls::with_current_program(|prog| Some(prog?.debug_application_ty(application_ty, fmt)))
125 }
126
127 fn debug_substitution(
128 substitution: &chalk_ir::Substitution<Interner>,
129 fmt: &mut fmt::Formatter<'_>,
130 ) -> Option<fmt::Result> {
131 tls::with_current_program(|prog| Some(prog?.debug_substitution(substitution, fmt)))
132 }
133
134 fn debug_separator_trait_ref(
135 separator_trait_ref: &chalk_ir::SeparatorTraitRef<Interner>,
136 fmt: &mut fmt::Formatter<'_>,
137 ) -> Option<fmt::Result> {
138 tls::with_current_program(|prog| {
139 Some(prog?.debug_separator_trait_ref(separator_trait_ref, fmt))
140 })
141 }
142
143 fn debug_fn_def_id(
144 fn_def_id: chalk_ir::FnDefId<Self>,
145 fmt: &mut fmt::Formatter<'_>,
146 ) -> Option<fmt::Result> {
147 tls::with_current_program(|prog| Some(prog?.debug_fn_def_id(fn_def_id, fmt)))
148 }
149 fn debug_const(
150 constant: &chalk_ir::Const<Self>,
151 fmt: &mut fmt::Formatter<'_>,
152 ) -> Option<fmt::Result> {
153 tls::with_current_program(|prog| Some(prog?.debug_const(constant, fmt)))
154 }
155 fn debug_variable_kinds(
156 variable_kinds: &chalk_ir::VariableKinds<Self>,
157 fmt: &mut fmt::Formatter<'_>,
158 ) -> Option<fmt::Result> {
159 tls::with_current_program(|prog| Some(prog?.debug_variable_kinds(variable_kinds, fmt)))
160 }
161 fn debug_variable_kinds_with_angles(
162 variable_kinds: &chalk_ir::VariableKinds<Self>,
163 fmt: &mut fmt::Formatter<'_>,
164 ) -> Option<fmt::Result> {
165 tls::with_current_program(|prog| {
166 Some(prog?.debug_variable_kinds_with_angles(variable_kinds, fmt))
167 })
168 }
169 fn debug_canonical_var_kinds(
170 canonical_var_kinds: &chalk_ir::CanonicalVarKinds<Self>,
171 fmt: &mut fmt::Formatter<'_>,
172 ) -> Option<fmt::Result> {
173 tls::with_current_program(|prog| {
174 Some(prog?.debug_canonical_var_kinds(canonical_var_kinds, fmt))
175 })
176 }
177 fn debug_program_clause(
178 clause: &chalk_ir::ProgramClause<Self>,
179 fmt: &mut fmt::Formatter<'_>,
180 ) -> Option<fmt::Result> {
181 tls::with_current_program(|prog| Some(prog?.debug_program_clause(clause, fmt)))
182 }
183 fn debug_program_clauses(
184 clauses: &chalk_ir::ProgramClauses<Self>,
185 fmt: &mut fmt::Formatter<'_>,
186 ) -> Option<fmt::Result> {
187 tls::with_current_program(|prog| Some(prog?.debug_program_clauses(clauses, fmt)))
188 }
189 fn debug_quantified_where_clauses(
190 clauses: &chalk_ir::QuantifiedWhereClauses<Self>,
191 fmt: &mut fmt::Formatter<'_>,
192 ) -> Option<fmt::Result> {
193 tls::with_current_program(|prog| Some(prog?.debug_quantified_where_clauses(clauses, fmt)))
194 }
195
196 fn intern_ty(&self, ty: chalk_ir::TyData<Self>) -> Box<chalk_ir::TyData<Self>> {
197 Box::new(ty)
198 }
199
200 fn ty_data<'a>(&self, ty: &'a Box<chalk_ir::TyData<Self>>) -> &'a chalk_ir::TyData<Self> {
201 ty
202 }
203
204 fn intern_lifetime(
205 &self,
206 lifetime: chalk_ir::LifetimeData<Self>,
207 ) -> chalk_ir::LifetimeData<Self> {
208 lifetime
209 }
210
211 fn lifetime_data<'a>(
212 &self,
213 lifetime: &'a chalk_ir::LifetimeData<Self>,
214 ) -> &'a chalk_ir::LifetimeData<Self> {
215 lifetime
216 }
217
218 fn intern_const(&self, constant: chalk_ir::ConstData<Self>) -> Arc<chalk_ir::ConstData<Self>> {
219 Arc::new(constant)
220 }
221
222 fn const_data<'a>(
223 &self,
224 constant: &'a Arc<chalk_ir::ConstData<Self>>,
225 ) -> &'a chalk_ir::ConstData<Self> {
226 constant
227 }
228
229 fn const_eq(&self, _ty: &Box<chalk_ir::TyData<Self>>, _c1: &(), _c2: &()) -> bool {
230 true
231 }
232
233 fn intern_generic_arg(
234 &self,
235 parameter: chalk_ir::GenericArgData<Self>,
236 ) -> chalk_ir::GenericArgData<Self> {
237 parameter
238 }
239
240 fn generic_arg_data<'a>(
241 &self,
242 parameter: &'a chalk_ir::GenericArgData<Self>,
243 ) -> &'a chalk_ir::GenericArgData<Self> {
244 parameter
245 }
246
247 fn intern_goal(&self, goal: GoalData<Self>) -> Arc<GoalData<Self>> {
248 Arc::new(goal)
249 }
250
251 fn intern_goals<E>(
252 &self,
253 data: impl IntoIterator<Item = Result<Goal<Self>, E>>,
254 ) -> Result<Self::InternedGoals, E> {
255 data.into_iter().collect()
256 }
257
258 fn goal_data<'a>(&self, goal: &'a Arc<GoalData<Self>>) -> &'a GoalData<Self> {
259 goal
260 }
261
262 fn goals_data<'a>(&self, goals: &'a Vec<Goal<Interner>>) -> &'a [Goal<Interner>] {
263 goals
264 }
265
266 fn intern_substitution<E>(
267 &self,
268 data: impl IntoIterator<Item = Result<GenericArg<Self>, E>>,
269 ) -> Result<Vec<GenericArg<Self>>, E> {
270 data.into_iter().collect()
271 }
272
273 fn substitution_data<'a>(
274 &self,
275 substitution: &'a Vec<GenericArg<Self>>,
276 ) -> &'a [GenericArg<Self>] {
277 substitution
278 }
279
280 fn intern_program_clause(
281 &self,
282 data: chalk_ir::ProgramClauseData<Self>,
283 ) -> chalk_ir::ProgramClauseData<Self> {
284 data
285 }
286
287 fn program_clause_data<'a>(
288 &self,
289 clause: &'a chalk_ir::ProgramClauseData<Self>,
290 ) -> &'a chalk_ir::ProgramClauseData<Self> {
291 clause
292 }
293
294 fn intern_program_clauses<E>(
295 &self,
296 data: impl IntoIterator<Item = Result<chalk_ir::ProgramClause<Self>, E>>,
297 ) -> Result<Arc<[chalk_ir::ProgramClause<Self>]>, E> {
298 data.into_iter().collect()
299 }
300
301 fn program_clauses_data<'a>(
302 &self,
303 clauses: &'a Arc<[chalk_ir::ProgramClause<Self>]>,
304 ) -> &'a [chalk_ir::ProgramClause<Self>] {
305 &clauses
306 }
307
308 fn intern_quantified_where_clauses<E>(
309 &self,
310 data: impl IntoIterator<Item = Result<chalk_ir::QuantifiedWhereClause<Self>, E>>,
311 ) -> Result<Self::InternedQuantifiedWhereClauses, E> {
312 data.into_iter().collect()
313 }
314
315 fn quantified_where_clauses_data<'a>(
316 &self,
317 clauses: &'a Self::InternedQuantifiedWhereClauses,
318 ) -> &'a [chalk_ir::QuantifiedWhereClause<Self>] {
319 clauses
320 }
321
322 fn intern_generic_arg_kinds<E>(
323 &self,
324 data: impl IntoIterator<Item = Result<chalk_ir::VariableKind<Self>, E>>,
325 ) -> Result<Self::InternedVariableKinds, E> {
326 data.into_iter().collect()
327 }
328
329 fn variable_kinds_data<'a>(
330 &self,
331 parameter_kinds: &'a Self::InternedVariableKinds,
332 ) -> &'a [chalk_ir::VariableKind<Self>] {
333 &parameter_kinds
334 }
335
336 fn intern_canonical_var_kinds<E>(
337 &self,
338 data: impl IntoIterator<Item = Result<chalk_ir::CanonicalVarKind<Self>, E>>,
339 ) -> Result<Self::InternedCanonicalVarKinds, E> {
340 data.into_iter().collect()
341 }
342
343 fn canonical_var_kinds_data<'a>(
344 &self,
345 canonical_var_kinds: &'a Self::InternedCanonicalVarKinds,
346 ) -> &'a [chalk_ir::CanonicalVarKind<Self>] {
347 &canonical_var_kinds
348 }
349}
350
351impl chalk_ir::interner::HasInterner for Interner {
352 type Interner = Self;
353}
diff --git a/crates/ra_hir_ty/src/traits/chalk/mapping.rs b/crates/ra_hir_ty/src/traits/chalk/mapping.rs
new file mode 100644
index 000000000..5f6daf842
--- /dev/null
+++ b/crates/ra_hir_ty/src/traits/chalk/mapping.rs
@@ -0,0 +1,701 @@
1//! This module contains the implementations of the `ToChalk` trait, which
2//! handles conversion between our data types and their corresponding types in
3//! Chalk (in both directions); plus some helper functions for more specialized
4//! conversions.
5
6use chalk_ir::{
7 cast::Cast, fold::shift::Shift, interner::HasInterner, PlaceholderIndex, Scalar, TypeName,
8 UniverseIndex,
9};
10use chalk_solve::rust_ir;
11
12use hir_def::{type_ref::Mutability, AssocContainerId, GenericDefId, Lookup, TypeAliasId};
13use ra_db::salsa::InternKey;
14
15use crate::{
16 db::HirDatabase,
17 primitive::{FloatBitness, FloatTy, IntBitness, IntTy, Signedness, Uncertain},
18 traits::{builtin, AssocTyValue, Canonical, Impl, Obligation},
19 ApplicationTy, CallableDef, GenericPredicate, InEnvironment, ProjectionPredicate, ProjectionTy,
20 Substs, TraitEnvironment, TraitRef, Ty, TypeCtor,
21};
22
23use super::interner::*;
24use super::*;
25
26impl ToChalk for Ty {
27 type Chalk = chalk_ir::Ty<Interner>;
28 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Ty<Interner> {
29 match self {
30 Ty::Apply(apply_ty) => match apply_ty.ctor {
31 TypeCtor::Ref(m) => ref_to_chalk(db, m, apply_ty.parameters),
32 TypeCtor::FnPtr { num_args: _ } => {
33 let substitution = apply_ty.parameters.to_chalk(db).shifted_in(&Interner);
34 chalk_ir::TyData::Function(chalk_ir::Fn { num_binders: 0, substitution })
35 .intern(&Interner)
36 }
37 _ => {
38 let name = apply_ty.ctor.to_chalk(db);
39 let substitution = apply_ty.parameters.to_chalk(db);
40 chalk_ir::ApplicationTy { name, substitution }.cast(&Interner).intern(&Interner)
41 }
42 },
43 Ty::Projection(proj_ty) => {
44 let associated_ty_id = proj_ty.associated_ty.to_chalk(db);
45 let substitution = proj_ty.parameters.to_chalk(db);
46 chalk_ir::AliasTy::Projection(chalk_ir::ProjectionTy {
47 associated_ty_id,
48 substitution,
49 })
50 .cast(&Interner)
51 .intern(&Interner)
52 }
53 Ty::Placeholder(id) => {
54 let interned_id = db.intern_type_param_id(id);
55 PlaceholderIndex {
56 ui: UniverseIndex::ROOT,
57 idx: interned_id.as_intern_id().as_usize(),
58 }
59 .to_ty::<Interner>(&Interner)
60 }
61 Ty::Bound(idx) => chalk_ir::TyData::BoundVar(idx).intern(&Interner),
62 Ty::Infer(_infer_ty) => panic!("uncanonicalized infer ty"),
63 Ty::Dyn(predicates) => {
64 let where_clauses = chalk_ir::QuantifiedWhereClauses::from(
65 &Interner,
66 predicates.iter().filter(|p| !p.is_error()).cloned().map(|p| p.to_chalk(db)),
67 );
68 let bounded_ty = chalk_ir::DynTy { bounds: make_binders(where_clauses, 1) };
69 chalk_ir::TyData::Dyn(bounded_ty).intern(&Interner)
70 }
71 Ty::Opaque(_) | Ty::Unknown => {
72 let substitution = chalk_ir::Substitution::empty(&Interner);
73 let name = TypeName::Error;
74 chalk_ir::ApplicationTy { name, substitution }.cast(&Interner).intern(&Interner)
75 }
76 }
77 }
78 fn from_chalk(db: &dyn HirDatabase, chalk: chalk_ir::Ty<Interner>) -> Self {
79 match chalk.data(&Interner).clone() {
80 chalk_ir::TyData::Apply(apply_ty) => match apply_ty.name {
81 TypeName::Error => Ty::Unknown,
82 TypeName::Ref(m) => ref_from_chalk(db, m, apply_ty.substitution),
83 _ => {
84 let ctor = from_chalk(db, apply_ty.name);
85 let parameters = from_chalk(db, apply_ty.substitution);
86 Ty::Apply(ApplicationTy { ctor, parameters })
87 }
88 },
89 chalk_ir::TyData::Placeholder(idx) => {
90 assert_eq!(idx.ui, UniverseIndex::ROOT);
91 let interned_id = crate::db::GlobalTypeParamId::from_intern_id(
92 crate::salsa::InternId::from(idx.idx),
93 );
94 Ty::Placeholder(db.lookup_intern_type_param_id(interned_id))
95 }
96 chalk_ir::TyData::Alias(chalk_ir::AliasTy::Projection(proj)) => {
97 let associated_ty = from_chalk(db, proj.associated_ty_id);
98 let parameters = from_chalk(db, proj.substitution);
99 Ty::Projection(ProjectionTy { associated_ty, parameters })
100 }
101 chalk_ir::TyData::Alias(chalk_ir::AliasTy::Opaque(_)) => unimplemented!(),
102 chalk_ir::TyData::Function(chalk_ir::Fn { num_binders: _, substitution }) => {
103 let parameters: Substs = from_chalk(db, substitution);
104 Ty::Apply(ApplicationTy {
105 ctor: TypeCtor::FnPtr { num_args: (parameters.len() - 1) as u16 },
106 parameters,
107 })
108 }
109 chalk_ir::TyData::BoundVar(idx) => Ty::Bound(idx),
110 chalk_ir::TyData::InferenceVar(_iv, _kind) => Ty::Unknown,
111 chalk_ir::TyData::Dyn(where_clauses) => {
112 assert_eq!(where_clauses.bounds.binders.len(&Interner), 1);
113 let predicates = where_clauses
114 .bounds
115 .skip_binders()
116 .iter(&Interner)
117 .map(|c| from_chalk(db, c.clone()))
118 .collect();
119 Ty::Dyn(predicates)
120 }
121 }
122 }
123}
124
125const LIFETIME_PLACEHOLDER: PlaceholderIndex =
126 PlaceholderIndex { ui: UniverseIndex::ROOT, idx: usize::MAX };
127
128/// We currently don't model lifetimes, but Chalk does. So, we have to insert a
129/// fake lifetime here, because Chalks built-in logic may expect it to be there.
130fn ref_to_chalk(
131 db: &dyn HirDatabase,
132 mutability: Mutability,
133 subst: Substs,
134) -> chalk_ir::Ty<Interner> {
135 let arg = subst[0].clone().to_chalk(db);
136 let lifetime = LIFETIME_PLACEHOLDER.to_lifetime(&Interner);
137 chalk_ir::ApplicationTy {
138 name: TypeName::Ref(mutability.to_chalk(db)),
139 substitution: chalk_ir::Substitution::from(
140 &Interner,
141 vec![lifetime.cast(&Interner), arg.cast(&Interner)],
142 ),
143 }
144 .intern(&Interner)
145}
146
147/// Here we remove the lifetime from the type we got from Chalk.
148fn ref_from_chalk(
149 db: &dyn HirDatabase,
150 mutability: chalk_ir::Mutability,
151 subst: chalk_ir::Substitution<Interner>,
152) -> Ty {
153 let tys = subst
154 .iter(&Interner)
155 .filter_map(|p| Some(from_chalk(db, p.ty(&Interner)?.clone())))
156 .collect();
157 Ty::apply(TypeCtor::Ref(from_chalk(db, mutability)), Substs(tys))
158}
159
160impl ToChalk for Substs {
161 type Chalk = chalk_ir::Substitution<Interner>;
162
163 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Substitution<Interner> {
164 chalk_ir::Substitution::from(&Interner, self.iter().map(|ty| ty.clone().to_chalk(db)))
165 }
166
167 fn from_chalk(db: &dyn HirDatabase, parameters: chalk_ir::Substitution<Interner>) -> Substs {
168 let tys = parameters
169 .iter(&Interner)
170 .map(|p| match p.ty(&Interner) {
171 Some(ty) => from_chalk(db, ty.clone()),
172 None => unimplemented!(),
173 })
174 .collect();
175 Substs(tys)
176 }
177}
178
179impl ToChalk for TraitRef {
180 type Chalk = chalk_ir::TraitRef<Interner>;
181
182 fn to_chalk(self: TraitRef, db: &dyn HirDatabase) -> chalk_ir::TraitRef<Interner> {
183 let trait_id = self.trait_.to_chalk(db);
184 let substitution = self.substs.to_chalk(db);
185 chalk_ir::TraitRef { trait_id, substitution }
186 }
187
188 fn from_chalk(db: &dyn HirDatabase, trait_ref: chalk_ir::TraitRef<Interner>) -> Self {
189 let trait_ = from_chalk(db, trait_ref.trait_id);
190 let substs = from_chalk(db, trait_ref.substitution);
191 TraitRef { trait_, substs }
192 }
193}
194
195impl ToChalk for hir_def::TraitId {
196 type Chalk = TraitId;
197
198 fn to_chalk(self, _db: &dyn HirDatabase) -> TraitId {
199 chalk_ir::TraitId(self.as_intern_id())
200 }
201
202 fn from_chalk(_db: &dyn HirDatabase, trait_id: TraitId) -> hir_def::TraitId {
203 InternKey::from_intern_id(trait_id.0)
204 }
205}
206
207impl ToChalk for TypeCtor {
208 type Chalk = TypeName<Interner>;
209
210 fn to_chalk(self, db: &dyn HirDatabase) -> TypeName<Interner> {
211 match self {
212 TypeCtor::AssociatedType(type_alias) => {
213 let type_id = type_alias.to_chalk(db);
214 TypeName::AssociatedType(type_id)
215 }
216
217 TypeCtor::Bool => TypeName::Scalar(Scalar::Bool),
218 TypeCtor::Char => TypeName::Scalar(Scalar::Char),
219 TypeCtor::Int(Uncertain::Known(int_ty)) => TypeName::Scalar(int_ty_to_chalk(int_ty)),
220 TypeCtor::Float(Uncertain::Known(FloatTy { bitness: FloatBitness::X32 })) => {
221 TypeName::Scalar(Scalar::Float(chalk_ir::FloatTy::F32))
222 }
223 TypeCtor::Float(Uncertain::Known(FloatTy { bitness: FloatBitness::X64 })) => {
224 TypeName::Scalar(Scalar::Float(chalk_ir::FloatTy::F64))
225 }
226
227 TypeCtor::Tuple { cardinality } => TypeName::Tuple(cardinality.into()),
228 TypeCtor::RawPtr(mutability) => TypeName::Raw(mutability.to_chalk(db)),
229 TypeCtor::Slice => TypeName::Slice,
230 TypeCtor::Ref(mutability) => TypeName::Ref(mutability.to_chalk(db)),
231 TypeCtor::Str => TypeName::Str,
232 TypeCtor::FnDef(callable_def) => {
233 let id = callable_def.to_chalk(db);
234 TypeName::FnDef(id)
235 }
236 TypeCtor::Never => TypeName::Never,
237
238 TypeCtor::Int(Uncertain::Unknown)
239 | TypeCtor::Float(Uncertain::Unknown)
240 | TypeCtor::Adt(_)
241 | TypeCtor::Array
242 | TypeCtor::FnPtr { .. }
243 | TypeCtor::Closure { .. } => {
244 // other TypeCtors get interned and turned into a chalk StructId
245 let struct_id = db.intern_type_ctor(self).into();
246 TypeName::Adt(struct_id)
247 }
248 }
249 }
250
251 fn from_chalk(db: &dyn HirDatabase, type_name: TypeName<Interner>) -> TypeCtor {
252 match type_name {
253 TypeName::Adt(struct_id) => db.lookup_intern_type_ctor(struct_id.into()),
254 TypeName::AssociatedType(type_id) => TypeCtor::AssociatedType(from_chalk(db, type_id)),
255 TypeName::OpaqueType(_) => unreachable!(),
256
257 TypeName::Scalar(Scalar::Bool) => TypeCtor::Bool,
258 TypeName::Scalar(Scalar::Char) => TypeCtor::Char,
259 TypeName::Scalar(Scalar::Int(int_ty)) => TypeCtor::Int(Uncertain::Known(IntTy {
260 signedness: Signedness::Signed,
261 bitness: bitness_from_chalk_int(int_ty),
262 })),
263 TypeName::Scalar(Scalar::Uint(uint_ty)) => TypeCtor::Int(Uncertain::Known(IntTy {
264 signedness: Signedness::Unsigned,
265 bitness: bitness_from_chalk_uint(uint_ty),
266 })),
267 TypeName::Scalar(Scalar::Float(chalk_ir::FloatTy::F32)) => {
268 TypeCtor::Float(Uncertain::Known(FloatTy { bitness: FloatBitness::X32 }))
269 }
270 TypeName::Scalar(Scalar::Float(chalk_ir::FloatTy::F64)) => {
271 TypeCtor::Float(Uncertain::Known(FloatTy { bitness: FloatBitness::X64 }))
272 }
273 TypeName::Tuple(cardinality) => TypeCtor::Tuple { cardinality: cardinality as u16 },
274 TypeName::Raw(mutability) => TypeCtor::RawPtr(from_chalk(db, mutability)),
275 TypeName::Slice => TypeCtor::Slice,
276 TypeName::Ref(mutability) => TypeCtor::Ref(from_chalk(db, mutability)),
277 TypeName::Str => TypeCtor::Str,
278 TypeName::Never => TypeCtor::Never,
279
280 TypeName::FnDef(fn_def_id) => {
281 let callable_def = from_chalk(db, fn_def_id);
282 TypeCtor::FnDef(callable_def)
283 }
284
285 TypeName::Array | TypeName::Error => {
286 // this should not be reached, since we don't represent TypeName::Error with TypeCtor
287 unreachable!()
288 }
289 }
290 }
291}
292
293fn bitness_from_chalk_uint(uint_ty: chalk_ir::UintTy) -> IntBitness {
294 use chalk_ir::UintTy;
295
296 match uint_ty {
297 UintTy::Usize => IntBitness::Xsize,
298 UintTy::U8 => IntBitness::X8,
299 UintTy::U16 => IntBitness::X16,
300 UintTy::U32 => IntBitness::X32,
301 UintTy::U64 => IntBitness::X64,
302 UintTy::U128 => IntBitness::X128,
303 }
304}
305
306fn bitness_from_chalk_int(int_ty: chalk_ir::IntTy) -> IntBitness {
307 use chalk_ir::IntTy;
308
309 match int_ty {
310 IntTy::Isize => IntBitness::Xsize,
311 IntTy::I8 => IntBitness::X8,
312 IntTy::I16 => IntBitness::X16,
313 IntTy::I32 => IntBitness::X32,
314 IntTy::I64 => IntBitness::X64,
315 IntTy::I128 => IntBitness::X128,
316 }
317}
318
319fn int_ty_to_chalk(int_ty: IntTy) -> Scalar {
320 use chalk_ir::{IntTy, UintTy};
321
322 match int_ty.signedness {
323 Signedness::Signed => Scalar::Int(match int_ty.bitness {
324 IntBitness::Xsize => IntTy::Isize,
325 IntBitness::X8 => IntTy::I8,
326 IntBitness::X16 => IntTy::I16,
327 IntBitness::X32 => IntTy::I32,
328 IntBitness::X64 => IntTy::I64,
329 IntBitness::X128 => IntTy::I128,
330 }),
331 Signedness::Unsigned => Scalar::Uint(match int_ty.bitness {
332 IntBitness::Xsize => UintTy::Usize,
333 IntBitness::X8 => UintTy::U8,
334 IntBitness::X16 => UintTy::U16,
335 IntBitness::X32 => UintTy::U32,
336 IntBitness::X64 => UintTy::U64,
337 IntBitness::X128 => UintTy::U128,
338 }),
339 }
340}
341
342impl ToChalk for Mutability {
343 type Chalk = chalk_ir::Mutability;
344 fn to_chalk(self, _db: &dyn HirDatabase) -> Self::Chalk {
345 match self {
346 Mutability::Shared => chalk_ir::Mutability::Not,
347 Mutability::Mut => chalk_ir::Mutability::Mut,
348 }
349 }
350 fn from_chalk(_db: &dyn HirDatabase, chalk: Self::Chalk) -> Self {
351 match chalk {
352 chalk_ir::Mutability::Mut => Mutability::Mut,
353 chalk_ir::Mutability::Not => Mutability::Shared,
354 }
355 }
356}
357
358impl ToChalk for Impl {
359 type Chalk = ImplId;
360
361 fn to_chalk(self, db: &dyn HirDatabase) -> ImplId {
362 db.intern_chalk_impl(self).into()
363 }
364
365 fn from_chalk(db: &dyn HirDatabase, impl_id: ImplId) -> Impl {
366 db.lookup_intern_chalk_impl(impl_id.into())
367 }
368}
369
370impl ToChalk for CallableDef {
371 type Chalk = FnDefId;
372
373 fn to_chalk(self, db: &dyn HirDatabase) -> FnDefId {
374 db.intern_callable_def(self).into()
375 }
376
377 fn from_chalk(db: &dyn HirDatabase, fn_def_id: FnDefId) -> CallableDef {
378 db.lookup_intern_callable_def(fn_def_id.into())
379 }
380}
381
382impl ToChalk for TypeAliasId {
383 type Chalk = AssocTypeId;
384
385 fn to_chalk(self, _db: &dyn HirDatabase) -> AssocTypeId {
386 chalk_ir::AssocTypeId(self.as_intern_id())
387 }
388
389 fn from_chalk(_db: &dyn HirDatabase, type_alias_id: AssocTypeId) -> TypeAliasId {
390 InternKey::from_intern_id(type_alias_id.0)
391 }
392}
393
394impl ToChalk for AssocTyValue {
395 type Chalk = AssociatedTyValueId;
396
397 fn to_chalk(self, db: &dyn HirDatabase) -> AssociatedTyValueId {
398 db.intern_assoc_ty_value(self).into()
399 }
400
401 fn from_chalk(db: &dyn HirDatabase, assoc_ty_value_id: AssociatedTyValueId) -> AssocTyValue {
402 db.lookup_intern_assoc_ty_value(assoc_ty_value_id.into())
403 }
404}
405
406impl ToChalk for GenericPredicate {
407 type Chalk = chalk_ir::QuantifiedWhereClause<Interner>;
408
409 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::QuantifiedWhereClause<Interner> {
410 match self {
411 GenericPredicate::Implemented(trait_ref) => {
412 let chalk_trait_ref = trait_ref.to_chalk(db);
413 let chalk_trait_ref = chalk_trait_ref.shifted_in(&Interner);
414 make_binders(chalk_ir::WhereClause::Implemented(chalk_trait_ref), 0)
415 }
416 GenericPredicate::Projection(projection_pred) => {
417 let ty = projection_pred.ty.to_chalk(db).shifted_in(&Interner);
418 let projection = projection_pred.projection_ty.to_chalk(db).shifted_in(&Interner);
419 let alias = chalk_ir::AliasTy::Projection(projection);
420 make_binders(chalk_ir::WhereClause::AliasEq(chalk_ir::AliasEq { alias, ty }), 0)
421 }
422 GenericPredicate::Error => panic!("tried passing GenericPredicate::Error to Chalk"),
423 }
424 }
425
426 fn from_chalk(
427 db: &dyn HirDatabase,
428 where_clause: chalk_ir::QuantifiedWhereClause<Interner>,
429 ) -> GenericPredicate {
430 // we don't produce any where clauses with binders and can't currently deal with them
431 match where_clause
432 .skip_binders()
433 .shifted_out(&Interner)
434 .expect("unexpected bound vars in where clause")
435 {
436 chalk_ir::WhereClause::Implemented(tr) => {
437 GenericPredicate::Implemented(from_chalk(db, tr))
438 }
439 chalk_ir::WhereClause::AliasEq(projection_eq) => {
440 let projection_ty = from_chalk(
441 db,
442 match projection_eq.alias {
443 chalk_ir::AliasTy::Projection(p) => p,
444 _ => unimplemented!(),
445 },
446 );
447 let ty = from_chalk(db, projection_eq.ty);
448 GenericPredicate::Projection(ProjectionPredicate { projection_ty, ty })
449 }
450 }
451 }
452}
453
454impl ToChalk for ProjectionTy {
455 type Chalk = chalk_ir::ProjectionTy<Interner>;
456
457 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::ProjectionTy<Interner> {
458 chalk_ir::ProjectionTy {
459 associated_ty_id: self.associated_ty.to_chalk(db),
460 substitution: self.parameters.to_chalk(db),
461 }
462 }
463
464 fn from_chalk(
465 db: &dyn HirDatabase,
466 projection_ty: chalk_ir::ProjectionTy<Interner>,
467 ) -> ProjectionTy {
468 ProjectionTy {
469 associated_ty: from_chalk(db, projection_ty.associated_ty_id),
470 parameters: from_chalk(db, projection_ty.substitution),
471 }
472 }
473}
474
475impl ToChalk for ProjectionPredicate {
476 type Chalk = chalk_ir::AliasEq<Interner>;
477
478 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::AliasEq<Interner> {
479 chalk_ir::AliasEq {
480 alias: chalk_ir::AliasTy::Projection(self.projection_ty.to_chalk(db)),
481 ty: self.ty.to_chalk(db),
482 }
483 }
484
485 fn from_chalk(_db: &dyn HirDatabase, _normalize: chalk_ir::AliasEq<Interner>) -> Self {
486 unimplemented!()
487 }
488}
489
490impl ToChalk for Obligation {
491 type Chalk = chalk_ir::DomainGoal<Interner>;
492
493 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::DomainGoal<Interner> {
494 match self {
495 Obligation::Trait(tr) => tr.to_chalk(db).cast(&Interner),
496 Obligation::Projection(pr) => pr.to_chalk(db).cast(&Interner),
497 }
498 }
499
500 fn from_chalk(_db: &dyn HirDatabase, _goal: chalk_ir::DomainGoal<Interner>) -> Self {
501 unimplemented!()
502 }
503}
504
505impl<T> ToChalk for Canonical<T>
506where
507 T: ToChalk,
508 T::Chalk: HasInterner<Interner = Interner>,
509{
510 type Chalk = chalk_ir::Canonical<T::Chalk>;
511
512 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Canonical<T::Chalk> {
513 let parameter = chalk_ir::CanonicalVarKind::new(
514 chalk_ir::VariableKind::Ty(chalk_ir::TyKind::General),
515 chalk_ir::UniverseIndex::ROOT,
516 );
517 let value = self.value.to_chalk(db);
518 chalk_ir::Canonical {
519 value,
520 binders: chalk_ir::CanonicalVarKinds::from(&Interner, vec![parameter; self.num_vars]),
521 }
522 }
523
524 fn from_chalk(db: &dyn HirDatabase, canonical: chalk_ir::Canonical<T::Chalk>) -> Canonical<T> {
525 Canonical {
526 num_vars: canonical.binders.len(&Interner),
527 value: from_chalk(db, canonical.value),
528 }
529 }
530}
531
532impl ToChalk for Arc<TraitEnvironment> {
533 type Chalk = chalk_ir::Environment<Interner>;
534
535 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Environment<Interner> {
536 let mut clauses = Vec::new();
537 for pred in &self.predicates {
538 if pred.is_error() {
539 // for env, we just ignore errors
540 continue;
541 }
542 let program_clause: chalk_ir::ProgramClause<Interner> =
543 pred.clone().to_chalk(db).cast(&Interner);
544 clauses.push(program_clause.into_from_env_clause(&Interner));
545 }
546 chalk_ir::Environment::new(&Interner).add_clauses(&Interner, clauses)
547 }
548
549 fn from_chalk(
550 _db: &dyn HirDatabase,
551 _env: chalk_ir::Environment<Interner>,
552 ) -> Arc<TraitEnvironment> {
553 unimplemented!()
554 }
555}
556
557impl<T: ToChalk> ToChalk for InEnvironment<T>
558where
559 T::Chalk: chalk_ir::interner::HasInterner<Interner = Interner>,
560{
561 type Chalk = chalk_ir::InEnvironment<T::Chalk>;
562
563 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::InEnvironment<T::Chalk> {
564 chalk_ir::InEnvironment {
565 environment: self.environment.to_chalk(db),
566 goal: self.value.to_chalk(db),
567 }
568 }
569
570 fn from_chalk(
571 db: &dyn HirDatabase,
572 in_env: chalk_ir::InEnvironment<T::Chalk>,
573 ) -> InEnvironment<T> {
574 InEnvironment {
575 environment: from_chalk(db, in_env.environment),
576 value: from_chalk(db, in_env.goal),
577 }
578 }
579}
580
581impl ToChalk for builtin::BuiltinImplData {
582 type Chalk = ImplDatum;
583
584 fn to_chalk(self, db: &dyn HirDatabase) -> ImplDatum {
585 let impl_type = rust_ir::ImplType::External;
586 let where_clauses = self.where_clauses.into_iter().map(|w| w.to_chalk(db)).collect();
587
588 let impl_datum_bound =
589 rust_ir::ImplDatumBound { trait_ref: self.trait_ref.to_chalk(db), where_clauses };
590 let associated_ty_value_ids =
591 self.assoc_ty_values.into_iter().map(|v| v.to_chalk(db)).collect();
592 rust_ir::ImplDatum {
593 binders: make_binders(impl_datum_bound, self.num_vars),
594 impl_type,
595 polarity: rust_ir::Polarity::Positive,
596 associated_ty_value_ids,
597 }
598 }
599
600 fn from_chalk(_db: &dyn HirDatabase, _data: ImplDatum) -> Self {
601 unimplemented!()
602 }
603}
604
605impl ToChalk for builtin::BuiltinImplAssocTyValueData {
606 type Chalk = AssociatedTyValue;
607
608 fn to_chalk(self, db: &dyn HirDatabase) -> AssociatedTyValue {
609 let ty = self.value.to_chalk(db);
610 let value_bound = rust_ir::AssociatedTyValueBound { ty };
611
612 rust_ir::AssociatedTyValue {
613 associated_ty_id: self.assoc_ty_id.to_chalk(db),
614 impl_id: self.impl_.to_chalk(db),
615 value: make_binders(value_bound, self.num_vars),
616 }
617 }
618
619 fn from_chalk(
620 _db: &dyn HirDatabase,
621 _data: AssociatedTyValue,
622 ) -> builtin::BuiltinImplAssocTyValueData {
623 unimplemented!()
624 }
625}
626
627pub(super) fn make_binders<T>(value: T, num_vars: usize) -> chalk_ir::Binders<T>
628where
629 T: HasInterner<Interner = Interner>,
630{
631 chalk_ir::Binders::new(
632 chalk_ir::VariableKinds::from(
633 &Interner,
634 std::iter::repeat(chalk_ir::VariableKind::Ty(chalk_ir::TyKind::General)).take(num_vars),
635 ),
636 value,
637 )
638}
639
640pub(super) fn convert_where_clauses(
641 db: &dyn HirDatabase,
642 def: GenericDefId,
643 substs: &Substs,
644) -> Vec<chalk_ir::QuantifiedWhereClause<Interner>> {
645 let generic_predicates = db.generic_predicates(def);
646 let mut result = Vec::with_capacity(generic_predicates.len());
647 for pred in generic_predicates.iter() {
648 if pred.value.is_error() {
649 // skip errored predicates completely
650 continue;
651 }
652 result.push(pred.clone().subst(substs).to_chalk(db));
653 }
654 result
655}
656
657pub(super) fn generic_predicate_to_inline_bound(
658 db: &dyn HirDatabase,
659 pred: &GenericPredicate,
660 self_ty: &Ty,
661) -> Option<rust_ir::InlineBound<Interner>> {
662 // An InlineBound is like a GenericPredicate, except the self type is left out.
663 // We don't have a special type for this, but Chalk does.
664 match pred {
665 GenericPredicate::Implemented(trait_ref) => {
666 if &trait_ref.substs[0] != self_ty {
667 // we can only convert predicates back to type bounds if they
668 // have the expected self type
669 return None;
670 }
671 let args_no_self = trait_ref.substs[1..]
672 .iter()
673 .map(|ty| ty.clone().to_chalk(db).cast(&Interner))
674 .collect();
675 let trait_bound =
676 rust_ir::TraitBound { trait_id: trait_ref.trait_.to_chalk(db), args_no_self };
677 Some(rust_ir::InlineBound::TraitBound(trait_bound))
678 }
679 GenericPredicate::Projection(proj) => {
680 if &proj.projection_ty.parameters[0] != self_ty {
681 return None;
682 }
683 let trait_ = match proj.projection_ty.associated_ty.lookup(db.upcast()).container {
684 AssocContainerId::TraitId(t) => t,
685 _ => panic!("associated type not in trait"),
686 };
687 let args_no_self = proj.projection_ty.parameters[1..]
688 .iter()
689 .map(|ty| ty.clone().to_chalk(db).cast(&Interner))
690 .collect();
691 let alias_eq_bound = rust_ir::AliasEqBound {
692 value: proj.ty.clone().to_chalk(db),
693 trait_bound: rust_ir::TraitBound { trait_id: trait_.to_chalk(db), args_no_self },
694 associated_ty_id: proj.projection_ty.associated_ty.to_chalk(db),
695 parameters: Vec::new(), // FIXME we don't support generic associated types yet
696 };
697 Some(rust_ir::InlineBound::AliasEqBound(alias_eq_bound))
698 }
699 GenericPredicate::Error => None,
700 }
701}
diff --git a/crates/ra_hir_ty/src/traits/chalk/tls.rs b/crates/ra_hir_ty/src/traits/chalk/tls.rs
index 4867cb17e..d88828c7c 100644
--- a/crates/ra_hir_ty/src/traits/chalk/tls.rs
+++ b/crates/ra_hir_ty/src/traits/chalk/tls.rs
@@ -1,7 +1,7 @@
1//! Implementation of Chalk debug helper functions using TLS. 1//! Implementation of Chalk debug helper functions using TLS.
2use std::fmt; 2use std::fmt;
3 3
4use chalk_ir::{AliasTy, Goal, Goals, Lifetime, Parameter, ProgramClauseImplication, TypeName}; 4use chalk_ir::{AliasTy, GenericArg, Goal, Goals, Lifetime, ProgramClauseImplication, TypeName};
5use itertools::Itertools; 5use itertools::Itertools;
6 6
7use super::{from_chalk, Interner}; 7use super::{from_chalk, Interner};
@@ -15,10 +15,10 @@ pub struct DebugContext<'a>(&'a (dyn HirDatabase + 'a));
15impl DebugContext<'_> { 15impl DebugContext<'_> {
16 pub fn debug_struct_id( 16 pub fn debug_struct_id(
17 &self, 17 &self,
18 id: super::StructId, 18 id: super::AdtId,
19 f: &mut fmt::Formatter<'_>, 19 f: &mut fmt::Formatter<'_>,
20 ) -> Result<(), fmt::Error> { 20 ) -> Result<(), fmt::Error> {
21 let type_ctor: TypeCtor = from_chalk(self.0, TypeName::Struct(id)); 21 let type_ctor: TypeCtor = from_chalk(self.0, TypeName::Adt(id));
22 match type_ctor { 22 match type_ctor {
23 TypeCtor::Bool => write!(f, "bool")?, 23 TypeCtor::Bool => write!(f, "bool")?,
24 TypeCtor::Char => write!(f, "char")?, 24 TypeCtor::Char => write!(f, "char")?,
@@ -188,9 +188,9 @@ impl DebugContext<'_> {
188 write!(fmt, "{:?}", lifetime.data(&Interner)) 188 write!(fmt, "{:?}", lifetime.data(&Interner))
189 } 189 }
190 190
191 pub fn debug_parameter( 191 pub fn debug_generic_arg(
192 &self, 192 &self,
193 parameter: &Parameter<Interner>, 193 parameter: &GenericArg<Interner>,
194 fmt: &mut fmt::Formatter<'_>, 194 fmt: &mut fmt::Formatter<'_>,
195 ) -> Result<(), fmt::Error> { 195 ) -> Result<(), fmt::Error> {
196 write!(fmt, "{:?}", parameter.data(&Interner).inner_debug()) 196 write!(fmt, "{:?}", parameter.data(&Interner).inner_debug())
@@ -244,6 +244,79 @@ impl DebugContext<'_> {
244 ) -> Result<(), fmt::Error> { 244 ) -> Result<(), fmt::Error> {
245 write!(fmt, "{:?}", separator_trait_ref.debug(&Interner)) 245 write!(fmt, "{:?}", separator_trait_ref.debug(&Interner))
246 } 246 }
247
248 pub fn debug_fn_def_id(
249 &self,
250 fn_def_id: chalk_ir::FnDefId<Interner>,
251 fmt: &mut fmt::Formatter<'_>,
252 ) -> Result<(), fmt::Error> {
253 let def: CallableDef = from_chalk(self.0, fn_def_id);
254 let name = match def {
255 CallableDef::FunctionId(ff) => self.0.function_data(ff).name.clone(),
256 CallableDef::StructId(s) => self.0.struct_data(s).name.clone(),
257 CallableDef::EnumVariantId(e) => {
258 let enum_data = self.0.enum_data(e.parent);
259 enum_data.variants[e.local_id].name.clone()
260 }
261 };
262 match def {
263 CallableDef::FunctionId(_) => write!(fmt, "{{fn {}}}", name),
264 CallableDef::StructId(_) | CallableDef::EnumVariantId(_) => {
265 write!(fmt, "{{ctor {}}}", name)
266 }
267 }
268 }
269
270 pub fn debug_const(
271 &self,
272 _constant: &chalk_ir::Const<Interner>,
273 fmt: &mut fmt::Formatter<'_>,
274 ) -> fmt::Result {
275 write!(fmt, "const")
276 }
277
278 pub fn debug_variable_kinds(
279 &self,
280 variable_kinds: &chalk_ir::VariableKinds<Interner>,
281 fmt: &mut fmt::Formatter<'_>,
282 ) -> fmt::Result {
283 write!(fmt, "{:?}", variable_kinds.as_slice(&Interner))
284 }
285 pub fn debug_variable_kinds_with_angles(
286 &self,
287 variable_kinds: &chalk_ir::VariableKinds<Interner>,
288 fmt: &mut fmt::Formatter<'_>,
289 ) -> fmt::Result {
290 write!(fmt, "{:?}", variable_kinds.inner_debug(&Interner))
291 }
292 pub fn debug_canonical_var_kinds(
293 &self,
294 canonical_var_kinds: &chalk_ir::CanonicalVarKinds<Interner>,
295 fmt: &mut fmt::Formatter<'_>,
296 ) -> fmt::Result {
297 write!(fmt, "{:?}", canonical_var_kinds.as_slice(&Interner))
298 }
299 pub fn debug_program_clause(
300 &self,
301 clause: &chalk_ir::ProgramClause<Interner>,
302 fmt: &mut fmt::Formatter<'_>,
303 ) -> fmt::Result {
304 write!(fmt, "{:?}", clause.data(&Interner))
305 }
306 pub fn debug_program_clauses(
307 &self,
308 clauses: &chalk_ir::ProgramClauses<Interner>,
309 fmt: &mut fmt::Formatter<'_>,
310 ) -> fmt::Result {
311 write!(fmt, "{:?}", clauses.as_slice(&Interner))
312 }
313 pub fn debug_quantified_where_clauses(
314 &self,
315 clauses: &chalk_ir::QuantifiedWhereClauses<Interner>,
316 fmt: &mut fmt::Formatter<'_>,
317 ) -> fmt::Result {
318 write!(fmt, "{:?}", clauses.as_slice(&Interner))
319 }
247} 320}
248 321
249mod unsafe_tls { 322mod unsafe_tls {