aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_ty
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir_ty')
-rw-r--r--crates/ra_hir_ty/Cargo.toml6
-rw-r--r--crates/ra_hir_ty/src/_match.rs68
-rw-r--r--crates/ra_hir_ty/src/diagnostics.rs28
-rw-r--r--crates/ra_hir_ty/src/display.rs239
-rw-r--r--crates/ra_hir_ty/src/infer.rs148
-rw-r--r--crates/ra_hir_ty/src/infer/coerce.rs36
-rw-r--r--crates/ra_hir_ty/src/infer/expr.rs116
-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.rs30
-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.rs50
-rw-r--r--crates/ra_hir_ty/src/tests/display_source_code.rs50
-rw-r--r--crates/ra_hir_ty/src/tests/macros.rs32
-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.rs43
-rw-r--r--crates/ra_hir_ty/src/tests/regression.rs75
-rw-r--r--crates/ra_hir_ty/src/tests/simple.rs182
-rw-r--r--crates/ra_hir_ty/src/tests/traits.rs178
-rw-r--r--crates/ra_hir_ty/src/traits/chalk.rs57
26 files changed, 1444 insertions, 254 deletions
diff --git a/crates/ra_hir_ty/Cargo.toml b/crates/ra_hir_ty/Cargo.toml
index 65db6d1b0..5fc0ec5e3 100644
--- a/crates/ra_hir_ty/Cargo.toml
+++ b/crates/ra_hir_ty/Cargo.toml
@@ -27,9 +27,9 @@ test_utils = { path = "../test_utils" }
27 27
28scoped-tls = "1" 28scoped-tls = "1"
29 29
30chalk-solve = { git = "https://github.com/rust-lang/chalk.git", rev = "2c072cc830d04af5f10b390e6643327f85108282" } 30chalk-solve = { git = "https://github.com/rust-lang/chalk.git", rev = "3e9c2503ae9c5277c2acb74624dc267876dd89b3" }
31chalk-rust-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "2c072cc830d04af5f10b390e6643327f85108282" } 31chalk-rust-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "3e9c2503ae9c5277c2acb74624dc267876dd89b3" }
32chalk-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "2c072cc830d04af5f10b390e6643327f85108282" } 32chalk-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "3e9c2503ae9c5277c2acb74624dc267876dd89b3" }
33 33
34[dev-dependencies] 34[dev-dependencies]
35insta = "0.16.0" 35insta = "0.16.0"
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/diagnostics.rs b/crates/ra_hir_ty/src/diagnostics.rs
index c8fd54861..41ac70272 100644
--- a/crates/ra_hir_ty/src/diagnostics.rs
+++ b/crates/ra_hir_ty/src/diagnostics.rs
@@ -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..957d6e0b5 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,14 @@ 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,
213} 222}
214 223
215impl<'a> InferenceContext<'a> { 224impl<'a> InferenceContext<'a> {
@@ -224,6 +233,8 @@ impl<'a> InferenceContext<'a> {
224 owner, 233 owner,
225 body: db.body(owner), 234 body: db.body(owner),
226 resolver, 235 resolver,
236 diverges: Diverges::Maybe,
237 breakables: Vec::new(),
227 } 238 }
228 } 239 }
229 240
@@ -429,43 +440,95 @@ impl<'a> InferenceContext<'a> {
429 let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver); 440 let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver);
430 // FIXME: this should resolve assoc items as well, see this example: 441 // FIXME: this should resolve assoc items as well, see this example:
431 // https://play.rust-lang.org/?gist=087992e9e22495446c01c0d4e2d69521 442 // https://play.rust-lang.org/?gist=087992e9e22495446c01c0d4e2d69521
432 return match resolver.resolve_path_in_type_ns_fully(self.db.upcast(), path.mod_path()) { 443 let (resolution, unresolved) =
433 Some(TypeNs::AdtId(AdtId::StructId(strukt))) => { 444 match resolver.resolve_path_in_type_ns(self.db.upcast(), path.mod_path()) {
445 Some(it) => it,
446 None => return (Ty::Unknown, None),
447 };
448 return match resolution {
449 TypeNs::AdtId(AdtId::StructId(strukt)) => {
434 let substs = Ty::substs_from_path(&ctx, path, strukt.into()); 450 let substs = Ty::substs_from_path(&ctx, path, strukt.into());
435 let ty = self.db.ty(strukt.into()); 451 let ty = self.db.ty(strukt.into());
436 let ty = self.insert_type_vars(ty.subst(&substs)); 452 let ty = self.insert_type_vars(ty.subst(&substs));
437 (ty, Some(strukt.into())) 453 forbid_unresolved_segments((ty, Some(strukt.into())), unresolved)
438 } 454 }
439 Some(TypeNs::EnumVariantId(var)) => { 455 TypeNs::EnumVariantId(var) => {
440 let substs = Ty::substs_from_path(&ctx, path, var.into()); 456 let substs = Ty::substs_from_path(&ctx, path, var.into());
441 let ty = self.db.ty(var.parent.into()); 457 let ty = self.db.ty(var.parent.into());
442 let ty = self.insert_type_vars(ty.subst(&substs)); 458 let ty = self.insert_type_vars(ty.subst(&substs));
443 (ty, Some(var.into())) 459 forbid_unresolved_segments((ty, Some(var.into())), unresolved)
444 } 460 }
445 Some(TypeNs::SelfType(impl_id)) => { 461 TypeNs::SelfType(impl_id) => {
446 let generics = crate::utils::generics(self.db.upcast(), impl_id.into()); 462 let generics = crate::utils::generics(self.db.upcast(), impl_id.into());
447 let substs = Substs::type_params_for_generics(&generics); 463 let substs = Substs::type_params_for_generics(&generics);
448 let ty = self.db.impl_self_ty(impl_id).subst(&substs); 464 let ty = self.db.impl_self_ty(impl_id).subst(&substs);
449 let variant = ty_variant(&ty); 465 match unresolved {
450 (ty, variant) 466 None => {
467 let variant = ty_variant(&ty);
468 (ty, variant)
469 }
470 Some(1) => {
471 let segment = path.mod_path().segments.last().unwrap();
472 // this could be an enum variant or associated type
473 if let Some((AdtId::EnumId(enum_id), _)) = ty.as_adt() {
474 let enum_data = self.db.enum_data(enum_id);
475 if let Some(local_id) = enum_data.variant(segment) {
476 let variant = EnumVariantId { parent: enum_id, local_id };
477 return (ty, Some(variant.into()));
478 }
479 }
480 // FIXME potentially resolve assoc type
481 (Ty::Unknown, None)
482 }
483 Some(_) => {
484 // FIXME diagnostic
485 (Ty::Unknown, None)
486 }
487 }
451 } 488 }
452 Some(TypeNs::TypeAliasId(it)) => { 489 TypeNs::TypeAliasId(it) => {
453 let substs = Substs::build_for_def(self.db, it) 490 let substs = Substs::build_for_def(self.db, it)
454 .fill(std::iter::repeat_with(|| self.table.new_type_var())) 491 .fill(std::iter::repeat_with(|| self.table.new_type_var()))
455 .build(); 492 .build();
456 let ty = self.db.ty(it.into()).subst(&substs); 493 let ty = self.db.ty(it.into()).subst(&substs);
457 let variant = ty_variant(&ty); 494 let variant = ty_variant(&ty);
458 (ty, variant) 495 forbid_unresolved_segments((ty, variant), unresolved)
496 }
497 TypeNs::AdtSelfType(_) => {
498 // FIXME this could happen in array size expressions, once we're checking them
499 (Ty::Unknown, None)
500 }
501 TypeNs::GenericParam(_) => {
502 // FIXME potentially resolve assoc type
503 (Ty::Unknown, None)
504 }
505 TypeNs::AdtId(AdtId::EnumId(_))
506 | TypeNs::AdtId(AdtId::UnionId(_))
507 | TypeNs::BuiltinType(_)
508 | TypeNs::TraitId(_) => {
509 // FIXME diagnostic
510 (Ty::Unknown, None)
459 } 511 }
460 Some(_) | None => (Ty::Unknown, None),
461 }; 512 };
462 513
514 fn forbid_unresolved_segments(
515 result: (Ty, Option<VariantId>),
516 unresolved: Option<usize>,
517 ) -> (Ty, Option<VariantId>) {
518 if unresolved.is_none() {
519 result
520 } else {
521 // FIXME diagnostic
522 (Ty::Unknown, None)
523 }
524 }
525
463 fn ty_variant(ty: &Ty) -> Option<VariantId> { 526 fn ty_variant(ty: &Ty) -> Option<VariantId> {
464 ty.as_adt().and_then(|(adt_id, _)| match adt_id { 527 ty.as_adt().and_then(|(adt_id, _)| match adt_id {
465 AdtId::StructId(s) => Some(VariantId::StructId(s)), 528 AdtId::StructId(s) => Some(VariantId::StructId(s)),
466 AdtId::UnionId(u) => Some(VariantId::UnionId(u)), 529 AdtId::UnionId(u) => Some(VariantId::UnionId(u)),
467 AdtId::EnumId(_) => { 530 AdtId::EnumId(_) => {
468 // Error E0071, expected struct, variant or union type, found enum `Foo` 531 // FIXME Error E0071, expected struct, variant or union type, found enum `Foo`
469 None 532 None
470 } 533 }
471 }) 534 })
@@ -476,6 +539,10 @@ impl<'a> InferenceContext<'a> {
476 self.return_ty = self.make_ty(&data.type_ref); 539 self.return_ty = self.make_ty(&data.type_ref);
477 } 540 }
478 541
542 fn collect_static(&mut self, data: &StaticData) {
543 self.return_ty = self.make_ty(&data.type_ref);
544 }
545
479 fn collect_fn(&mut self, data: &FunctionData) { 546 fn collect_fn(&mut self, data: &FunctionData) {
480 let body = Arc::clone(&self.body); // avoid borrow checker problem 547 let body = Arc::clone(&self.body); // avoid borrow checker problem
481 let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver) 548 let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver)
@@ -666,15 +733,57 @@ impl Expectation {
666 } 733 }
667} 734}
668 735
736#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
737enum Diverges {
738 Maybe,
739 Always,
740}
741
742impl Diverges {
743 fn is_always(self) -> bool {
744 self == Diverges::Always
745 }
746}
747
748impl std::ops::BitAnd for Diverges {
749 type Output = Self;
750 fn bitand(self, other: Self) -> Self {
751 std::cmp::min(self, other)
752 }
753}
754
755impl std::ops::BitOr for Diverges {
756 type Output = Self;
757 fn bitor(self, other: Self) -> Self {
758 std::cmp::max(self, other)
759 }
760}
761
762impl std::ops::BitAndAssign for Diverges {
763 fn bitand_assign(&mut self, other: Self) {
764 *self = *self & other;
765 }
766}
767
768impl std::ops::BitOrAssign for Diverges {
769 fn bitor_assign(&mut self, other: Self) {
770 *self = *self | other;
771 }
772}
773
669mod diagnostics { 774mod diagnostics {
670 use hir_def::{expr::ExprId, FunctionId}; 775 use hir_def::{expr::ExprId, FunctionId};
671 use hir_expand::diagnostics::DiagnosticSink; 776 use hir_expand::diagnostics::DiagnosticSink;
672 777
673 use crate::{db::HirDatabase, diagnostics::NoSuchField}; 778 use crate::{
779 db::HirDatabase,
780 diagnostics::{BreakOutsideOfLoop, NoSuchField},
781 };
674 782
675 #[derive(Debug, PartialEq, Eq, Clone)] 783 #[derive(Debug, PartialEq, Eq, Clone)]
676 pub(super) enum InferenceDiagnostic { 784 pub(super) enum InferenceDiagnostic {
677 NoSuchField { expr: ExprId, field: usize }, 785 NoSuchField { expr: ExprId, field: usize },
786 BreakOutsideOfLoop { expr: ExprId },
678 } 787 }
679 788
680 impl InferenceDiagnostic { 789 impl InferenceDiagnostic {
@@ -690,6 +799,13 @@ mod diagnostics {
690 let field = source_map.field_syntax(*expr, *field); 799 let field = source_map.field_syntax(*expr, *field);
691 sink.push(NoSuchField { file: field.file_id, field: field.value }) 800 sink.push(NoSuchField { file: field.file_id, field: field.value })
692 } 801 }
802 InferenceDiagnostic::BreakOutsideOfLoop { expr } => {
803 let (_, source_map) = db.body_with_source_map(owner.into());
804 let ptr = source_map
805 .expr_syntax(*expr)
806 .expect("break outside of loop in synthetic syntax");
807 sink.push(BreakOutsideOfLoop { file: ptr.file_id, expr: ptr.value })
808 }
693 } 809 }
694 } 810 }
695 } 811 }
diff --git a/crates/ra_hir_ty/src/infer/coerce.rs b/crates/ra_hir_ty/src/infer/coerce.rs
index 89200255a..2ee9adb16 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,35 @@ 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 // For incompatible types, we use the latter one as result
49 // to be better recovery for `if` without `else`.
50 ty2.clone()
51 }
38 } 52 }
39 } 53 }
40 54
@@ -84,9 +98,7 @@ impl<'a> InferenceContext<'a> {
84 match from_ty.callable_sig(self.db) { 98 match from_ty.callable_sig(self.db) {
85 None => return false, 99 None => return false,
86 Some(sig) => { 100 Some(sig) => {
87 let num_args = sig.params_and_return.len() as u16 - 1; 101 from_ty = Ty::fn_ptr(sig);
88 from_ty =
89 Ty::apply(TypeCtor::FnPtr { num_args }, Substs(sig.params_and_return));
90 } 102 }
91 } 103 }
92 } 104 }
diff --git a/crates/ra_hir_ty/src/infer/expr.rs b/crates/ra_hir_ty/src/infer/expr.rs
index efc60986b..b28724f0e 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,
@@ -21,11 +21,18 @@ use crate::{
21 Ty, TypeCtor, Uncertain, 21 Ty, TypeCtor, Uncertain,
22}; 22};
23 23
24use super::{BindingMode, Expectation, InferenceContext, InferenceDiagnostic, TypeMismatch}; 24use super::{
25 BindingMode, BreakableContext, Diverges, Expectation, InferenceContext, InferenceDiagnostic,
26 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,68 @@ 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 } => self.infer_block(statements, *tail, expected),
90 Expr::TryBlock { body } => {
91 let _inner = self.infer_expr(*body, expected);
92 // FIXME should be std::result::Result<{inner}, _>
93 Ty::Unknown
94 }
76 Expr::Loop { body } => { 95 Expr::Loop { body } => {
96 self.breakables.push(BreakableContext {
97 may_break: false,
98 break_ty: self.table.new_type_var(),
99 });
77 self.infer_expr(*body, &Expectation::has_type(Ty::unit())); 100 self.infer_expr(*body, &Expectation::has_type(Ty::unit()));
78 // FIXME handle break with value 101
79 Ty::simple(TypeCtor::Never) 102 let ctxt = self.breakables.pop().expect("breakable stack broken");
103 if ctxt.may_break {
104 self.diverges = Diverges::Maybe;
105 }
106
107 if ctxt.may_break {
108 ctxt.break_ty
109 } else {
110 Ty::simple(TypeCtor::Never)
111 }
80 } 112 }
81 Expr::While { condition, body } => { 113 Expr::While { condition, body } => {
114 self.breakables.push(BreakableContext { may_break: false, break_ty: Ty::Unknown });
82 // while let is desugared to a match loop, so this is always simple while 115 // 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))); 116 self.infer_expr(*condition, &Expectation::has_type(Ty::simple(TypeCtor::Bool)));
84 self.infer_expr(*body, &Expectation::has_type(Ty::unit())); 117 self.infer_expr(*body, &Expectation::has_type(Ty::unit()));
118 let _ctxt = self.breakables.pop().expect("breakable stack broken");
119 // the body may not run, so it diverging doesn't mean we diverge
120 self.diverges = Diverges::Maybe;
85 Ty::unit() 121 Ty::unit()
86 } 122 }
87 Expr::For { iterable, body, pat } => { 123 Expr::For { iterable, body, pat } => {
88 let iterable_ty = self.infer_expr(*iterable, &Expectation::none()); 124 let iterable_ty = self.infer_expr(*iterable, &Expectation::none());
89 125
126 self.breakables.push(BreakableContext { may_break: false, break_ty: Ty::Unknown });
90 let pat_ty = 127 let pat_ty =
91 self.resolve_associated_type(iterable_ty, self.resolve_into_iter_item()); 128 self.resolve_associated_type(iterable_ty, self.resolve_into_iter_item());
92 129
93 self.infer_pat(*pat, &pat_ty, BindingMode::default()); 130 self.infer_pat(*pat, &pat_ty, BindingMode::default());
131
94 self.infer_expr(*body, &Expectation::has_type(Ty::unit())); 132 self.infer_expr(*body, &Expectation::has_type(Ty::unit()));
133 let _ctxt = self.breakables.pop().expect("breakable stack broken");
134 // the body may not run, so it diverging doesn't mean we diverge
135 self.diverges = Diverges::Maybe;
95 Ty::unit() 136 Ty::unit()
96 } 137 }
97 Expr::Lambda { body, args, ret_type, arg_types } => { 138 Expr::Lambda { body, args, ret_type, arg_types } => {
@@ -127,10 +168,12 @@ impl<'a> InferenceContext<'a> {
127 // infer the body. 168 // infer the body.
128 self.coerce(&closure_ty, &expected.ty); 169 self.coerce(&closure_ty, &expected.ty);
129 170
130 let prev_ret_ty = std::mem::replace(&mut self.return_ty, ret_ty.clone()); 171 let prev_diverges = mem::replace(&mut self.diverges, Diverges::Maybe);
172 let prev_ret_ty = mem::replace(&mut self.return_ty, ret_ty.clone());
131 173
132 self.infer_expr_coerce(*body, &Expectation::has_type(ret_ty)); 174 self.infer_expr_coerce(*body, &Expectation::has_type(ret_ty));
133 175
176 self.diverges = prev_diverges;
134 self.return_ty = prev_ret_ty; 177 self.return_ty = prev_ret_ty;
135 178
136 closure_ty 179 closure_ty
@@ -160,7 +203,11 @@ impl<'a> InferenceContext<'a> {
160 self.table.new_type_var() 203 self.table.new_type_var()
161 }; 204 };
162 205
206 let matchee_diverges = self.diverges;
207 let mut all_arms_diverge = Diverges::Always;
208
163 for arm in arms { 209 for arm in arms {
210 self.diverges = Diverges::Maybe;
164 let _pat_ty = self.infer_pat(arm.pat, &input_ty, BindingMode::default()); 211 let _pat_ty = self.infer_pat(arm.pat, &input_ty, BindingMode::default());
165 if let Some(guard_expr) = arm.guard { 212 if let Some(guard_expr) = arm.guard {
166 self.infer_expr( 213 self.infer_expr(
@@ -170,9 +217,12 @@ impl<'a> InferenceContext<'a> {
170 } 217 }
171 218
172 let arm_ty = self.infer_expr_inner(arm.expr, &expected); 219 let arm_ty = self.infer_expr_inner(arm.expr, &expected);
220 all_arms_diverge &= self.diverges;
173 result_ty = self.coerce_merge_branch(&result_ty, &arm_ty); 221 result_ty = self.coerce_merge_branch(&result_ty, &arm_ty);
174 } 222 }
175 223
224 self.diverges = matchee_diverges | all_arms_diverge;
225
176 result_ty 226 result_ty
177 } 227 }
178 Expr::Path(p) => { 228 Expr::Path(p) => {
@@ -182,10 +232,29 @@ impl<'a> InferenceContext<'a> {
182 } 232 }
183 Expr::Continue => Ty::simple(TypeCtor::Never), 233 Expr::Continue => Ty::simple(TypeCtor::Never),
184 Expr::Break { expr } => { 234 Expr::Break { expr } => {
185 if let Some(expr) = expr { 235 let val_ty = if let Some(expr) = expr {
186 // FIXME handle break with value 236 self.infer_expr(*expr, &Expectation::none())
187 self.infer_expr(*expr, &Expectation::none()); 237 } else {
238 Ty::unit()
239 };
240
241 let last_ty = if let Some(ctxt) = self.breakables.last() {
242 ctxt.break_ty.clone()
243 } else {
244 Ty::Unknown
245 };
246
247 let merged_type = self.coerce_merge_branch(&last_ty, &val_ty);
248
249 if let Some(ctxt) = self.breakables.last_mut() {
250 ctxt.break_ty = merged_type;
251 ctxt.may_break = true;
252 } else {
253 self.push_diagnostic(InferenceDiagnostic::BreakOutsideOfLoop {
254 expr: tgt_expr,
255 });
188 } 256 }
257
189 Ty::simple(TypeCtor::Never) 258 Ty::simple(TypeCtor::Never)
190 } 259 }
191 Expr::Return { expr } => { 260 Expr::Return { expr } => {
@@ -496,8 +565,8 @@ impl<'a> InferenceContext<'a> {
496 } 565 }
497 Literal::ByteString(..) => { 566 Literal::ByteString(..) => {
498 let byte_type = Ty::simple(TypeCtor::Int(Uncertain::Known(IntTy::u8()))); 567 let byte_type = Ty::simple(TypeCtor::Int(Uncertain::Known(IntTy::u8())));
499 let slice_type = Ty::apply_one(TypeCtor::Slice, byte_type); 568 let array_type = Ty::apply_one(TypeCtor::Array, byte_type);
500 Ty::apply_one(TypeCtor::Ref(Mutability::Shared), slice_type) 569 Ty::apply_one(TypeCtor::Ref(Mutability::Shared), array_type)
501 } 570 }
502 Literal::Char(..) => Ty::simple(TypeCtor::Char), 571 Literal::Char(..) => Ty::simple(TypeCtor::Char),
503 Literal::Int(_v, ty) => Ty::simple(TypeCtor::Int((*ty).into())), 572 Literal::Int(_v, ty) => Ty::simple(TypeCtor::Int((*ty).into())),
@@ -517,7 +586,6 @@ impl<'a> InferenceContext<'a> {
517 tail: Option<ExprId>, 586 tail: Option<ExprId>,
518 expected: &Expectation, 587 expected: &Expectation,
519 ) -> Ty { 588 ) -> Ty {
520 let mut diverges = false;
521 for stmt in statements { 589 for stmt in statements {
522 match stmt { 590 match stmt {
523 Statement::Let { pat, type_ref, initializer } => { 591 Statement::Let { pat, type_ref, initializer } => {
@@ -539,9 +607,7 @@ impl<'a> InferenceContext<'a> {
539 self.infer_pat(*pat, &ty, BindingMode::default()); 607 self.infer_pat(*pat, &ty, BindingMode::default());
540 } 608 }
541 Statement::Expr(expr) => { 609 Statement::Expr(expr) => {
542 if let ty_app!(TypeCtor::Never) = self.infer_expr(*expr, &Expectation::none()) { 610 self.infer_expr(*expr, &Expectation::none());
543 diverges = true;
544 }
545 } 611 }
546 } 612 }
547 } 613 }
@@ -549,14 +615,22 @@ impl<'a> InferenceContext<'a> {
549 let ty = if let Some(expr) = tail { 615 let ty = if let Some(expr) = tail {
550 self.infer_expr_coerce(expr, expected) 616 self.infer_expr_coerce(expr, expected)
551 } else { 617 } else {
552 self.coerce(&Ty::unit(), expected.coercion_target()); 618 // Citing rustc: if there is no explicit tail expression,
553 Ty::unit() 619 // that is typically equivalent to a tail expression
620 // of `()` -- except if the block diverges. In that
621 // case, there is no value supplied from the tail
622 // expression (assuming there are no other breaks,
623 // this implies that the type of the block will be
624 // `!`).
625 if self.diverges.is_always() {
626 // we don't even make an attempt at coercion
627 self.table.new_maybe_never_type_var()
628 } else {
629 self.coerce(&Ty::unit(), expected.coercion_target());
630 Ty::unit()
631 }
554 }; 632 };
555 if diverges { 633 ty
556 Ty::simple(TypeCtor::Never)
557 } else {
558 ty
559 }
560 } 634 }
561 635
562 fn infer_method_call( 636 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..c87ee06ce 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;
@@ -427,6 +426,11 @@ impl Substs {
427 } 426 }
428} 427}
429 428
429/// Return an index of a parameter in the generic type parameter list by it's id.
430pub fn param_idx(db: &dyn HirDatabase, id: TypeParamId) -> Option<usize> {
431 generics(db.upcast(), id.parent).param_idx(id)
432}
433
430#[derive(Debug, Clone)] 434#[derive(Debug, Clone)]
431pub struct SubstsBuilder { 435pub struct SubstsBuilder {
432 vec: Vec<Ty>, 436 vec: Vec<Ty>,
@@ -683,6 +687,12 @@ impl Ty {
683 pub fn unit() -> Self { 687 pub fn unit() -> Self {
684 Ty::apply(TypeCtor::Tuple { cardinality: 0 }, Substs::empty()) 688 Ty::apply(TypeCtor::Tuple { cardinality: 0 }, Substs::empty())
685 } 689 }
690 pub fn fn_ptr(sig: FnSig) -> Self {
691 Ty::apply(
692 TypeCtor::FnPtr { num_args: sig.params().len() as u16 },
693 Substs(sig.params_and_return),
694 )
695 }
686 696
687 pub fn as_reference(&self) -> Option<(&Ty, Mutability)> { 697 pub fn as_reference(&self) -> Option<(&Ty, Mutability)> {
688 match self { 698 match self {
@@ -730,6 +740,10 @@ impl Ty {
730 } 740 }
731 } 741 }
732 742
743 pub fn is_never(&self) -> bool {
744 matches!(self, Ty::Apply(ApplicationTy { ctor: TypeCtor::Never, .. }))
745 }
746
733 /// If this is a `dyn Trait` type, this returns the `Trait` part. 747 /// If this is a `dyn Trait` type, this returns the `Trait` part.
734 pub fn dyn_trait_ref(&self) -> Option<&TraitRef> { 748 pub fn dyn_trait_ref(&self) -> Option<&TraitRef> {
735 match self { 749 match self {
@@ -793,15 +807,13 @@ impl Ty {
793 } 807 }
794 } 808 }
795 809
796 /// If this is an `impl Trait` or `dyn Trait`, returns that trait. 810 /// If this is a `dyn Trait`, returns that trait.
797 pub fn inherent_trait(&self) -> Option<TraitId> { 811 pub fn dyn_trait(&self) -> Option<TraitId> {
798 match self { 812 match self {
799 Ty::Dyn(predicates) | Ty::Opaque(predicates) => { 813 Ty::Dyn(predicates) => predicates.iter().find_map(|pred| match pred {
800 predicates.iter().find_map(|pred| match pred { 814 GenericPredicate::Implemented(tr) => Some(tr.trait_),
801 GenericPredicate::Implemented(tr) => Some(tr.trait_), 815 _ => None,
802 _ => None, 816 }),
803 })
804 }
805 _ => None, 817 _ => None,
806 } 818 }
807 } 819 }
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..2cc4f4bf9 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 {
@@ -339,7 +339,7 @@ fn test(i: i32) {
339 339
340#[test] 340#[test]
341fn coerce_merge_one_by_one1() { 341fn coerce_merge_one_by_one1() {
342 covers!(coerce_merge_fail_fallback); 342 mark::check!(coerce_merge_fail_fallback);
343 343
344 assert_snapshot!( 344 assert_snapshot!(
345 infer(r#" 345 infer(r#"
@@ -384,7 +384,7 @@ fn foo() -> u32 {
384} 384}
385"#, true), 385"#, true),
386 @r###" 386 @r###"
387 17..40 '{ ...own; }': ! 387 17..40 '{ ...own; }': u32
388 23..37 'return unknown': ! 388 23..37 'return unknown': !
389 30..37 'unknown': u32 389 30..37 'unknown': u32
390 "### 390 "###
@@ -514,7 +514,7 @@ fn foo() {
514 27..103 '{ ... }': &u32 514 27..103 '{ ... }': &u32
515 37..82 'if tru... }': () 515 37..82 'if tru... }': ()
516 40..44 'true': bool 516 40..44 'true': bool
517 45..82 '{ ... }': ! 517 45..82 '{ ... }': ()
518 59..71 'return &1u32': ! 518 59..71 'return &1u32': !
519 66..71 '&1u32': &u32 519 66..71 '&1u32': &u32
520 67..71 '1u32': u32 520 67..71 '1u32': u32
@@ -546,6 +546,48 @@ fn test() {
546} 546}
547 547
548#[test] 548#[test]
549fn coerce_fn_items_in_match_arms() {
550 mark::check!(coerce_fn_reification);
551 assert_snapshot!(
552 infer_with_mismatches(r#"
553fn foo1(x: u32) -> isize { 1 }
554fn foo2(x: u32) -> isize { 2 }
555fn foo3(x: u32) -> isize { 3 }
556fn test() {
557 let x = match 1 {
558 1 => foo1,
559 2 => foo2,
560 _ => foo3,
561 };
562}
563"#, true),
564 @r###"
565 9..10 'x': u32
566 26..31 '{ 1 }': isize
567 28..29 '1': isize
568 40..41 'x': u32
569 57..62 '{ 2 }': isize
570 59..60 '2': isize
571 71..72 'x': u32
572 88..93 '{ 3 }': isize
573 90..91 '3': isize
574 104..193 '{ ... }; }': ()
575 114..115 'x': fn(u32) -> isize
576 118..190 'match ... }': fn(u32) -> isize
577 124..125 '1': i32
578 136..137 '1': i32
579 136..137 '1': i32
580 141..145 'foo1': fn foo1(u32) -> isize
581 155..156 '2': i32
582 155..156 '2': i32
583 160..164 'foo2': fn foo2(u32) -> isize
584 174..175 '_': i32
585 179..183 'foo3': fn foo3(u32) -> isize
586 "###
587 );
588}
589
590#[test]
549fn coerce_closure_to_fn_ptr() { 591fn coerce_closure_to_fn_ptr() {
550 assert_snapshot!( 592 assert_snapshot!(
551 infer_with_mismatches(r#" 593 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 1f796876d..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
@@ -428,6 +428,32 @@ fn main() {
428} 428}
429 429
430#[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]
431fn infer_builtin_macros_line() { 457fn infer_builtin_macros_line() {
432 assert_snapshot!( 458 assert_snapshot!(
433 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..0c5f972a2 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#"
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..fd2208af2 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': !
@@ -414,7 +414,7 @@ fn test() {
414 27..31 '5f32': f32 414 27..31 '5f32': f32
415 37..41 '5f64': f64 415 37..41 '5f64': f64
416 47..54 '"hello"': &str 416 47..54 '"hello"': &str
417 60..68 'b"bytes"': &[u8] 417 60..68 'b"bytes"': &[u8; _]
418 74..77 ''c'': char 418 74..77 ''c'': char
419 83..87 'b'b'': u8 419 83..87 'b'b'': u8
420 93..97 '3.14': f64 420 93..97 '3.14': f64
@@ -422,7 +422,7 @@ fn test() {
422 113..118 'false': bool 422 113..118 'false': bool
423 124..128 'true': bool 423 124..128 'true': bool
424 134..202 'r#" ... "#': &str 424 134..202 'r#" ... "#': &str
425 208..218 'br#"yolo"#': &[u8] 425 208..218 'br#"yolo"#': &[u8; _]
426 "### 426 "###
427 ); 427 );
428} 428}
@@ -576,6 +576,50 @@ impl S {
576} 576}
577 577
578#[test] 578#[test]
579fn infer_self_as_path() {
580 assert_snapshot!(
581 infer(r#"
582struct S1;
583struct S2(isize);
584enum E {
585 V1,
586 V2(u32),
587}
588
589impl S1 {
590 fn test() {
591 Self;
592 }
593}
594impl S2 {
595 fn test() {
596 Self(1);
597 }
598}
599impl E {
600 fn test() {
601 Self::V1;
602 Self::V2(1);
603 }
604}
605"#),
606 @r###"
607 87..108 '{ ... }': ()
608 97..101 'Self': S1
609 135..159 '{ ... }': ()
610 145..149 'Self': S2(isize) -> S2
611 145..152 'Self(1)': S2
612 150..151 '1': isize
613 185..231 '{ ... }': ()
614 195..203 'Self::V1': E
615 213..221 'Self::V2': V2(u32) -> E
616 213..224 'Self::V2(1)': E
617 222..223 '1': u32
618 "###
619 );
620}
621
622#[test]
579fn infer_binary_op() { 623fn infer_binary_op() {
580 assert_snapshot!( 624 assert_snapshot!(
581 infer(r#" 625 infer(r#"
@@ -935,7 +979,7 @@ fn foo() {
935 29..33 'true': bool 979 29..33 'true': bool
936 34..51 '{ ... }': i32 980 34..51 '{ ... }': i32
937 44..45 '1': i32 981 44..45 '1': i32
938 57..80 '{ ... }': ! 982 57..80 '{ ... }': i32
939 67..73 'return': ! 983 67..73 'return': !
940 90..93 '_x2': i32 984 90..93 '_x2': i32
941 96..149 'if tru... }': i32 985 96..149 'if tru... }': i32
@@ -951,7 +995,7 @@ fn foo() {
951 186..190 'true': bool 995 186..190 'true': bool
952 194..195 '3': i32 996 194..195 '3': i32
953 205..206 '_': bool 997 205..206 '_': bool
954 210..241 '{ ... }': ! 998 210..241 '{ ... }': i32
955 224..230 'return': ! 999 224..230 'return': !
956 257..260 '_x4': i32 1000 257..260 '_x4': i32
957 263..320 'match ... }': i32 1001 263..320 'match ... }': i32
@@ -1687,7 +1731,7 @@ fn foo() -> u32 {
1687 17..59 '{ ...; }; }': () 1731 17..59 '{ ...; }; }': ()
1688 27..28 'x': || -> usize 1732 27..28 'x': || -> usize
1689 31..56 '|| -> ...n 1; }': || -> usize 1733 31..56 '|| -> ...n 1; }': || -> usize
1690 43..56 '{ return 1; }': ! 1734 43..56 '{ return 1; }': usize
1691 45..53 'return 1': ! 1735 45..53 'return 1': !
1692 52..53 '1': usize 1736 52..53 '1': usize
1693 "### 1737 "###
@@ -1706,7 +1750,7 @@ fn foo() -> u32 {
1706 17..48 '{ ...; }; }': () 1750 17..48 '{ ...; }; }': ()
1707 27..28 'x': || -> () 1751 27..28 'x': || -> ()
1708 31..45 '|| { return; }': || -> () 1752 31..45 '|| { return; }': || -> ()
1709 34..45 '{ return; }': ! 1753 34..45 '{ return; }': ()
1710 36..42 'return': ! 1754 36..42 'return': !
1711 "### 1755 "###
1712 ); 1756 );
@@ -1755,3 +1799,127 @@ fn main() {
1755 "### 1799 "###
1756 ); 1800 );
1757} 1801}
1802
1803#[test]
1804fn effects_smoke_test() {
1805 assert_snapshot!(
1806 infer(r#"
1807fn main() {
1808 let x = unsafe { 92 };
1809 let y = async { async { () }.await };
1810 let z = try { () };
1811 let t = 'a: { 92 };
1812}
1813"#),
1814 @r###"
1815 11..131 '{ ...2 }; }': ()
1816 21..22 'x': i32
1817 32..38 '{ 92 }': i32
1818 34..36 '92': i32
1819 48..49 'y': {unknown}
1820 58..80 '{ asyn...wait }': {unknown}
1821 60..78 'async ....await': {unknown}
1822 66..72 '{ () }': ()
1823 68..70 '()': ()
1824 90..91 'z': {unknown}
1825 94..104 'try { () }': {unknown}
1826 98..104 '{ () }': ()
1827 100..102 '()': ()
1828 114..115 't': i32
1829 122..128 '{ 92 }': i32
1830 124..126 '92': i32
1831 "###
1832 )
1833}
1834
1835#[test]
1836fn infer_generic_from_later_assignment() {
1837 assert_snapshot!(
1838 infer(r#"
1839enum Option<T> { Some(T), None }
1840use Option::*;
1841
1842fn test() {
1843 let mut end = None;
1844 loop {
1845 end = Some(true);
1846 }
1847}
1848"#),
1849 @r###"
1850 60..130 '{ ... } }': ()
1851 70..77 'mut end': Option<bool>
1852 80..84 'None': Option<bool>
1853 90..128 'loop {... }': !
1854 95..128 '{ ... }': ()
1855 105..108 'end': Option<bool>
1856 105..121 'end = ...(true)': ()
1857 111..115 'Some': Some<bool>(bool) -> Option<bool>
1858 111..121 'Some(true)': Option<bool>
1859 116..120 'true': bool
1860 "###
1861 );
1862}
1863
1864#[test]
1865fn infer_loop_break_with_val() {
1866 assert_snapshot!(
1867 infer(r#"
1868enum Option<T> { Some(T), None }
1869use Option::*;
1870
1871fn test() {
1872 let x = loop {
1873 if false {
1874 break None;
1875 }
1876
1877 break Some(true);
1878 };
1879}
1880"#),
1881 @r###"
1882 60..169 '{ ... }; }': ()
1883 70..71 'x': Option<bool>
1884 74..166 'loop {... }': Option<bool>
1885 79..166 '{ ... }': ()
1886 89..133 'if fal... }': ()
1887 92..97 'false': bool
1888 98..133 '{ ... }': ()
1889 112..122 'break None': !
1890 118..122 'None': Option<bool>
1891 143..159 'break ...(true)': !
1892 149..153 'Some': Some<bool>(bool) -> Option<bool>
1893 149..159 'Some(true)': Option<bool>
1894 154..158 'true': bool
1895 "###
1896 );
1897}
1898
1899#[test]
1900fn infer_loop_break_without_val() {
1901 assert_snapshot!(
1902 infer(r#"
1903enum Option<T> { Some(T), None }
1904use Option::*;
1905
1906fn test() {
1907 let x = loop {
1908 if false {
1909 break;
1910 }
1911 };
1912}
1913"#),
1914 @r###"
1915 60..137 '{ ... }; }': ()
1916 70..71 'x': ()
1917 74..134 'loop {... }': ()
1918 79..134 '{ ... }': ()
1919 89..128 'if fal... }': ()
1920 92..97 'false': bool
1921 98..128 '{ ... }': ()
1922 112..117 'break': !
1923 "###
1924 );
1925}
diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs
index e555c879a..34f4b9039 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}
diff --git a/crates/ra_hir_ty/src/traits/chalk.rs b/crates/ra_hir_ty/src/traits/chalk.rs
index 1ccb7c3b4..5870618a0 100644
--- a/crates/ra_hir_ty/src/traits/chalk.rs
+++ b/crates/ra_hir_ty/src/traits/chalk.rs
@@ -182,7 +182,10 @@ impl chalk_ir::interner::Interner for Interner {
182 Arc::new(goal) 182 Arc::new(goal)
183 } 183 }
184 184
185 fn intern_goals(&self, data: impl IntoIterator<Item = Goal<Self>>) -> Self::InternedGoals { 185 fn intern_goals<E>(
186 &self,
187 data: impl IntoIterator<Item = Result<Goal<Self>, E>>,
188 ) -> Result<Self::InternedGoals, E> {
186 data.into_iter().collect() 189 data.into_iter().collect()
187 } 190 }
188 191
@@ -222,10 +225,10 @@ impl chalk_ir::interner::Interner for Interner {
222 clause 225 clause
223 } 226 }
224 227
225 fn intern_program_clauses( 228 fn intern_program_clauses<E>(
226 &self, 229 &self,
227 data: impl IntoIterator<Item = chalk_ir::ProgramClause<Self>>, 230 data: impl IntoIterator<Item = Result<chalk_ir::ProgramClause<Self>, E>>,
228 ) -> Arc<[chalk_ir::ProgramClause<Self>]> { 231 ) -> Result<Arc<[chalk_ir::ProgramClause<Self>]>, E> {
229 data.into_iter().collect() 232 data.into_iter().collect()
230 } 233 }
231 234
@@ -236,10 +239,10 @@ impl chalk_ir::interner::Interner for Interner {
236 &clauses 239 &clauses
237 } 240 }
238 241
239 fn intern_quantified_where_clauses( 242 fn intern_quantified_where_clauses<E>(
240 &self, 243 &self,
241 data: impl IntoIterator<Item = chalk_ir::QuantifiedWhereClause<Self>>, 244 data: impl IntoIterator<Item = Result<chalk_ir::QuantifiedWhereClause<Self>, E>>,
242 ) -> Self::InternedQuantifiedWhereClauses { 245 ) -> Result<Self::InternedQuantifiedWhereClauses, E> {
243 data.into_iter().collect() 246 data.into_iter().collect()
244 } 247 }
245 248
@@ -250,10 +253,10 @@ impl chalk_ir::interner::Interner for Interner {
250 clauses 253 clauses
251 } 254 }
252 255
253 fn intern_parameter_kinds( 256 fn intern_parameter_kinds<E>(
254 &self, 257 &self,
255 data: impl IntoIterator<Item = chalk_ir::ParameterKind<()>>, 258 data: impl IntoIterator<Item = Result<chalk_ir::ParameterKind<()>, E>>,
256 ) -> Self::InternedParameterKinds { 259 ) -> Result<Self::InternedParameterKinds, E> {
257 data.into_iter().collect() 260 data.into_iter().collect()
258 } 261 }
259 262
@@ -264,10 +267,10 @@ impl chalk_ir::interner::Interner for Interner {
264 &parameter_kinds 267 &parameter_kinds
265 } 268 }
266 269
267 fn intern_canonical_var_kinds( 270 fn intern_canonical_var_kinds<E>(
268 &self, 271 &self,
269 data: impl IntoIterator<Item = chalk_ir::ParameterKind<UniverseIndex>>, 272 data: impl IntoIterator<Item = Result<chalk_ir::ParameterKind<UniverseIndex>, E>>,
270 ) -> Self::InternedCanonicalVarKinds { 273 ) -> Result<Self::InternedCanonicalVarKinds, E> {
271 data.into_iter().collect() 274 data.into_iter().collect()
272 } 275 }
273 276
@@ -460,6 +463,14 @@ impl ToChalk for TypeCtor {
460 TypeName::Struct(struct_id) => db.lookup_intern_type_ctor(struct_id.into()), 463 TypeName::Struct(struct_id) => db.lookup_intern_type_ctor(struct_id.into()),
461 TypeName::AssociatedType(type_id) => TypeCtor::AssociatedType(from_chalk(db, type_id)), 464 TypeName::AssociatedType(type_id) => TypeCtor::AssociatedType(from_chalk(db, type_id)),
462 TypeName::OpaqueType(_) => unreachable!(), 465 TypeName::OpaqueType(_) => unreachable!(),
466
467 TypeName::Scalar(_) => unreachable!(),
468 TypeName::Tuple(_) => unreachable!(),
469 TypeName::Raw(_) => unreachable!(),
470 TypeName::Slice => unreachable!(),
471 TypeName::Ref(_) => unreachable!(),
472 TypeName::Str => unreachable!(),
473
463 TypeName::Error => { 474 TypeName::Error => {
464 // this should not be reached, since we don't represent TypeName::Error with TypeCtor 475 // this should not be reached, since we don't represent TypeName::Error with TypeCtor
465 unreachable!() 476 unreachable!()
@@ -862,12 +873,6 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
862 // We don't do coherence checking (yet) 873 // We don't do coherence checking (yet)
863 unimplemented!() 874 unimplemented!()
864 } 875 }
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 { 876 fn interner(&self) -> &Interner {
872 &Interner 877 &Interner
873 } 878 }
@@ -892,6 +897,20 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
892 ) -> Arc<chalk_rust_ir::OpaqueTyDatum<Interner>> { 897 ) -> Arc<chalk_rust_ir::OpaqueTyDatum<Interner>> {
893 unimplemented!() 898 unimplemented!()
894 } 899 }
900
901 fn force_impl_for(
902 &self,
903 _well_known: chalk_rust_ir::WellKnownTrait,
904 _ty: &chalk_ir::TyData<Interner>,
905 ) -> Option<bool> {
906 // this method is mostly for rustc
907 None
908 }
909
910 fn is_object_safe(&self, _trait_id: chalk_ir::TraitId<Interner>) -> bool {
911 // FIXME: implement actual object safety
912 true
913 }
895} 914}
896 915
897pub(crate) fn program_clauses_for_chalk_env_query( 916pub(crate) fn program_clauses_for_chalk_env_query(