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.toml7
-rw-r--r--crates/ra_hir_ty/src/_match.rs68
-rw-r--r--crates/ra_hir_ty/src/db.rs7
-rw-r--r--crates/ra_hir_ty/src/diagnostics.rs32
-rw-r--r--crates/ra_hir_ty/src/display.rs239
-rw-r--r--crates/ra_hir_ty/src/infer.rs159
-rw-r--r--crates/ra_hir_ty/src/infer/coerce.rs34
-rw-r--r--crates/ra_hir_ty/src/infer/expr.rs194
-rw-r--r--crates/ra_hir_ty/src/infer/pat.rs4
-rw-r--r--crates/ra_hir_ty/src/infer/path.rs35
-rw-r--r--crates/ra_hir_ty/src/infer/unify.rs8
-rw-r--r--crates/ra_hir_ty/src/lib.rs56
-rw-r--r--crates/ra_hir_ty/src/lower.rs2
-rw-r--r--crates/ra_hir_ty/src/marks.rs11
-rw-r--r--crates/ra_hir_ty/src/method_resolution.rs12
-rw-r--r--crates/ra_hir_ty/src/op.rs3
-rw-r--r--crates/ra_hir_ty/src/tests.rs62
-rw-r--r--crates/ra_hir_ty/src/tests/coercion.rs67
-rw-r--r--crates/ra_hir_ty/src/tests/display_source_code.rs50
-rw-r--r--crates/ra_hir_ty/src/tests/macros.rs72
-rw-r--r--crates/ra_hir_ty/src/tests/method_resolution.rs46
-rw-r--r--crates/ra_hir_ty/src/tests/never_type.rs177
-rw-r--r--crates/ra_hir_ty/src/tests/patterns.rs93
-rw-r--r--crates/ra_hir_ty/src/tests/regression.rs75
-rw-r--r--crates/ra_hir_ty/src/tests/simple.rs258
-rw-r--r--crates/ra_hir_ty/src/tests/traits.rs374
-rw-r--r--crates/ra_hir_ty/src/traits/builtin.rs3
-rw-r--r--crates/ra_hir_ty/src/traits/chalk.rs944
-rw-r--r--crates/ra_hir_ty/src/traits/chalk/interner.rs353
-rw-r--r--crates/ra_hir_ty/src/traits/chalk/mapping.rs701
-rw-r--r--crates/ra_hir_ty/src/traits/chalk/tls.rs83
31 files changed, 3131 insertions, 1098 deletions
diff --git a/crates/ra_hir_ty/Cargo.toml b/crates/ra_hir_ty/Cargo.toml
index 04d3cd6a2..4b8dcdc07 100644
--- a/crates/ra_hir_ty/Cargo.toml
+++ b/crates/ra_hir_ty/Cargo.toml
@@ -11,7 +11,7 @@ doctest = false
11itertools = "0.9.0" 11itertools = "0.9.0"
12arrayvec = "0.5.1" 12arrayvec = "0.5.1"
13smallvec = "1.2.0" 13smallvec = "1.2.0"
14ena = "0.13.1" 14ena = "0.14.0"
15log = "0.4.8" 15log = "0.4.8"
16rustc-hash = "1.1.0" 16rustc-hash = "1.1.0"
17 17
@@ -27,9 +27,8 @@ 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 = "329b7f3fdd2431ed6f6778cde53f22374c7d094c" }
31chalk-rust-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "2c072cc830d04af5f10b390e6643327f85108282" } 31chalk-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "329b7f3fdd2431ed6f6778cde53f22374c7d094c" }
32chalk-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "2c072cc830d04af5f10b390e6643327f85108282" }
33 32
34[dev-dependencies] 33[dev-dependencies]
35insta = "0.16.0" 34insta = "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/db.rs b/crates/ra_hir_ty/src/db.rs
index fdb49560b..0a8bb24ac 100644
--- a/crates/ra_hir_ty/src/db.rs
+++ b/crates/ra_hir_ty/src/db.rs
@@ -76,6 +76,8 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
76 #[salsa::interned] 76 #[salsa::interned]
77 fn intern_type_ctor(&self, type_ctor: TypeCtor) -> crate::TypeCtorId; 77 fn intern_type_ctor(&self, type_ctor: TypeCtor) -> crate::TypeCtorId;
78 #[salsa::interned] 78 #[salsa::interned]
79 fn intern_callable_def(&self, callable_def: CallableDef) -> crate::CallableDefId;
80 #[salsa::interned]
79 fn intern_type_param_id(&self, param_id: TypeParamId) -> GlobalTypeParamId; 81 fn intern_type_param_id(&self, param_id: TypeParamId) -> GlobalTypeParamId;
80 #[salsa::interned] 82 #[salsa::interned]
81 fn intern_chalk_impl(&self, impl_: Impl) -> crate::traits::GlobalImplId; 83 fn intern_chalk_impl(&self, impl_: Impl) -> crate::traits::GlobalImplId;
@@ -89,11 +91,14 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
89 fn trait_datum(&self, krate: CrateId, trait_id: chalk::TraitId) -> Arc<chalk::TraitDatum>; 91 fn trait_datum(&self, krate: CrateId, trait_id: chalk::TraitId) -> Arc<chalk::TraitDatum>;
90 92
91 #[salsa::invoke(chalk::struct_datum_query)] 93 #[salsa::invoke(chalk::struct_datum_query)]
92 fn struct_datum(&self, krate: CrateId, struct_id: chalk::StructId) -> Arc<chalk::StructDatum>; 94 fn struct_datum(&self, krate: CrateId, struct_id: chalk::AdtId) -> Arc<chalk::StructDatum>;
93 95
94 #[salsa::invoke(crate::traits::chalk::impl_datum_query)] 96 #[salsa::invoke(crate::traits::chalk::impl_datum_query)]
95 fn impl_datum(&self, krate: CrateId, impl_id: chalk::ImplId) -> Arc<chalk::ImplDatum>; 97 fn impl_datum(&self, krate: CrateId, impl_id: chalk::ImplId) -> Arc<chalk::ImplDatum>;
96 98
99 #[salsa::invoke(crate::traits::chalk::fn_def_datum_query)]
100 fn fn_def_datum(&self, krate: CrateId, fn_def_id: chalk::FnDefId) -> Arc<chalk::FnDefDatum>;
101
97 #[salsa::invoke(crate::traits::chalk::associated_ty_value_query)] 102 #[salsa::invoke(crate::traits::chalk::associated_ty_value_query)]
98 fn associated_ty_value( 103 fn associated_ty_value(
99 &self, 104 &self,
diff --git a/crates/ra_hir_ty/src/diagnostics.rs b/crates/ra_hir_ty/src/diagnostics.rs
index c8fd54861..2c7298714 100644
--- a/crates/ra_hir_ty/src/diagnostics.rs
+++ b/crates/ra_hir_ty/src/diagnostics.rs
@@ -40,7 +40,7 @@ impl Diagnostic for MissingFields {
40 fn message(&self) -> String { 40 fn message(&self) -> String {
41 let mut buf = String::from("Missing structure fields:\n"); 41 let mut buf = String::from("Missing structure fields:\n");
42 for field in &self.missed_fields { 42 for field in &self.missed_fields {
43 format_to!(buf, "- {}", field); 43 format_to!(buf, "- {}\n", field);
44 } 44 }
45 buf 45 buf
46 } 46 }
@@ -73,7 +73,7 @@ impl Diagnostic for MissingPatFields {
73 fn message(&self) -> String { 73 fn message(&self) -> String {
74 let mut buf = String::from("Missing structure fields:\n"); 74 let mut buf = String::from("Missing structure fields:\n");
75 for field in &self.missed_fields { 75 for field in &self.missed_fields {
76 format_to!(buf, "- {}", field); 76 format_to!(buf, "- {}\n", field);
77 } 77 }
78 buf 78 buf
79 } 79 }
@@ -131,3 +131,31 @@ impl AstDiagnostic for MissingOkInTailExpr {
131 ast::Expr::cast(node).unwrap() 131 ast::Expr::cast(node).unwrap()
132 } 132 }
133} 133}
134
135#[derive(Debug)]
136pub struct BreakOutsideOfLoop {
137 pub file: HirFileId,
138 pub expr: AstPtr<ast::Expr>,
139}
140
141impl Diagnostic for BreakOutsideOfLoop {
142 fn message(&self) -> String {
143 "break outside of loop".to_string()
144 }
145 fn source(&self) -> InFile<SyntaxNodePtr> {
146 InFile { file_id: self.file, value: self.expr.clone().into() }
147 }
148 fn as_any(&self) -> &(dyn Any + Send + 'static) {
149 self
150 }
151}
152
153impl AstDiagnostic for BreakOutsideOfLoop {
154 type AST = ast::Expr;
155
156 fn ast(&self, db: &impl AstDatabase) -> Self::AST {
157 let root = db.parse_or_expand(self.file).unwrap();
158 let node = self.source().value.to_node(&root);
159 ast::Expr::cast(node).unwrap()
160 }
161}
diff --git a/crates/ra_hir_ty/src/display.rs b/crates/ra_hir_ty/src/display.rs
index d03bbd5a7..b9c4d2e89 100644
--- a/crates/ra_hir_ty/src/display.rs
+++ b/crates/ra_hir_ty/src/display.rs
@@ -6,28 +6,42 @@ use crate::{
6 db::HirDatabase, utils::generics, ApplicationTy, CallableDef, FnSig, GenericPredicate, 6 db::HirDatabase, utils::generics, ApplicationTy, CallableDef, FnSig, GenericPredicate,
7 Obligation, ProjectionTy, Substs, TraitRef, Ty, TypeCtor, 7 Obligation, ProjectionTy, Substs, TraitRef, Ty, TypeCtor,
8}; 8};
9use hir_def::{generics::TypeParamProvenance, AdtId, AssocContainerId, Lookup}; 9use hir_def::{
10 find_path, generics::TypeParamProvenance, item_scope::ItemInNs, AdtId, AssocContainerId,
11 Lookup, ModuleId,
12};
10use hir_expand::name::Name; 13use hir_expand::name::Name;
11 14
12pub struct HirFormatter<'a, 'b> { 15pub struct HirFormatter<'a> {
13 pub db: &'a dyn HirDatabase, 16 pub db: &'a dyn HirDatabase,
14 fmt: &'a mut fmt::Formatter<'b>, 17 fmt: &'a mut dyn fmt::Write,
15 buf: String, 18 buf: String,
16 curr_size: usize, 19 curr_size: usize,
17 pub(crate) max_size: Option<usize>, 20 pub(crate) max_size: Option<usize>,
18 omit_verbose_types: bool, 21 omit_verbose_types: bool,
22 display_target: DisplayTarget,
19} 23}
20 24
21pub trait HirDisplay { 25pub trait HirDisplay {
22 fn hir_fmt(&self, f: &mut HirFormatter) -> fmt::Result; 26 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError>;
23 27
28 /// Returns a `Display`able type that is human-readable.
29 /// Use this for showing types to the user (e.g. diagnostics)
24 fn display<'a>(&'a self, db: &'a dyn HirDatabase) -> HirDisplayWrapper<'a, Self> 30 fn display<'a>(&'a self, db: &'a dyn HirDatabase) -> HirDisplayWrapper<'a, Self>
25 where 31 where
26 Self: Sized, 32 Self: Sized,
27 { 33 {
28 HirDisplayWrapper(db, self, None, false) 34 HirDisplayWrapper {
35 db,
36 t: self,
37 max_size: None,
38 omit_verbose_types: false,
39 display_target: DisplayTarget::Diagnostics,
40 }
29 } 41 }
30 42
43 /// Returns a `Display`able type that is human-readable and tries to be succinct.
44 /// Use this for showing types to the user where space is constrained (e.g. doc popups)
31 fn display_truncated<'a>( 45 fn display_truncated<'a>(
32 &'a self, 46 &'a self,
33 db: &'a dyn HirDatabase, 47 db: &'a dyn HirDatabase,
@@ -36,16 +50,46 @@ pub trait HirDisplay {
36 where 50 where
37 Self: Sized, 51 Self: Sized,
38 { 52 {
39 HirDisplayWrapper(db, self, max_size, true) 53 HirDisplayWrapper {
54 db,
55 t: self,
56 max_size,
57 omit_verbose_types: true,
58 display_target: DisplayTarget::Diagnostics,
59 }
60 }
61
62 /// Returns a String representation of `self` that can be inserted into the given module.
63 /// Use this when generating code (e.g. assists)
64 fn display_source_code<'a>(
65 &'a self,
66 db: &'a dyn HirDatabase,
67 module_id: ModuleId,
68 ) -> Result<String, DisplaySourceCodeError> {
69 let mut result = String::new();
70 match self.hir_fmt(&mut HirFormatter {
71 db,
72 fmt: &mut result,
73 buf: String::with_capacity(20),
74 curr_size: 0,
75 max_size: None,
76 omit_verbose_types: false,
77 display_target: DisplayTarget::SourceCode { module_id },
78 }) {
79 Ok(()) => {}
80 Err(HirDisplayError::FmtError) => panic!("Writing to String can't fail!"),
81 Err(HirDisplayError::DisplaySourceCodeError(e)) => return Err(e),
82 };
83 Ok(result)
40 } 84 }
41} 85}
42 86
43impl<'a, 'b> HirFormatter<'a, 'b> { 87impl<'a> HirFormatter<'a> {
44 pub fn write_joined<T: HirDisplay>( 88 pub fn write_joined<T: HirDisplay>(
45 &mut self, 89 &mut self,
46 iter: impl IntoIterator<Item = T>, 90 iter: impl IntoIterator<Item = T>,
47 sep: &str, 91 sep: &str,
48 ) -> fmt::Result { 92 ) -> Result<(), HirDisplayError> {
49 let mut first = true; 93 let mut first = true;
50 for e in iter { 94 for e in iter {
51 if !first { 95 if !first {
@@ -58,14 +102,14 @@ impl<'a, 'b> HirFormatter<'a, 'b> {
58 } 102 }
59 103
60 /// This allows using the `write!` macro directly with a `HirFormatter`. 104 /// This allows using the `write!` macro directly with a `HirFormatter`.
61 pub fn write_fmt(&mut self, args: fmt::Arguments) -> fmt::Result { 105 pub fn write_fmt(&mut self, args: fmt::Arguments) -> Result<(), HirDisplayError> {
62 // We write to a buffer first to track output size 106 // We write to a buffer first to track output size
63 self.buf.clear(); 107 self.buf.clear();
64 fmt::write(&mut self.buf, args)?; 108 fmt::write(&mut self.buf, args)?;
65 self.curr_size += self.buf.len(); 109 self.curr_size += self.buf.len();
66 110
67 // Then we write to the internal formatter from the buffer 111 // Then we write to the internal formatter from the buffer
68 self.fmt.write_str(&self.buf) 112 self.fmt.write_str(&self.buf).map_err(HirDisplayError::from)
69 } 113 }
70 114
71 pub fn should_truncate(&self) -> bool { 115 pub fn should_truncate(&self) -> bool {
@@ -81,34 +125,82 @@ impl<'a, 'b> HirFormatter<'a, 'b> {
81 } 125 }
82} 126}
83 127
84pub struct HirDisplayWrapper<'a, T>(&'a dyn HirDatabase, &'a T, Option<usize>, bool); 128#[derive(Clone, Copy)]
129enum DisplayTarget {
130 /// Display types for inlays, doc popups, autocompletion, etc...
131 /// Showing `{unknown}` or not qualifying paths is fine here.
132 /// There's no reason for this to fail.
133 Diagnostics,
134 /// Display types for inserting them in source files.
135 /// The generated code should compile, so paths need to be qualified.
136 SourceCode { module_id: ModuleId },
137}
138
139impl DisplayTarget {
140 fn is_source_code(&self) -> bool {
141 matches!(self, Self::SourceCode {..})
142 }
143}
144
145#[derive(Debug)]
146pub enum DisplaySourceCodeError {
147 PathNotFound,
148}
149
150pub enum HirDisplayError {
151 /// Errors that can occur when generating source code
152 DisplaySourceCodeError(DisplaySourceCodeError),
153 /// `FmtError` is required to be compatible with std::fmt::Display
154 FmtError,
155}
156impl From<fmt::Error> for HirDisplayError {
157 fn from(_: fmt::Error) -> Self {
158 Self::FmtError
159 }
160}
161
162pub struct HirDisplayWrapper<'a, T> {
163 db: &'a dyn HirDatabase,
164 t: &'a T,
165 max_size: Option<usize>,
166 omit_verbose_types: bool,
167 display_target: DisplayTarget,
168}
85 169
86impl<'a, T> fmt::Display for HirDisplayWrapper<'a, T> 170impl<'a, T> fmt::Display for HirDisplayWrapper<'a, T>
87where 171where
88 T: HirDisplay, 172 T: HirDisplay,
89{ 173{
90 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 174 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
91 self.1.hir_fmt(&mut HirFormatter { 175 match self.t.hir_fmt(&mut HirFormatter {
92 db: self.0, 176 db: self.db,
93 fmt: f, 177 fmt: f,
94 buf: String::with_capacity(20), 178 buf: String::with_capacity(20),
95 curr_size: 0, 179 curr_size: 0,
96 max_size: self.2, 180 max_size: self.max_size,
97 omit_verbose_types: self.3, 181 omit_verbose_types: self.omit_verbose_types,
98 }) 182 display_target: self.display_target,
183 }) {
184 Ok(()) => Ok(()),
185 Err(HirDisplayError::FmtError) => Err(fmt::Error),
186 Err(HirDisplayError::DisplaySourceCodeError(_)) => {
187 // This should never happen
188 panic!("HirDisplay failed when calling Display::fmt!")
189 }
190 }
99 } 191 }
100} 192}
101 193
102const TYPE_HINT_TRUNCATION: &str = "…"; 194const TYPE_HINT_TRUNCATION: &str = "…";
103 195
104impl HirDisplay for &Ty { 196impl HirDisplay for &Ty {
105 fn hir_fmt(&self, f: &mut HirFormatter) -> fmt::Result { 197 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
106 HirDisplay::hir_fmt(*self, f) 198 HirDisplay::hir_fmt(*self, f)
107 } 199 }
108} 200}
109 201
110impl HirDisplay for ApplicationTy { 202impl HirDisplay for ApplicationTy {
111 fn hir_fmt(&self, f: &mut HirFormatter) -> fmt::Result { 203 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
112 if f.should_truncate() { 204 if f.should_truncate() {
113 return write!(f, "{}", TYPE_HINT_TRUNCATION); 205 return write!(f, "{}", TYPE_HINT_TRUNCATION);
114 } 206 }
@@ -191,45 +283,66 @@ impl HirDisplay for ApplicationTy {
191 } 283 }
192 } 284 }
193 TypeCtor::Adt(def_id) => { 285 TypeCtor::Adt(def_id) => {
194 let name = match def_id { 286 match f.display_target {
195 AdtId::StructId(it) => f.db.struct_data(it).name.clone(), 287 DisplayTarget::Diagnostics => {
196 AdtId::UnionId(it) => f.db.union_data(it).name.clone(), 288 let name = match def_id {
197 AdtId::EnumId(it) => f.db.enum_data(it).name.clone(), 289 AdtId::StructId(it) => f.db.struct_data(it).name.clone(),
198 }; 290 AdtId::UnionId(it) => f.db.union_data(it).name.clone(),
199 write!(f, "{}", name)?; 291 AdtId::EnumId(it) => f.db.enum_data(it).name.clone(),
292 };
293 write!(f, "{}", name)?;
294 }
295 DisplayTarget::SourceCode { module_id } => {
296 if let Some(path) = find_path::find_path(
297 f.db.upcast(),
298 ItemInNs::Types(def_id.into()),
299 module_id,
300 ) {
301 write!(f, "{}", path)?;
302 } else {
303 return Err(HirDisplayError::DisplaySourceCodeError(
304 DisplaySourceCodeError::PathNotFound,
305 ));
306 }
307 }
308 }
309
200 if self.parameters.len() > 0 { 310 if self.parameters.len() > 0 {
201 let mut non_default_parameters = Vec::with_capacity(self.parameters.len()); 311 let mut non_default_parameters = Vec::with_capacity(self.parameters.len());
202 let parameters_to_write = if f.omit_verbose_types() { 312 let parameters_to_write =
203 match self 313 if f.display_target.is_source_code() || f.omit_verbose_types() {
204 .ctor 314 match self
205 .as_generic_def() 315 .ctor
206 .map(|generic_def_id| f.db.generic_defaults(generic_def_id)) 316 .as_generic_def()
207 .filter(|defaults| !defaults.is_empty()) 317 .map(|generic_def_id| f.db.generic_defaults(generic_def_id))
208 { 318 .filter(|defaults| !defaults.is_empty())
209 None => self.parameters.0.as_ref(), 319 {
210 Some(default_parameters) => { 320 None => self.parameters.0.as_ref(),
211 for (i, parameter) in self.parameters.iter().enumerate() { 321 Some(default_parameters) => {
212 match (parameter, default_parameters.get(i)) { 322 for (i, parameter) in self.parameters.iter().enumerate() {
213 (&Ty::Unknown, _) | (_, None) => { 323 match (parameter, default_parameters.get(i)) {
214 non_default_parameters.push(parameter.clone()) 324 (&Ty::Unknown, _) | (_, None) => {
325 non_default_parameters.push(parameter.clone())
326 }
327 (_, Some(default_parameter))
328 if parameter != default_parameter =>
329 {
330 non_default_parameters.push(parameter.clone())
331 }
332 _ => (),
215 } 333 }
216 (_, Some(default_parameter))
217 if parameter != default_parameter =>
218 {
219 non_default_parameters.push(parameter.clone())
220 }
221 _ => (),
222 } 334 }
335 &non_default_parameters
223 } 336 }
224 &non_default_parameters
225 } 337 }
226 } 338 } else {
227 } else { 339 self.parameters.0.as_ref()
228 self.parameters.0.as_ref() 340 };
229 }; 341 if !parameters_to_write.is_empty() {
230 write!(f, "<")?; 342 write!(f, "<")?;
231 f.write_joined(parameters_to_write, ", ")?; 343 f.write_joined(parameters_to_write, ", ")?;
232 write!(f, ">")?; 344 write!(f, ">")?;
345 }
233 } 346 }
234 } 347 }
235 TypeCtor::AssociatedType(type_alias) => { 348 TypeCtor::AssociatedType(type_alias) => {
@@ -269,7 +382,7 @@ impl HirDisplay for ApplicationTy {
269} 382}
270 383
271impl HirDisplay for ProjectionTy { 384impl HirDisplay for ProjectionTy {
272 fn hir_fmt(&self, f: &mut HirFormatter) -> fmt::Result { 385 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
273 if f.should_truncate() { 386 if f.should_truncate() {
274 return write!(f, "{}", TYPE_HINT_TRUNCATION); 387 return write!(f, "{}", TYPE_HINT_TRUNCATION);
275 } 388 }
@@ -287,7 +400,7 @@ impl HirDisplay for ProjectionTy {
287} 400}
288 401
289impl HirDisplay for Ty { 402impl HirDisplay for Ty {
290 fn hir_fmt(&self, f: &mut HirFormatter) -> fmt::Result { 403 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
291 if f.should_truncate() { 404 if f.should_truncate() {
292 return write!(f, "{}", TYPE_HINT_TRUNCATION); 405 return write!(f, "{}", TYPE_HINT_TRUNCATION);
293 } 406 }
@@ -332,7 +445,7 @@ impl HirDisplay for Ty {
332fn write_bounds_like_dyn_trait( 445fn write_bounds_like_dyn_trait(
333 predicates: &[GenericPredicate], 446 predicates: &[GenericPredicate],
334 f: &mut HirFormatter, 447 f: &mut HirFormatter,
335) -> fmt::Result { 448) -> Result<(), HirDisplayError> {
336 // Note: This code is written to produce nice results (i.e. 449 // Note: This code is written to produce nice results (i.e.
337 // corresponding to surface Rust) for types that can occur in 450 // corresponding to surface Rust) for types that can occur in
338 // actual Rust. It will have weird results if the predicates 451 // actual Rust. It will have weird results if the predicates
@@ -394,7 +507,7 @@ fn write_bounds_like_dyn_trait(
394} 507}
395 508
396impl TraitRef { 509impl TraitRef {
397 fn hir_fmt_ext(&self, f: &mut HirFormatter, use_as: bool) -> fmt::Result { 510 fn hir_fmt_ext(&self, f: &mut HirFormatter, use_as: bool) -> Result<(), HirDisplayError> {
398 if f.should_truncate() { 511 if f.should_truncate() {
399 return write!(f, "{}", TYPE_HINT_TRUNCATION); 512 return write!(f, "{}", TYPE_HINT_TRUNCATION);
400 } 513 }
@@ -416,19 +529,19 @@ impl TraitRef {
416} 529}
417 530
418impl HirDisplay for TraitRef { 531impl HirDisplay for TraitRef {
419 fn hir_fmt(&self, f: &mut HirFormatter) -> fmt::Result { 532 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
420 self.hir_fmt_ext(f, false) 533 self.hir_fmt_ext(f, false)
421 } 534 }
422} 535}
423 536
424impl HirDisplay for &GenericPredicate { 537impl HirDisplay for &GenericPredicate {
425 fn hir_fmt(&self, f: &mut HirFormatter) -> fmt::Result { 538 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
426 HirDisplay::hir_fmt(*self, f) 539 HirDisplay::hir_fmt(*self, f)
427 } 540 }
428} 541}
429 542
430impl HirDisplay for GenericPredicate { 543impl HirDisplay for GenericPredicate {
431 fn hir_fmt(&self, f: &mut HirFormatter) -> fmt::Result { 544 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
432 if f.should_truncate() { 545 if f.should_truncate() {
433 return write!(f, "{}", TYPE_HINT_TRUNCATION); 546 return write!(f, "{}", TYPE_HINT_TRUNCATION);
434 } 547 }
@@ -452,15 +565,15 @@ impl HirDisplay for GenericPredicate {
452} 565}
453 566
454impl HirDisplay for Obligation { 567impl HirDisplay for Obligation {
455 fn hir_fmt(&self, f: &mut HirFormatter) -> fmt::Result { 568 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
456 match self { 569 Ok(match self {
457 Obligation::Trait(tr) => write!(f, "Implements({})", tr.display(f.db)), 570 Obligation::Trait(tr) => write!(f, "Implements({})", tr.display(f.db))?,
458 Obligation::Projection(proj) => write!( 571 Obligation::Projection(proj) => write!(
459 f, 572 f,
460 "Normalize({} => {})", 573 "Normalize({} => {})",
461 proj.projection_ty.display(f.db), 574 proj.projection_ty.display(f.db),
462 proj.ty.display(f.db) 575 proj.ty.display(f.db)
463 ), 576 )?,
464 } 577 })
465 } 578 }
466} 579}
diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs
index bd4ef69a0..dc77e88e5 100644
--- a/crates/ra_hir_ty/src/infer.rs
+++ b/crates/ra_hir_ty/src/infer.rs
@@ -22,13 +22,14 @@ use rustc_hash::FxHashMap;
22 22
23use hir_def::{ 23use hir_def::{
24 body::Body, 24 body::Body,
25 data::{ConstData, FunctionData}, 25 data::{ConstData, FunctionData, StaticData},
26 expr::{BindingAnnotation, ExprId, PatId}, 26 expr::{BindingAnnotation, ExprId, PatId},
27 lang_item::LangItemTarget, 27 lang_item::LangItemTarget,
28 path::{path, Path}, 28 path::{path, Path},
29 resolver::{HasResolver, Resolver, TypeNs}, 29 resolver::{HasResolver, Resolver, TypeNs},
30 type_ref::{Mutability, TypeRef}, 30 type_ref::{Mutability, TypeRef},
31 AdtId, AssocItemId, DefWithBodyId, FieldId, FunctionId, TraitId, TypeAliasId, VariantId, 31 AdtId, AssocItemId, DefWithBodyId, EnumVariantId, FieldId, FunctionId, TraitId, TypeAliasId,
32 VariantId,
32}; 33};
33use hir_expand::{diagnostics::DiagnosticSink, name::name}; 34use hir_expand::{diagnostics::DiagnosticSink, name::name};
34use ra_arena::map::ArenaMap; 35use ra_arena::map::ArenaMap;
@@ -71,7 +72,7 @@ pub(crate) fn infer_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc<Infer
71 match def { 72 match def {
72 DefWithBodyId::ConstId(c) => ctx.collect_const(&db.const_data(c)), 73 DefWithBodyId::ConstId(c) => ctx.collect_const(&db.const_data(c)),
73 DefWithBodyId::FunctionId(f) => ctx.collect_fn(&db.function_data(f)), 74 DefWithBodyId::FunctionId(f) => ctx.collect_fn(&db.function_data(f)),
74 DefWithBodyId::StaticId(s) => ctx.collect_const(&db.static_data(s)), 75 DefWithBodyId::StaticId(s) => ctx.collect_static(&db.static_data(s)),
75 } 76 }
76 77
77 ctx.infer_body(); 78 ctx.infer_body();
@@ -210,6 +211,25 @@ struct InferenceContext<'a> {
210 /// closures, but currently this is the only field that will change there, 211 /// closures, but currently this is the only field that will change there,
211 /// so it doesn't make sense. 212 /// so it doesn't make sense.
212 return_ty: Ty, 213 return_ty: Ty,
214 diverges: Diverges,
215 breakables: Vec<BreakableContext>,
216}
217
218#[derive(Clone, Debug)]
219struct BreakableContext {
220 pub may_break: bool,
221 pub break_ty: Ty,
222 pub label: Option<name::Name>,
223}
224
225fn find_breakable<'c>(
226 ctxs: &'c mut [BreakableContext],
227 label: Option<&name::Name>,
228) -> Option<&'c mut BreakableContext> {
229 match label {
230 Some(_) => ctxs.iter_mut().rev().find(|ctx| ctx.label.as_ref() == label),
231 None => ctxs.last_mut(),
232 }
213} 233}
214 234
215impl<'a> InferenceContext<'a> { 235impl<'a> InferenceContext<'a> {
@@ -224,6 +244,8 @@ impl<'a> InferenceContext<'a> {
224 owner, 244 owner,
225 body: db.body(owner), 245 body: db.body(owner),
226 resolver, 246 resolver,
247 diverges: Diverges::Maybe,
248 breakables: Vec::new(),
227 } 249 }
228 } 250 }
229 251
@@ -429,43 +451,95 @@ impl<'a> InferenceContext<'a> {
429 let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver); 451 let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver);
430 // FIXME: this should resolve assoc items as well, see this example: 452 // FIXME: this should resolve assoc items as well, see this example:
431 // https://play.rust-lang.org/?gist=087992e9e22495446c01c0d4e2d69521 453 // https://play.rust-lang.org/?gist=087992e9e22495446c01c0d4e2d69521
432 return match resolver.resolve_path_in_type_ns_fully(self.db.upcast(), path.mod_path()) { 454 let (resolution, unresolved) =
433 Some(TypeNs::AdtId(AdtId::StructId(strukt))) => { 455 match resolver.resolve_path_in_type_ns(self.db.upcast(), path.mod_path()) {
456 Some(it) => it,
457 None => return (Ty::Unknown, None),
458 };
459 return match resolution {
460 TypeNs::AdtId(AdtId::StructId(strukt)) => {
434 let substs = Ty::substs_from_path(&ctx, path, strukt.into()); 461 let substs = Ty::substs_from_path(&ctx, path, strukt.into());
435 let ty = self.db.ty(strukt.into()); 462 let ty = self.db.ty(strukt.into());
436 let ty = self.insert_type_vars(ty.subst(&substs)); 463 let ty = self.insert_type_vars(ty.subst(&substs));
437 (ty, Some(strukt.into())) 464 forbid_unresolved_segments((ty, Some(strukt.into())), unresolved)
438 } 465 }
439 Some(TypeNs::EnumVariantId(var)) => { 466 TypeNs::EnumVariantId(var) => {
440 let substs = Ty::substs_from_path(&ctx, path, var.into()); 467 let substs = Ty::substs_from_path(&ctx, path, var.into());
441 let ty = self.db.ty(var.parent.into()); 468 let ty = self.db.ty(var.parent.into());
442 let ty = self.insert_type_vars(ty.subst(&substs)); 469 let ty = self.insert_type_vars(ty.subst(&substs));
443 (ty, Some(var.into())) 470 forbid_unresolved_segments((ty, Some(var.into())), unresolved)
444 } 471 }
445 Some(TypeNs::SelfType(impl_id)) => { 472 TypeNs::SelfType(impl_id) => {
446 let generics = crate::utils::generics(self.db.upcast(), impl_id.into()); 473 let generics = crate::utils::generics(self.db.upcast(), impl_id.into());
447 let substs = Substs::type_params_for_generics(&generics); 474 let substs = Substs::type_params_for_generics(&generics);
448 let ty = self.db.impl_self_ty(impl_id).subst(&substs); 475 let ty = self.db.impl_self_ty(impl_id).subst(&substs);
449 let variant = ty_variant(&ty); 476 match unresolved {
450 (ty, variant) 477 None => {
478 let variant = ty_variant(&ty);
479 (ty, variant)
480 }
481 Some(1) => {
482 let segment = path.mod_path().segments.last().unwrap();
483 // this could be an enum variant or associated type
484 if let Some((AdtId::EnumId(enum_id), _)) = ty.as_adt() {
485 let enum_data = self.db.enum_data(enum_id);
486 if let Some(local_id) = enum_data.variant(segment) {
487 let variant = EnumVariantId { parent: enum_id, local_id };
488 return (ty, Some(variant.into()));
489 }
490 }
491 // FIXME potentially resolve assoc type
492 (Ty::Unknown, None)
493 }
494 Some(_) => {
495 // FIXME diagnostic
496 (Ty::Unknown, None)
497 }
498 }
451 } 499 }
452 Some(TypeNs::TypeAliasId(it)) => { 500 TypeNs::TypeAliasId(it) => {
453 let substs = Substs::build_for_def(self.db, it) 501 let substs = Substs::build_for_def(self.db, it)
454 .fill(std::iter::repeat_with(|| self.table.new_type_var())) 502 .fill(std::iter::repeat_with(|| self.table.new_type_var()))
455 .build(); 503 .build();
456 let ty = self.db.ty(it.into()).subst(&substs); 504 let ty = self.db.ty(it.into()).subst(&substs);
457 let variant = ty_variant(&ty); 505 let variant = ty_variant(&ty);
458 (ty, variant) 506 forbid_unresolved_segments((ty, variant), unresolved)
507 }
508 TypeNs::AdtSelfType(_) => {
509 // FIXME this could happen in array size expressions, once we're checking them
510 (Ty::Unknown, None)
511 }
512 TypeNs::GenericParam(_) => {
513 // FIXME potentially resolve assoc type
514 (Ty::Unknown, None)
515 }
516 TypeNs::AdtId(AdtId::EnumId(_))
517 | TypeNs::AdtId(AdtId::UnionId(_))
518 | TypeNs::BuiltinType(_)
519 | TypeNs::TraitId(_) => {
520 // FIXME diagnostic
521 (Ty::Unknown, None)
459 } 522 }
460 Some(_) | None => (Ty::Unknown, None),
461 }; 523 };
462 524
525 fn forbid_unresolved_segments(
526 result: (Ty, Option<VariantId>),
527 unresolved: Option<usize>,
528 ) -> (Ty, Option<VariantId>) {
529 if unresolved.is_none() {
530 result
531 } else {
532 // FIXME diagnostic
533 (Ty::Unknown, None)
534 }
535 }
536
463 fn ty_variant(ty: &Ty) -> Option<VariantId> { 537 fn ty_variant(ty: &Ty) -> Option<VariantId> {
464 ty.as_adt().and_then(|(adt_id, _)| match adt_id { 538 ty.as_adt().and_then(|(adt_id, _)| match adt_id {
465 AdtId::StructId(s) => Some(VariantId::StructId(s)), 539 AdtId::StructId(s) => Some(VariantId::StructId(s)),
466 AdtId::UnionId(u) => Some(VariantId::UnionId(u)), 540 AdtId::UnionId(u) => Some(VariantId::UnionId(u)),
467 AdtId::EnumId(_) => { 541 AdtId::EnumId(_) => {
468 // Error E0071, expected struct, variant or union type, found enum `Foo` 542 // FIXME Error E0071, expected struct, variant or union type, found enum `Foo`
469 None 543 None
470 } 544 }
471 }) 545 })
@@ -476,6 +550,10 @@ impl<'a> InferenceContext<'a> {
476 self.return_ty = self.make_ty(&data.type_ref); 550 self.return_ty = self.make_ty(&data.type_ref);
477 } 551 }
478 552
553 fn collect_static(&mut self, data: &StaticData) {
554 self.return_ty = self.make_ty(&data.type_ref);
555 }
556
479 fn collect_fn(&mut self, data: &FunctionData) { 557 fn collect_fn(&mut self, data: &FunctionData) {
480 let body = Arc::clone(&self.body); // avoid borrow checker problem 558 let body = Arc::clone(&self.body); // avoid borrow checker problem
481 let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver) 559 let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver)
@@ -666,15 +744,57 @@ impl Expectation {
666 } 744 }
667} 745}
668 746
747#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
748enum Diverges {
749 Maybe,
750 Always,
751}
752
753impl Diverges {
754 fn is_always(self) -> bool {
755 self == Diverges::Always
756 }
757}
758
759impl std::ops::BitAnd for Diverges {
760 type Output = Self;
761 fn bitand(self, other: Self) -> Self {
762 std::cmp::min(self, other)
763 }
764}
765
766impl std::ops::BitOr for Diverges {
767 type Output = Self;
768 fn bitor(self, other: Self) -> Self {
769 std::cmp::max(self, other)
770 }
771}
772
773impl std::ops::BitAndAssign for Diverges {
774 fn bitand_assign(&mut self, other: Self) {
775 *self = *self & other;
776 }
777}
778
779impl std::ops::BitOrAssign for Diverges {
780 fn bitor_assign(&mut self, other: Self) {
781 *self = *self | other;
782 }
783}
784
669mod diagnostics { 785mod diagnostics {
670 use hir_def::{expr::ExprId, FunctionId}; 786 use hir_def::{expr::ExprId, FunctionId};
671 use hir_expand::diagnostics::DiagnosticSink; 787 use hir_expand::diagnostics::DiagnosticSink;
672 788
673 use crate::{db::HirDatabase, diagnostics::NoSuchField}; 789 use crate::{
790 db::HirDatabase,
791 diagnostics::{BreakOutsideOfLoop, NoSuchField},
792 };
674 793
675 #[derive(Debug, PartialEq, Eq, Clone)] 794 #[derive(Debug, PartialEq, Eq, Clone)]
676 pub(super) enum InferenceDiagnostic { 795 pub(super) enum InferenceDiagnostic {
677 NoSuchField { expr: ExprId, field: usize }, 796 NoSuchField { expr: ExprId, field: usize },
797 BreakOutsideOfLoop { expr: ExprId },
678 } 798 }
679 799
680 impl InferenceDiagnostic { 800 impl InferenceDiagnostic {
@@ -690,6 +810,13 @@ mod diagnostics {
690 let field = source_map.field_syntax(*expr, *field); 810 let field = source_map.field_syntax(*expr, *field);
691 sink.push(NoSuchField { file: field.file_id, field: field.value }) 811 sink.push(NoSuchField { file: field.file_id, field: field.value })
692 } 812 }
813 InferenceDiagnostic::BreakOutsideOfLoop { expr } => {
814 let (_, source_map) = db.body_with_source_map(owner.into());
815 let ptr = source_map
816 .expr_syntax(*expr)
817 .expect("break outside of loop in synthetic syntax");
818 sink.push(BreakOutsideOfLoop { file: ptr.file_id, expr: ptr.value })
819 }
693 } 820 }
694 } 821 }
695 } 822 }
diff --git a/crates/ra_hir_ty/src/infer/coerce.rs b/crates/ra_hir_ty/src/infer/coerce.rs
index 89200255a..32c7c57cd 100644
--- a/crates/ra_hir_ty/src/infer/coerce.rs
+++ b/crates/ra_hir_ty/src/infer/coerce.rs
@@ -5,7 +5,7 @@
5//! See: https://doc.rust-lang.org/nomicon/coercions.html 5//! See: https://doc.rust-lang.org/nomicon/coercions.html
6 6
7use hir_def::{lang_item::LangItemTarget, type_ref::Mutability}; 7use hir_def::{lang_item::LangItemTarget, type_ref::Mutability};
8use test_utils::tested_by; 8use test_utils::mark;
9 9
10use crate::{autoderef, traits::Solution, Obligation, Substs, TraitRef, Ty, TypeCtor}; 10use crate::{autoderef, traits::Solution, Obligation, Substs, TraitRef, Ty, TypeCtor};
11 11
@@ -20,21 +20,33 @@ impl<'a> InferenceContext<'a> {
20 self.coerce_inner(from_ty, &to_ty) 20 self.coerce_inner(from_ty, &to_ty)
21 } 21 }
22 22
23 /// Merge two types from different branches, with possible implicit coerce. 23 /// Merge two types from different branches, with possible coercion.
24 /// 24 ///
25 /// Note that it is only possible that one type are coerced to another. 25 /// Mostly this means trying to coerce one to the other, but
26 /// Coercing both types to another least upper bound type is not possible in rustc, 26 /// - if we have two function types for different functions, we need to
27 /// which will simply result in "incompatible types" error. 27 /// coerce both to function pointers;
28 /// - if we were concerned with lifetime subtyping, we'd need to look for a
29 /// least upper bound.
28 pub(super) fn coerce_merge_branch(&mut self, ty1: &Ty, ty2: &Ty) -> Ty { 30 pub(super) fn coerce_merge_branch(&mut self, ty1: &Ty, ty2: &Ty) -> Ty {
29 if self.coerce(ty1, ty2) { 31 if self.coerce(ty1, ty2) {
30 ty2.clone() 32 ty2.clone()
31 } else if self.coerce(ty2, ty1) { 33 } else if self.coerce(ty2, ty1) {
32 ty1.clone() 34 ty1.clone()
33 } else { 35 } else {
34 tested_by!(coerce_merge_fail_fallback); 36 if let (ty_app!(TypeCtor::FnDef(_)), ty_app!(TypeCtor::FnDef(_))) = (ty1, ty2) {
35 // For incompatible types, we use the latter one as result 37 mark::hit!(coerce_fn_reification);
36 // to be better recovery for `if` without `else`. 38 // Special case: two function types. Try to coerce both to
37 ty2.clone() 39 // pointers to have a chance at getting a match. See
40 // https://github.com/rust-lang/rust/blob/7b805396bf46dce972692a6846ce2ad8481c5f85/src/librustc_typeck/check/coercion.rs#L877-L916
41 let sig1 = ty1.callable_sig(self.db).expect("FnDef without callable sig");
42 let sig2 = ty2.callable_sig(self.db).expect("FnDef without callable sig");
43 let ptr_ty1 = Ty::fn_ptr(sig1);
44 let ptr_ty2 = Ty::fn_ptr(sig2);
45 self.coerce_merge_branch(&ptr_ty1, &ptr_ty2)
46 } else {
47 mark::hit!(coerce_merge_fail_fallback);
48 ty1.clone()
49 }
38 } 50 }
39 } 51 }
40 52
@@ -84,9 +96,7 @@ impl<'a> InferenceContext<'a> {
84 match from_ty.callable_sig(self.db) { 96 match from_ty.callable_sig(self.db) {
85 None => return false, 97 None => return false,
86 Some(sig) => { 98 Some(sig) => {
87 let num_args = sig.params_and_return.len() as u16 - 1; 99 from_ty = Ty::fn_ptr(sig);
88 from_ty =
89 Ty::apply(TypeCtor::FnPtr { num_args }, Substs(sig.params_and_return));
90 } 100 }
91 } 101 }
92 } 102 }
diff --git a/crates/ra_hir_ty/src/infer/expr.rs b/crates/ra_hir_ty/src/infer/expr.rs
index efc60986b..4a98e2deb 100644
--- a/crates/ra_hir_ty/src/infer/expr.rs
+++ b/crates/ra_hir_ty/src/infer/expr.rs
@@ -1,7 +1,7 @@
1//! Type inference for expressions. 1//! Type inference for expressions.
2 2
3use std::iter::{repeat, repeat_with}; 3use std::iter::{repeat, repeat_with};
4use std::sync::Arc; 4use std::{mem, sync::Arc};
5 5
6use hir_def::{ 6use hir_def::{
7 builtin_type::Signedness, 7 builtin_type::Signedness,
@@ -17,15 +17,22 @@ use crate::{
17 autoderef, method_resolution, op, 17 autoderef, method_resolution, op,
18 traits::InEnvironment, 18 traits::InEnvironment,
19 utils::{generics, variant_data, Generics}, 19 utils::{generics, variant_data, Generics},
20 ApplicationTy, Binders, CallableDef, InferTy, IntTy, Mutability, Obligation, Substs, TraitRef, 20 ApplicationTy, Binders, CallableDef, InferTy, IntTy, Mutability, Obligation, Rawness, Substs,
21 Ty, TypeCtor, Uncertain, 21 TraitRef, Ty, TypeCtor, Uncertain,
22}; 22};
23 23
24use super::{BindingMode, Expectation, InferenceContext, InferenceDiagnostic, TypeMismatch}; 24use super::{
25 find_breakable, BindingMode, BreakableContext, Diverges, Expectation, InferenceContext,
26 InferenceDiagnostic, TypeMismatch,
27};
25 28
26impl<'a> InferenceContext<'a> { 29impl<'a> InferenceContext<'a> {
27 pub(super) fn infer_expr(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty { 30 pub(super) fn infer_expr(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty {
28 let ty = self.infer_expr_inner(tgt_expr, expected); 31 let ty = self.infer_expr_inner(tgt_expr, expected);
32 if ty.is_never() {
33 // Any expression that produces a value of type `!` must have diverged
34 self.diverges = Diverges::Always;
35 }
29 let could_unify = self.unify(&ty, &expected.ty); 36 let could_unify = self.unify(&ty, &expected.ty);
30 if !could_unify { 37 if !could_unify {
31 self.result.type_mismatches.insert( 38 self.result.type_mismatches.insert(
@@ -64,34 +71,80 @@ impl<'a> InferenceContext<'a> {
64 // if let is desugared to match, so this is always simple if 71 // if let is desugared to match, so this is always simple if
65 self.infer_expr(*condition, &Expectation::has_type(Ty::simple(TypeCtor::Bool))); 72 self.infer_expr(*condition, &Expectation::has_type(Ty::simple(TypeCtor::Bool)));
66 73
74 let condition_diverges = mem::replace(&mut self.diverges, Diverges::Maybe);
75 let mut both_arms_diverge = Diverges::Always;
76
67 let then_ty = self.infer_expr_inner(*then_branch, &expected); 77 let then_ty = self.infer_expr_inner(*then_branch, &expected);
78 both_arms_diverge &= mem::replace(&mut self.diverges, Diverges::Maybe);
68 let else_ty = match else_branch { 79 let else_ty = match else_branch {
69 Some(else_branch) => self.infer_expr_inner(*else_branch, &expected), 80 Some(else_branch) => self.infer_expr_inner(*else_branch, &expected),
70 None => Ty::unit(), 81 None => Ty::unit(),
71 }; 82 };
83 both_arms_diverge &= self.diverges;
84
85 self.diverges = condition_diverges | both_arms_diverge;
72 86
73 self.coerce_merge_branch(&then_ty, &else_ty) 87 self.coerce_merge_branch(&then_ty, &else_ty)
74 } 88 }
75 Expr::Block { statements, tail } => self.infer_block(statements, *tail, expected), 89 Expr::Block { statements, tail, .. } => {
76 Expr::Loop { body } => { 90 // FIXME: Breakable block inference
91 self.infer_block(statements, *tail, expected)
92 }
93 Expr::TryBlock { body } => {
94 let _inner = self.infer_expr(*body, expected);
95 // FIXME should be std::result::Result<{inner}, _>
96 Ty::Unknown
97 }
98 Expr::Loop { body, label } => {
99 self.breakables.push(BreakableContext {
100 may_break: false,
101 break_ty: self.table.new_type_var(),
102 label: label.clone(),
103 });
77 self.infer_expr(*body, &Expectation::has_type(Ty::unit())); 104 self.infer_expr(*body, &Expectation::has_type(Ty::unit()));
78 // FIXME handle break with value 105
79 Ty::simple(TypeCtor::Never) 106 let ctxt = self.breakables.pop().expect("breakable stack broken");
107 if ctxt.may_break {
108 self.diverges = Diverges::Maybe;
109 }
110
111 if ctxt.may_break {
112 ctxt.break_ty
113 } else {
114 Ty::simple(TypeCtor::Never)
115 }
80 } 116 }
81 Expr::While { condition, body } => { 117 Expr::While { condition, body, label } => {
118 self.breakables.push(BreakableContext {
119 may_break: false,
120 break_ty: Ty::Unknown,
121 label: label.clone(),
122 });
82 // while let is desugared to a match loop, so this is always simple while 123 // while let is desugared to a match loop, so this is always simple while
83 self.infer_expr(*condition, &Expectation::has_type(Ty::simple(TypeCtor::Bool))); 124 self.infer_expr(*condition, &Expectation::has_type(Ty::simple(TypeCtor::Bool)));
84 self.infer_expr(*body, &Expectation::has_type(Ty::unit())); 125 self.infer_expr(*body, &Expectation::has_type(Ty::unit()));
126 let _ctxt = self.breakables.pop().expect("breakable stack broken");
127 // the body may not run, so it diverging doesn't mean we diverge
128 self.diverges = Diverges::Maybe;
85 Ty::unit() 129 Ty::unit()
86 } 130 }
87 Expr::For { iterable, body, pat } => { 131 Expr::For { iterable, body, pat, label } => {
88 let iterable_ty = self.infer_expr(*iterable, &Expectation::none()); 132 let iterable_ty = self.infer_expr(*iterable, &Expectation::none());
89 133
134 self.breakables.push(BreakableContext {
135 may_break: false,
136 break_ty: Ty::Unknown,
137 label: label.clone(),
138 });
90 let pat_ty = 139 let pat_ty =
91 self.resolve_associated_type(iterable_ty, self.resolve_into_iter_item()); 140 self.resolve_associated_type(iterable_ty, self.resolve_into_iter_item());
92 141
93 self.infer_pat(*pat, &pat_ty, BindingMode::default()); 142 self.infer_pat(*pat, &pat_ty, BindingMode::default());
143
94 self.infer_expr(*body, &Expectation::has_type(Ty::unit())); 144 self.infer_expr(*body, &Expectation::has_type(Ty::unit()));
145 let _ctxt = self.breakables.pop().expect("breakable stack broken");
146 // the body may not run, so it diverging doesn't mean we diverge
147 self.diverges = Diverges::Maybe;
95 Ty::unit() 148 Ty::unit()
96 } 149 }
97 Expr::Lambda { body, args, ret_type, arg_types } => { 150 Expr::Lambda { body, args, ret_type, arg_types } => {
@@ -99,13 +152,13 @@ impl<'a> InferenceContext<'a> {
99 152
100 let mut sig_tys = Vec::new(); 153 let mut sig_tys = Vec::new();
101 154
102 for (arg_pat, arg_type) in args.iter().zip(arg_types.iter()) { 155 // collect explicitly written argument types
103 let expected = if let Some(type_ref) = arg_type { 156 for arg_type in arg_types.iter() {
157 let arg_ty = if let Some(type_ref) = arg_type {
104 self.make_ty(type_ref) 158 self.make_ty(type_ref)
105 } else { 159 } else {
106 Ty::Unknown 160 self.table.new_type_var()
107 }; 161 };
108 let arg_ty = self.infer_pat(*arg_pat, &expected, BindingMode::default());
109 sig_tys.push(arg_ty); 162 sig_tys.push(arg_ty);
110 } 163 }
111 164
@@ -117,7 +170,7 @@ impl<'a> InferenceContext<'a> {
117 sig_tys.push(ret_ty.clone()); 170 sig_tys.push(ret_ty.clone());
118 let sig_ty = Ty::apply( 171 let sig_ty = Ty::apply(
119 TypeCtor::FnPtr { num_args: sig_tys.len() as u16 - 1 }, 172 TypeCtor::FnPtr { num_args: sig_tys.len() as u16 - 1 },
120 Substs(sig_tys.into()), 173 Substs(sig_tys.clone().into()),
121 ); 174 );
122 let closure_ty = 175 let closure_ty =
123 Ty::apply_one(TypeCtor::Closure { def: self.owner, expr: tgt_expr }, sig_ty); 176 Ty::apply_one(TypeCtor::Closure { def: self.owner, expr: tgt_expr }, sig_ty);
@@ -127,10 +180,18 @@ impl<'a> InferenceContext<'a> {
127 // infer the body. 180 // infer the body.
128 self.coerce(&closure_ty, &expected.ty); 181 self.coerce(&closure_ty, &expected.ty);
129 182
130 let prev_ret_ty = std::mem::replace(&mut self.return_ty, ret_ty.clone()); 183 // Now go through the argument patterns
184 for (arg_pat, arg_ty) in args.iter().zip(sig_tys) {
185 let resolved = self.resolve_ty_as_possible(arg_ty);
186 self.infer_pat(*arg_pat, &resolved, BindingMode::default());
187 }
188
189 let prev_diverges = mem::replace(&mut self.diverges, Diverges::Maybe);
190 let prev_ret_ty = mem::replace(&mut self.return_ty, ret_ty.clone());
131 191
132 self.infer_expr_coerce(*body, &Expectation::has_type(ret_ty)); 192 self.infer_expr_coerce(*body, &Expectation::has_type(ret_ty));
133 193
194 self.diverges = prev_diverges;
134 self.return_ty = prev_ret_ty; 195 self.return_ty = prev_ret_ty;
135 196
136 closure_ty 197 closure_ty
@@ -160,7 +221,11 @@ impl<'a> InferenceContext<'a> {
160 self.table.new_type_var() 221 self.table.new_type_var()
161 }; 222 };
162 223
224 let matchee_diverges = self.diverges;
225 let mut all_arms_diverge = Diverges::Always;
226
163 for arm in arms { 227 for arm in arms {
228 self.diverges = Diverges::Maybe;
164 let _pat_ty = self.infer_pat(arm.pat, &input_ty, BindingMode::default()); 229 let _pat_ty = self.infer_pat(arm.pat, &input_ty, BindingMode::default());
165 if let Some(guard_expr) = arm.guard { 230 if let Some(guard_expr) = arm.guard {
166 self.infer_expr( 231 self.infer_expr(
@@ -170,9 +235,12 @@ impl<'a> InferenceContext<'a> {
170 } 235 }
171 236
172 let arm_ty = self.infer_expr_inner(arm.expr, &expected); 237 let arm_ty = self.infer_expr_inner(arm.expr, &expected);
238 all_arms_diverge &= self.diverges;
173 result_ty = self.coerce_merge_branch(&result_ty, &arm_ty); 239 result_ty = self.coerce_merge_branch(&result_ty, &arm_ty);
174 } 240 }
175 241
242 self.diverges = matchee_diverges | all_arms_diverge;
243
176 result_ty 244 result_ty
177 } 245 }
178 Expr::Path(p) => { 246 Expr::Path(p) => {
@@ -180,12 +248,32 @@ impl<'a> InferenceContext<'a> {
180 let resolver = resolver_for_expr(self.db.upcast(), self.owner, tgt_expr); 248 let resolver = resolver_for_expr(self.db.upcast(), self.owner, tgt_expr);
181 self.infer_path(&resolver, p, tgt_expr.into()).unwrap_or(Ty::Unknown) 249 self.infer_path(&resolver, p, tgt_expr.into()).unwrap_or(Ty::Unknown)
182 } 250 }
183 Expr::Continue => Ty::simple(TypeCtor::Never), 251 Expr::Continue { .. } => Ty::simple(TypeCtor::Never),
184 Expr::Break { expr } => { 252 Expr::Break { expr, label } => {
185 if let Some(expr) = expr { 253 let val_ty = if let Some(expr) = expr {
186 // FIXME handle break with value 254 self.infer_expr(*expr, &Expectation::none())
187 self.infer_expr(*expr, &Expectation::none()); 255 } else {
256 Ty::unit()
257 };
258
259 let last_ty =
260 if let Some(ctxt) = find_breakable(&mut self.breakables, label.as_ref()) {
261 ctxt.break_ty.clone()
262 } else {
263 Ty::Unknown
264 };
265
266 let merged_type = self.coerce_merge_branch(&last_ty, &val_ty);
267
268 if let Some(ctxt) = find_breakable(&mut self.breakables, label.as_ref()) {
269 ctxt.break_ty = merged_type;
270 ctxt.may_break = true;
271 } else {
272 self.push_diagnostic(InferenceDiagnostic::BreakOutsideOfLoop {
273 expr: tgt_expr,
274 });
188 } 275 }
276
189 Ty::simple(TypeCtor::Never) 277 Ty::simple(TypeCtor::Never)
190 } 278 }
191 Expr::Return { expr } => { 279 Expr::Return { expr } => {
@@ -281,19 +369,28 @@ impl<'a> InferenceContext<'a> {
281 // FIXME check the cast... 369 // FIXME check the cast...
282 cast_ty 370 cast_ty
283 } 371 }
284 Expr::Ref { expr, mutability } => { 372 Expr::Ref { expr, rawness, mutability } => {
285 let expectation = 373 let expectation = if let Some((exp_inner, exp_rawness, exp_mutability)) =
286 if let Some((exp_inner, exp_mutability)) = &expected.ty.as_reference() { 374 &expected.ty.as_reference_or_ptr()
287 if *exp_mutability == Mutability::Mut && *mutability == Mutability::Shared { 375 {
288 // FIXME: throw type error - expected mut reference but found shared ref, 376 if *exp_mutability == Mutability::Mut && *mutability == Mutability::Shared {
289 // which cannot be coerced 377 // FIXME: throw type error - expected mut reference but found shared ref,
290 } 378 // which cannot be coerced
291 Expectation::rvalue_hint(Ty::clone(exp_inner)) 379 }
292 } else { 380 if *exp_rawness == Rawness::Ref && *rawness == Rawness::RawPtr {
293 Expectation::none() 381 // FIXME: throw type error - expected reference but found ptr,
294 }; 382 // which cannot be coerced
383 }
384 Expectation::rvalue_hint(Ty::clone(exp_inner))
385 } else {
386 Expectation::none()
387 };
295 let inner_ty = self.infer_expr_inner(*expr, &expectation); 388 let inner_ty = self.infer_expr_inner(*expr, &expectation);
296 Ty::apply_one(TypeCtor::Ref(*mutability), inner_ty) 389 let ty = match rawness {
390 Rawness::RawPtr => TypeCtor::RawPtr(*mutability),
391 Rawness::Ref => TypeCtor::Ref(*mutability),
392 };
393 Ty::apply_one(ty, inner_ty)
297 } 394 }
298 Expr::Box { expr } => { 395 Expr::Box { expr } => {
299 let inner_ty = self.infer_expr_inner(*expr, &Expectation::none()); 396 let inner_ty = self.infer_expr_inner(*expr, &Expectation::none());
@@ -496,8 +593,8 @@ impl<'a> InferenceContext<'a> {
496 } 593 }
497 Literal::ByteString(..) => { 594 Literal::ByteString(..) => {
498 let byte_type = Ty::simple(TypeCtor::Int(Uncertain::Known(IntTy::u8()))); 595 let byte_type = Ty::simple(TypeCtor::Int(Uncertain::Known(IntTy::u8())));
499 let slice_type = Ty::apply_one(TypeCtor::Slice, byte_type); 596 let array_type = Ty::apply_one(TypeCtor::Array, byte_type);
500 Ty::apply_one(TypeCtor::Ref(Mutability::Shared), slice_type) 597 Ty::apply_one(TypeCtor::Ref(Mutability::Shared), array_type)
501 } 598 }
502 Literal::Char(..) => Ty::simple(TypeCtor::Char), 599 Literal::Char(..) => Ty::simple(TypeCtor::Char),
503 Literal::Int(_v, ty) => Ty::simple(TypeCtor::Int((*ty).into())), 600 Literal::Int(_v, ty) => Ty::simple(TypeCtor::Int((*ty).into())),
@@ -517,7 +614,6 @@ impl<'a> InferenceContext<'a> {
517 tail: Option<ExprId>, 614 tail: Option<ExprId>,
518 expected: &Expectation, 615 expected: &Expectation,
519 ) -> Ty { 616 ) -> Ty {
520 let mut diverges = false;
521 for stmt in statements { 617 for stmt in statements {
522 match stmt { 618 match stmt {
523 Statement::Let { pat, type_ref, initializer } => { 619 Statement::Let { pat, type_ref, initializer } => {
@@ -539,9 +635,7 @@ impl<'a> InferenceContext<'a> {
539 self.infer_pat(*pat, &ty, BindingMode::default()); 635 self.infer_pat(*pat, &ty, BindingMode::default());
540 } 636 }
541 Statement::Expr(expr) => { 637 Statement::Expr(expr) => {
542 if let ty_app!(TypeCtor::Never) = self.infer_expr(*expr, &Expectation::none()) { 638 self.infer_expr(*expr, &Expectation::none());
543 diverges = true;
544 }
545 } 639 }
546 } 640 }
547 } 641 }
@@ -549,14 +643,22 @@ impl<'a> InferenceContext<'a> {
549 let ty = if let Some(expr) = tail { 643 let ty = if let Some(expr) = tail {
550 self.infer_expr_coerce(expr, expected) 644 self.infer_expr_coerce(expr, expected)
551 } else { 645 } else {
552 self.coerce(&Ty::unit(), expected.coercion_target()); 646 // Citing rustc: if there is no explicit tail expression,
553 Ty::unit() 647 // that is typically equivalent to a tail expression
648 // of `()` -- except if the block diverges. In that
649 // case, there is no value supplied from the tail
650 // expression (assuming there are no other breaks,
651 // this implies that the type of the block will be
652 // `!`).
653 if self.diverges.is_always() {
654 // we don't even make an attempt at coercion
655 self.table.new_maybe_never_type_var()
656 } else {
657 self.coerce(&Ty::unit(), expected.coercion_target());
658 Ty::unit()
659 }
554 }; 660 };
555 if diverges { 661 ty
556 Ty::simple(TypeCtor::Never)
557 } else {
558 ty
559 }
560 } 662 }
561 663
562 fn infer_method_call( 664 fn infer_method_call(
diff --git a/crates/ra_hir_ty/src/infer/pat.rs b/crates/ra_hir_ty/src/infer/pat.rs
index 54ec870df..4006f595d 100644
--- a/crates/ra_hir_ty/src/infer/pat.rs
+++ b/crates/ra_hir_ty/src/infer/pat.rs
@@ -10,7 +10,7 @@ use hir_def::{
10 FieldId, 10 FieldId,
11}; 11};
12use hir_expand::name::Name; 12use hir_expand::name::Name;
13use test_utils::tested_by; 13use test_utils::mark;
14 14
15use super::{BindingMode, Expectation, InferenceContext}; 15use super::{BindingMode, Expectation, InferenceContext};
16use crate::{utils::variant_data, Substs, Ty, TypeCtor}; 16use crate::{utils::variant_data, Substs, Ty, TypeCtor};
@@ -111,7 +111,7 @@ impl<'a> InferenceContext<'a> {
111 } 111 }
112 } 112 }
113 } else if let Pat::Ref { .. } = &body[pat] { 113 } else if let Pat::Ref { .. } = &body[pat] {
114 tested_by!(match_ergonomics_ref); 114 mark::hit!(match_ergonomics_ref);
115 // When you encounter a `&pat` pattern, reset to Move. 115 // When you encounter a `&pat` pattern, reset to Move.
116 // This is so that `w` is by value: `let (_, &w) = &(1, &2);` 116 // This is so that `w` is by value: `let (_, &w) = &(1, &2);`
117 default_bm = BindingMode::Move; 117 default_bm = BindingMode::Move;
diff --git a/crates/ra_hir_ty/src/infer/path.rs b/crates/ra_hir_ty/src/infer/path.rs
index 2b6bc0f79..1c2e56fb0 100644
--- a/crates/ra_hir_ty/src/infer/path.rs
+++ b/crates/ra_hir_ty/src/infer/path.rs
@@ -5,7 +5,7 @@ use std::iter;
5use hir_def::{ 5use hir_def::{
6 path::{Path, PathSegment}, 6 path::{Path, PathSegment},
7 resolver::{ResolveValueResult, Resolver, TypeNs, ValueNs}, 7 resolver::{ResolveValueResult, Resolver, TypeNs, ValueNs},
8 AssocContainerId, AssocItemId, Lookup, 8 AdtId, AssocContainerId, AssocItemId, EnumVariantId, Lookup,
9}; 9};
10use hir_expand::name::Name; 10use hir_expand::name::Name;
11 11
@@ -77,6 +77,18 @@ impl<'a> InferenceContext<'a> {
77 77
78 it.into() 78 it.into()
79 } 79 }
80 ValueNs::ImplSelf(impl_id) => {
81 let generics = crate::utils::generics(self.db.upcast(), impl_id.into());
82 let substs = Substs::type_params_for_generics(&generics);
83 let ty = self.db.impl_self_ty(impl_id).subst(&substs);
84 if let Some((AdtId::StructId(struct_id), _)) = ty.as_adt() {
85 let ty = self.db.value_ty(struct_id.into()).subst(&substs);
86 return Some(ty);
87 } else {
88 // FIXME: diagnostic, invalid Self reference
89 return None;
90 }
91 }
80 }; 92 };
81 93
82 let ty = self.db.value_ty(typable); 94 let ty = self.db.value_ty(typable);
@@ -199,6 +211,10 @@ impl<'a> InferenceContext<'a> {
199 return None; 211 return None;
200 } 212 }
201 213
214 if let Some(result) = self.resolve_enum_variant_on_ty(&ty, name, id) {
215 return Some(result);
216 }
217
202 let canonical_ty = self.canonicalizer().canonicalize_ty(ty.clone()); 218 let canonical_ty = self.canonicalizer().canonicalize_ty(ty.clone());
203 let krate = self.resolver.krate()?; 219 let krate = self.resolver.krate()?;
204 let traits_in_scope = self.resolver.traits_in_scope(self.db.upcast()); 220 let traits_in_scope = self.resolver.traits_in_scope(self.db.upcast());
@@ -250,4 +266,21 @@ impl<'a> InferenceContext<'a> {
250 }, 266 },
251 ) 267 )
252 } 268 }
269
270 fn resolve_enum_variant_on_ty(
271 &mut self,
272 ty: &Ty,
273 name: &Name,
274 id: ExprOrPatId,
275 ) -> Option<(ValueNs, Option<Substs>)> {
276 let (enum_id, subst) = match ty.as_adt() {
277 Some((AdtId::EnumId(e), subst)) => (e, subst),
278 _ => return None,
279 };
280 let enum_data = self.db.enum_data(enum_id);
281 let local_id = enum_data.variant(name)?;
282 let variant = EnumVariantId { parent: enum_id, local_id };
283 self.write_variant_resolution(id, variant.into());
284 Some((ValueNs::EnumVariantId(variant), Some(subst.clone())))
285 }
253} 286}
diff --git a/crates/ra_hir_ty/src/infer/unify.rs b/crates/ra_hir_ty/src/infer/unify.rs
index ab0bc8b70..269495ca0 100644
--- a/crates/ra_hir_ty/src/infer/unify.rs
+++ b/crates/ra_hir_ty/src/infer/unify.rs
@@ -4,7 +4,7 @@ use std::borrow::Cow;
4 4
5use ena::unify::{InPlaceUnificationTable, NoError, UnifyKey, UnifyValue}; 5use ena::unify::{InPlaceUnificationTable, NoError, UnifyKey, UnifyValue};
6 6
7use test_utils::tested_by; 7use test_utils::mark;
8 8
9use super::{InferenceContext, Obligation}; 9use super::{InferenceContext, Obligation};
10use crate::{ 10use crate::{
@@ -313,7 +313,7 @@ impl InferenceTable {
313 // more than once 313 // more than once
314 for i in 0..3 { 314 for i in 0..3 {
315 if i > 0 { 315 if i > 0 {
316 tested_by!(type_var_resolves_to_int_var); 316 mark::hit!(type_var_resolves_to_int_var);
317 } 317 }
318 match &*ty { 318 match &*ty {
319 Ty::Infer(tv) => { 319 Ty::Infer(tv) => {
@@ -342,7 +342,7 @@ impl InferenceTable {
342 Ty::Infer(tv) => { 342 Ty::Infer(tv) => {
343 let inner = tv.to_inner(); 343 let inner = tv.to_inner();
344 if tv_stack.contains(&inner) { 344 if tv_stack.contains(&inner) {
345 tested_by!(type_var_cycles_resolve_as_possible); 345 mark::hit!(type_var_cycles_resolve_as_possible);
346 // recursive type 346 // recursive type
347 return tv.fallback_value(); 347 return tv.fallback_value();
348 } 348 }
@@ -369,7 +369,7 @@ impl InferenceTable {
369 Ty::Infer(tv) => { 369 Ty::Infer(tv) => {
370 let inner = tv.to_inner(); 370 let inner = tv.to_inner();
371 if tv_stack.contains(&inner) { 371 if tv_stack.contains(&inner) {
372 tested_by!(type_var_cycles_resolve_completely); 372 mark::hit!(type_var_cycles_resolve_completely);
373 // recursive type 373 // recursive type
374 return tv.fallback_value(); 374 return tv.fallback_value();
375 } 375 }
diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs
index a6f56c661..9fa8d3bdc 100644
--- a/crates/ra_hir_ty/src/lib.rs
+++ b/crates/ra_hir_ty/src/lib.rs
@@ -42,7 +42,6 @@ pub mod expr;
42mod tests; 42mod tests;
43#[cfg(test)] 43#[cfg(test)]
44mod test_db; 44mod test_db;
45mod marks;
46mod _match; 45mod _match;
47 46
48use std::ops::Deref; 47use std::ops::Deref;
@@ -50,8 +49,10 @@ use std::sync::Arc;
50use std::{iter, mem}; 49use std::{iter, mem};
51 50
52use hir_def::{ 51use hir_def::{
53 expr::ExprId, type_ref::Mutability, AdtId, AssocContainerId, DefWithBodyId, GenericDefId, 52 expr::ExprId,
54 HasModule, Lookup, TraitId, TypeAliasId, TypeParamId, 53 type_ref::{Mutability, Rawness},
54 AdtId, AssocContainerId, DefWithBodyId, GenericDefId, HasModule, Lookup, TraitId, TypeAliasId,
55 TypeParamId,
55}; 56};
56use ra_db::{impl_intern_key, salsa, CrateId}; 57use ra_db::{impl_intern_key, salsa, CrateId};
57 58
@@ -156,10 +157,16 @@ pub enum TypeCtor {
156/// This exists just for Chalk, because Chalk just has a single `StructId` where 157/// This exists just for Chalk, because Chalk just has a single `StructId` where
157/// we have different kinds of ADTs, primitive types and special type 158/// we have different kinds of ADTs, primitive types and special type
158/// constructors like tuples and function pointers. 159/// constructors like tuples and function pointers.
159#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 160#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
160pub struct TypeCtorId(salsa::InternId); 161pub struct TypeCtorId(salsa::InternId);
161impl_intern_key!(TypeCtorId); 162impl_intern_key!(TypeCtorId);
162 163
164/// This exists just for Chalk, because Chalk just has a single `FnDefId` where
165/// we have different IDs for struct and enum variant constructors.
166#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
167pub struct CallableDefId(salsa::InternId);
168impl_intern_key!(CallableDefId);
169
163impl TypeCtor { 170impl TypeCtor {
164 pub fn num_ty_params(self, db: &dyn HirDatabase) -> usize { 171 pub fn num_ty_params(self, db: &dyn HirDatabase) -> usize {
165 match self { 172 match self {
@@ -427,6 +434,11 @@ impl Substs {
427 } 434 }
428} 435}
429 436
437/// Return an index of a parameter in the generic type parameter list by it's id.
438pub fn param_idx(db: &dyn HirDatabase, id: TypeParamId) -> Option<usize> {
439 generics(db.upcast(), id.parent).param_idx(id)
440}
441
430#[derive(Debug, Clone)] 442#[derive(Debug, Clone)]
431pub struct SubstsBuilder { 443pub struct SubstsBuilder {
432 vec: Vec<Ty>, 444 vec: Vec<Ty>,
@@ -683,6 +695,12 @@ impl Ty {
683 pub fn unit() -> Self { 695 pub fn unit() -> Self {
684 Ty::apply(TypeCtor::Tuple { cardinality: 0 }, Substs::empty()) 696 Ty::apply(TypeCtor::Tuple { cardinality: 0 }, Substs::empty())
685 } 697 }
698 pub fn fn_ptr(sig: FnSig) -> Self {
699 Ty::apply(
700 TypeCtor::FnPtr { num_args: sig.params().len() as u16 },
701 Substs(sig.params_and_return),
702 )
703 }
686 704
687 pub fn as_reference(&self) -> Option<(&Ty, Mutability)> { 705 pub fn as_reference(&self) -> Option<(&Ty, Mutability)> {
688 match self { 706 match self {
@@ -693,6 +711,18 @@ impl Ty {
693 } 711 }
694 } 712 }
695 713
714 pub fn as_reference_or_ptr(&self) -> Option<(&Ty, Rawness, Mutability)> {
715 match self {
716 Ty::Apply(ApplicationTy { ctor: TypeCtor::Ref(mutability), parameters }) => {
717 Some((parameters.as_single(), Rawness::Ref, *mutability))
718 }
719 Ty::Apply(ApplicationTy { ctor: TypeCtor::RawPtr(mutability), parameters }) => {
720 Some((parameters.as_single(), Rawness::RawPtr, *mutability))
721 }
722 _ => None,
723 }
724 }
725
696 pub fn strip_references(&self) -> &Ty { 726 pub fn strip_references(&self) -> &Ty {
697 let mut t: &Ty = self; 727 let mut t: &Ty = self;
698 728
@@ -730,6 +760,10 @@ impl Ty {
730 } 760 }
731 } 761 }
732 762
763 pub fn is_never(&self) -> bool {
764 matches!(self, Ty::Apply(ApplicationTy { ctor: TypeCtor::Never, .. }))
765 }
766
733 /// If this is a `dyn Trait` type, this returns the `Trait` part. 767 /// If this is a `dyn Trait` type, this returns the `Trait` part.
734 pub fn dyn_trait_ref(&self) -> Option<&TraitRef> { 768 pub fn dyn_trait_ref(&self) -> Option<&TraitRef> {
735 match self { 769 match self {
@@ -793,15 +827,13 @@ impl Ty {
793 } 827 }
794 } 828 }
795 829
796 /// If this is an `impl Trait` or `dyn Trait`, returns that trait. 830 /// If this is a `dyn Trait`, returns that trait.
797 pub fn inherent_trait(&self) -> Option<TraitId> { 831 pub fn dyn_trait(&self) -> Option<TraitId> {
798 match self { 832 match self {
799 Ty::Dyn(predicates) | Ty::Opaque(predicates) => { 833 Ty::Dyn(predicates) => predicates.iter().find_map(|pred| match pred {
800 predicates.iter().find_map(|pred| match pred { 834 GenericPredicate::Implemented(tr) => Some(tr.trait_),
801 GenericPredicate::Implemented(tr) => Some(tr.trait_), 835 _ => None,
802 _ => None, 836 }),
803 })
804 }
805 _ => None, 837 _ => None,
806 } 838 }
807 } 839 }
diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs
index 9ad6dbe07..35ac86a46 100644
--- a/crates/ra_hir_ty/src/lower.rs
+++ b/crates/ra_hir_ty/src/lower.rs
@@ -812,7 +812,7 @@ impl TraitEnvironment {
812 // add `Self: Trait<T1, T2, ...>` to the environment in trait 812 // add `Self: Trait<T1, T2, ...>` to the environment in trait
813 // function default implementations (and hypothetical code 813 // function default implementations (and hypothetical code
814 // inside consts or type aliases) 814 // inside consts or type aliases)
815 test_utils::tested_by!(trait_self_implements_self); 815 test_utils::mark::hit!(trait_self_implements_self);
816 let substs = Substs::type_params(db, trait_id); 816 let substs = Substs::type_params(db, trait_id);
817 let trait_ref = TraitRef { trait_: trait_id, substs }; 817 let trait_ref = TraitRef { trait_: trait_id, substs };
818 let pred = GenericPredicate::Implemented(trait_ref); 818 let pred = GenericPredicate::Implemented(trait_ref);
diff --git a/crates/ra_hir_ty/src/marks.rs b/crates/ra_hir_ty/src/marks.rs
deleted file mode 100644
index de5cb1d6b..000000000
--- a/crates/ra_hir_ty/src/marks.rs
+++ /dev/null
@@ -1,11 +0,0 @@
1//! See test_utils/src/marks.rs
2
3test_utils::marks!(
4 type_var_cycles_resolve_completely
5 type_var_cycles_resolve_as_possible
6 type_var_resolves_to_int_var
7 impl_self_type_match_without_receiver
8 match_ergonomics_ref
9 coerce_merge_fail_fallback
10 trait_self_implements_self
11);
diff --git a/crates/ra_hir_ty/src/method_resolution.rs b/crates/ra_hir_ty/src/method_resolution.rs
index 657284fd0..e19628fdf 100644
--- a/crates/ra_hir_ty/src/method_resolution.rs
+++ b/crates/ra_hir_ty/src/method_resolution.rs
@@ -408,8 +408,9 @@ fn iterate_trait_method_candidates<T>(
408 receiver_ty: Option<&Canonical<Ty>>, 408 receiver_ty: Option<&Canonical<Ty>>,
409 mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>, 409 mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>,
410) -> Option<T> { 410) -> Option<T> {
411 // if ty is `impl Trait` or `dyn Trait`, the trait doesn't need to be in scope 411 // if ty is `dyn Trait`, the trait doesn't need to be in scope
412 let inherent_trait = self_ty.value.inherent_trait().into_iter(); 412 let inherent_trait =
413 self_ty.value.dyn_trait().into_iter().flat_map(|t| all_super_traits(db.upcast(), t));
413 let env_traits = if let Ty::Placeholder(_) = self_ty.value { 414 let env_traits = if let Ty::Placeholder(_) = self_ty.value {
414 // if we have `T: Trait` in the param env, the trait doesn't need to be in scope 415 // if we have `T: Trait` in the param env, the trait doesn't need to be in scope
415 env.trait_predicates_for_self_ty(&self_ty.value) 416 env.trait_predicates_for_self_ty(&self_ty.value)
@@ -468,7 +469,7 @@ fn iterate_inherent_methods<T>(
468 // already happens in `is_valid_candidate` above; if not, we 469 // already happens in `is_valid_candidate` above; if not, we
469 // check it here 470 // check it here
470 if receiver_ty.is_none() && inherent_impl_substs(db, impl_def, self_ty).is_none() { 471 if receiver_ty.is_none() && inherent_impl_substs(db, impl_def, self_ty).is_none() {
471 test_utils::tested_by!(impl_self_type_match_without_receiver); 472 test_utils::mark::hit!(impl_self_type_match_without_receiver);
472 continue; 473 continue;
473 } 474 }
474 if let Some(result) = callback(&self_ty.value, item) { 475 if let Some(result) = callback(&self_ty.value, item) {
@@ -601,11 +602,6 @@ pub fn implements_trait(
601 krate: CrateId, 602 krate: CrateId,
602 trait_: TraitId, 603 trait_: TraitId,
603) -> bool { 604) -> bool {
604 if ty.value.inherent_trait() == Some(trait_) {
605 // FIXME this is a bit of a hack, since Chalk should say the same thing
606 // anyway, but currently Chalk doesn't implement `dyn/impl Trait` yet
607 return true;
608 }
609 let goal = generic_implements_goal(db, env, trait_, ty.clone()); 605 let goal = generic_implements_goal(db, env, trait_, ty.clone());
610 let solution = db.trait_solve(krate, goal); 606 let solution = db.trait_solve(krate, goal);
611 607
diff --git a/crates/ra_hir_ty/src/op.rs b/crates/ra_hir_ty/src/op.rs
index 54e2bd05a..0870874fc 100644
--- a/crates/ra_hir_ty/src/op.rs
+++ b/crates/ra_hir_ty/src/op.rs
@@ -30,7 +30,8 @@ pub(super) fn binary_op_return_ty(op: BinaryOp, lhs_ty: Ty, rhs_ty: Ty) -> Ty {
30pub(super) fn binary_op_rhs_expectation(op: BinaryOp, lhs_ty: Ty) -> Ty { 30pub(super) fn binary_op_rhs_expectation(op: BinaryOp, lhs_ty: Ty) -> Ty {
31 match op { 31 match op {
32 BinaryOp::LogicOp(..) => Ty::simple(TypeCtor::Bool), 32 BinaryOp::LogicOp(..) => Ty::simple(TypeCtor::Bool),
33 BinaryOp::Assignment { op: None } | BinaryOp::CmpOp(CmpOp::Eq { .. }) => match lhs_ty { 33 BinaryOp::Assignment { op: None } => lhs_ty,
34 BinaryOp::CmpOp(CmpOp::Eq { .. }) => match lhs_ty {
34 Ty::Apply(ApplicationTy { ctor, .. }) => match ctor { 35 Ty::Apply(ApplicationTy { ctor, .. }) => match ctor {
35 TypeCtor::Int(..) 36 TypeCtor::Int(..)
36 | TypeCtor::Float(..) 37 | TypeCtor::Float(..)
diff --git a/crates/ra_hir_ty/src/tests.rs b/crates/ra_hir_ty/src/tests.rs
index 588d81282..1fe05c70c 100644
--- a/crates/ra_hir_ty/src/tests.rs
+++ b/crates/ra_hir_ty/src/tests.rs
@@ -6,6 +6,7 @@ mod patterns;
6mod traits; 6mod traits;
7mod method_resolution; 7mod method_resolution;
8mod macros; 8mod macros;
9mod display_source_code;
9 10
10use std::sync::Arc; 11use std::sync::Arc;
11 12
@@ -16,7 +17,7 @@ use hir_def::{
16 item_scope::ItemScope, 17 item_scope::ItemScope,
17 keys, 18 keys,
18 nameres::CrateDefMap, 19 nameres::CrateDefMap,
19 AssocItemId, DefWithBodyId, LocalModuleId, Lookup, ModuleDefId, 20 AssocItemId, DefWithBodyId, LocalModuleId, Lookup, ModuleDefId, ModuleId,
20}; 21};
21use hir_expand::{db::AstDatabase, InFile}; 22use hir_expand::{db::AstDatabase, InFile};
22use insta::assert_snapshot; 23use insta::assert_snapshot;
@@ -37,6 +38,18 @@ use crate::{
37// update the snapshots. 38// update the snapshots.
38 39
39fn type_at_pos(db: &TestDB, pos: FilePosition) -> String { 40fn type_at_pos(db: &TestDB, pos: FilePosition) -> String {
41 type_at_pos_displayed(db, pos, |ty, _| ty.display(db).to_string())
42}
43
44fn displayed_source_at_pos(db: &TestDB, pos: FilePosition) -> String {
45 type_at_pos_displayed(db, pos, |ty, module_id| ty.display_source_code(db, module_id).unwrap())
46}
47
48fn type_at_pos_displayed(
49 db: &TestDB,
50 pos: FilePosition,
51 display_fn: impl FnOnce(&Ty, ModuleId) -> String,
52) -> String {
40 let file = db.parse(pos.file_id).ok().unwrap(); 53 let file = db.parse(pos.file_id).ok().unwrap();
41 let expr = algo::find_node_at_offset::<ast::Expr>(file.syntax(), pos.offset).unwrap(); 54 let expr = algo::find_node_at_offset::<ast::Expr>(file.syntax(), pos.offset).unwrap();
42 let fn_def = expr.syntax().ancestors().find_map(ast::FnDef::cast).unwrap(); 55 let fn_def = expr.syntax().ancestors().find_map(ast::FnDef::cast).unwrap();
@@ -49,7 +62,7 @@ fn type_at_pos(db: &TestDB, pos: FilePosition) -> String {
49 if let Some(expr_id) = source_map.node_expr(InFile::new(pos.file_id.into(), &expr)) { 62 if let Some(expr_id) = source_map.node_expr(InFile::new(pos.file_id.into(), &expr)) {
50 let infer = db.infer(func.into()); 63 let infer = db.infer(func.into());
51 let ty = &infer[expr_id]; 64 let ty = &infer[expr_id];
52 return ty.display(db).to_string(); 65 return display_fn(ty, module);
53 } 66 }
54 panic!("Can't find expression") 67 panic!("Can't find expression")
55} 68}
@@ -361,6 +374,33 @@ fn no_such_field_with_feature_flag_diagnostics() {
361} 374}
362 375
363#[test] 376#[test]
377fn no_such_field_enum_with_feature_flag_diagnostics() {
378 let diagnostics = TestDB::with_files(
379 r#"
380 //- /lib.rs crate:foo cfg:feature=foo
381 enum Foo {
382 #[cfg(not(feature = "foo"))]
383 Buz,
384 #[cfg(feature = "foo")]
385 Bar,
386 Baz
387 }
388
389 fn test_fn(f: Foo) {
390 match f {
391 Foo::Bar => {},
392 Foo::Baz => {},
393 }
394 }
395 "#,
396 )
397 .diagnostics()
398 .0;
399
400 assert_snapshot!(diagnostics, @r###""###);
401}
402
403#[test]
364fn no_such_field_with_feature_flag_diagnostics_on_struct_lit() { 404fn no_such_field_with_feature_flag_diagnostics_on_struct_lit() {
365 let diagnostics = TestDB::with_files( 405 let diagnostics = TestDB::with_files(
366 r#" 406 r#"
@@ -491,3 +531,21 @@ fn missing_record_pat_field_no_diagnostic_if_not_exhaustive() {
491 531
492 assert_snapshot!(diagnostics, @""); 532 assert_snapshot!(diagnostics, @"");
493} 533}
534
535#[test]
536fn break_outside_of_loop() {
537 let diagnostics = TestDB::with_files(
538 r"
539 //- /lib.rs
540 fn foo() {
541 break;
542 }
543 ",
544 )
545 .diagnostics()
546 .0;
547
548 assert_snapshot!(diagnostics, @r###""break": break outside of loop
549 "###
550 );
551}
diff --git a/crates/ra_hir_ty/src/tests/coercion.rs b/crates/ra_hir_ty/src/tests/coercion.rs
index e6fb3e123..6f777ed8c 100644
--- a/crates/ra_hir_ty/src/tests/coercion.rs
+++ b/crates/ra_hir_ty/src/tests/coercion.rs
@@ -1,6 +1,6 @@
1use super::infer_with_mismatches; 1use super::infer_with_mismatches;
2use insta::assert_snapshot; 2use insta::assert_snapshot;
3use test_utils::covers; 3use test_utils::mark;
4 4
5// Infer with some common definitions and impls. 5// Infer with some common definitions and impls.
6fn infer(source: &str) -> String { 6fn infer(source: &str) -> String {
@@ -116,15 +116,20 @@ fn infer_let_stmt_coerce() {
116 assert_snapshot!( 116 assert_snapshot!(
117 infer(r#" 117 infer(r#"
118fn test() { 118fn test() {
119 let x: &[i32] = &[1]; 119 let x: &[isize] = &[1];
120 let x: *const [isize] = &[1];
120} 121}
121"#), 122"#),
122 @r###" 123 @r###"
123 11..40 '{ ...[1]; }': () 124 11..76 '{ ...[1]; }': ()
124 21..22 'x': &[i32] 125 21..22 'x': &[isize]
125 33..37 '&[1]': &[i32; _] 126 35..39 '&[1]': &[isize; _]
126 34..37 '[1]': [i32; _] 127 36..39 '[1]': [isize; _]
127 35..36 '1': i32 128 37..38 '1': isize
129 49..50 'x': *const [isize]
130 69..73 '&[1]': &[isize; _]
131 70..73 '[1]': [isize; _]
132 71..72 '1': isize
128 "###); 133 "###);
129} 134}
130 135
@@ -339,7 +344,7 @@ fn test(i: i32) {
339 344
340#[test] 345#[test]
341fn coerce_merge_one_by_one1() { 346fn coerce_merge_one_by_one1() {
342 covers!(coerce_merge_fail_fallback); 347 mark::check!(coerce_merge_fail_fallback);
343 348
344 assert_snapshot!( 349 assert_snapshot!(
345 infer(r#" 350 infer(r#"
@@ -384,7 +389,7 @@ fn foo() -> u32 {
384} 389}
385"#, true), 390"#, true),
386 @r###" 391 @r###"
387 17..40 '{ ...own; }': ! 392 17..40 '{ ...own; }': u32
388 23..37 'return unknown': ! 393 23..37 'return unknown': !
389 30..37 'unknown': u32 394 30..37 'unknown': u32
390 "### 395 "###
@@ -514,7 +519,7 @@ fn foo() {
514 27..103 '{ ... }': &u32 519 27..103 '{ ... }': &u32
515 37..82 'if tru... }': () 520 37..82 'if tru... }': ()
516 40..44 'true': bool 521 40..44 'true': bool
517 45..82 '{ ... }': ! 522 45..82 '{ ... }': ()
518 59..71 'return &1u32': ! 523 59..71 'return &1u32': !
519 66..71 '&1u32': &u32 524 66..71 '&1u32': &u32
520 67..71 '1u32': u32 525 67..71 '1u32': u32
@@ -546,6 +551,48 @@ fn test() {
546} 551}
547 552
548#[test] 553#[test]
554fn coerce_fn_items_in_match_arms() {
555 mark::check!(coerce_fn_reification);
556 assert_snapshot!(
557 infer_with_mismatches(r#"
558fn foo1(x: u32) -> isize { 1 }
559fn foo2(x: u32) -> isize { 2 }
560fn foo3(x: u32) -> isize { 3 }
561fn test() {
562 let x = match 1 {
563 1 => foo1,
564 2 => foo2,
565 _ => foo3,
566 };
567}
568"#, true),
569 @r###"
570 9..10 'x': u32
571 26..31 '{ 1 }': isize
572 28..29 '1': isize
573 40..41 'x': u32
574 57..62 '{ 2 }': isize
575 59..60 '2': isize
576 71..72 'x': u32
577 88..93 '{ 3 }': isize
578 90..91 '3': isize
579 104..193 '{ ... }; }': ()
580 114..115 'x': fn(u32) -> isize
581 118..190 'match ... }': fn(u32) -> isize
582 124..125 '1': i32
583 136..137 '1': i32
584 136..137 '1': i32
585 141..145 'foo1': fn foo1(u32) -> isize
586 155..156 '2': i32
587 155..156 '2': i32
588 160..164 'foo2': fn foo2(u32) -> isize
589 174..175 '_': i32
590 179..183 'foo3': fn foo3(u32) -> isize
591 "###
592 );
593}
594
595#[test]
549fn coerce_closure_to_fn_ptr() { 596fn coerce_closure_to_fn_ptr() {
550 assert_snapshot!( 597 assert_snapshot!(
551 infer_with_mismatches(r#" 598 infer_with_mismatches(r#"
diff --git a/crates/ra_hir_ty/src/tests/display_source_code.rs b/crates/ra_hir_ty/src/tests/display_source_code.rs
new file mode 100644
index 000000000..4088b1d22
--- /dev/null
+++ b/crates/ra_hir_ty/src/tests/display_source_code.rs
@@ -0,0 +1,50 @@
1use super::displayed_source_at_pos;
2use crate::test_db::TestDB;
3use ra_db::fixture::WithFixture;
4
5#[test]
6fn qualify_path_to_submodule() {
7 let (db, pos) = TestDB::with_position(
8 r#"
9//- /main.rs
10
11mod foo {
12 pub struct Foo;
13}
14
15fn bar() {
16 let foo: foo::Foo = foo::Foo;
17 foo<|>
18}
19
20"#,
21 );
22 assert_eq!("foo::Foo", displayed_source_at_pos(&db, pos));
23}
24
25#[test]
26fn omit_default_type_parameters() {
27 let (db, pos) = TestDB::with_position(
28 r"
29 //- /main.rs
30 struct Foo<T = u8> { t: T }
31 fn main() {
32 let foo = Foo { t: 5 };
33 foo<|>;
34 }
35 ",
36 );
37 assert_eq!("Foo", displayed_source_at_pos(&db, pos));
38
39 let (db, pos) = TestDB::with_position(
40 r"
41 //- /main.rs
42 struct Foo<K, T = u8> { k: K, t: T }
43 fn main() {
44 let foo = Foo { k: 400, t: 5 };
45 foo<|>;
46 }
47 ",
48 );
49 assert_eq!("Foo<i32>", displayed_source_at_pos(&db, pos));
50}
diff --git a/crates/ra_hir_ty/src/tests/macros.rs b/crates/ra_hir_ty/src/tests/macros.rs
index 5ddecbdc6..4c6099aa2 100644
--- a/crates/ra_hir_ty/src/tests/macros.rs
+++ b/crates/ra_hir_ty/src/tests/macros.rs
@@ -197,7 +197,7 @@ fn spam() {
197 !0..6 '1isize': isize 197 !0..6 '1isize': isize
198 !0..6 '1isize': isize 198 !0..6 '1isize': isize
199 !0..6 '1isize': isize 199 !0..6 '1isize': isize
200 54..457 '{ ...!(); }': ! 200 54..457 '{ ...!(); }': ()
201 88..109 'spam!(...am!())': {unknown} 201 88..109 'spam!(...am!())': {unknown}
202 115..134 'for _ ...!() {}': () 202 115..134 'for _ ...!() {}': ()
203 119..120 '_': {unknown} 203 119..120 '_': {unknown}
@@ -269,7 +269,7 @@ fn test() { S.foo()<|>; }
269} 269}
270 270
271#[test] 271#[test]
272fn infer_impl_items_generated_by_macros() { 272fn infer_assoc_items_generated_by_macros() {
273 let t = type_at( 273 let t = type_at(
274 r#" 274 r#"
275//- /main.rs 275//- /main.rs
@@ -288,7 +288,7 @@ fn test() { S.foo()<|>; }
288} 288}
289 289
290#[test] 290#[test]
291fn infer_impl_items_generated_by_macros_chain() { 291fn infer_assoc_items_generated_by_macros_chain() {
292 let t = type_at( 292 let t = type_at(
293 r#" 293 r#"
294//- /main.rs 294//- /main.rs
@@ -339,6 +339,46 @@ pub fn baz() -> usize { 31usize }
339} 339}
340 340
341#[test] 341#[test]
342fn infer_macro_with_dollar_crate_is_correct_in_trait_associate_type() {
343 let (db, pos) = TestDB::with_position(
344 r#"
345//- /main.rs crate:main deps:foo
346use foo::Trait;
347
348fn test() {
349 let msg = foo::Message(foo::MessageRef);
350 let r = msg.deref();
351 r<|>;
352}
353
354//- /lib.rs crate:foo
355pub struct MessageRef;
356pub struct Message(MessageRef);
357
358pub trait Trait {
359 type Target;
360 fn deref(&self) -> &Self::Target;
361}
362
363#[macro_export]
364macro_rules! expand {
365 () => {
366 impl Trait for Message {
367 type Target = $crate::MessageRef;
368 fn deref(&self) -> &Self::Target {
369 &self.0
370 }
371 }
372 }
373}
374
375expand!();
376"#,
377 );
378 assert_eq!("&MessageRef", type_at_pos(&db, pos));
379}
380
381#[test]
342fn infer_type_value_non_legacy_macro_use_as() { 382fn infer_type_value_non_legacy_macro_use_as() {
343 assert_snapshot!( 383 assert_snapshot!(
344 infer(r#" 384 infer(r#"
@@ -388,6 +428,32 @@ fn main() {
388} 428}
389 429
390#[test] 430#[test]
431fn infer_local_inner_macros() {
432 let (db, pos) = TestDB::with_position(
433 r#"
434//- /main.rs crate:main deps:foo
435fn test() {
436 let x = foo::foo!(1);
437 x<|>;
438}
439
440//- /lib.rs crate:foo
441#[macro_export(local_inner_macros)]
442macro_rules! foo {
443 (1) => { bar!() };
444}
445
446#[macro_export]
447macro_rules! bar {
448 () => { 42 }
449}
450
451"#,
452 );
453 assert_eq!("i32", type_at_pos(&db, pos));
454}
455
456#[test]
391fn infer_builtin_macros_line() { 457fn infer_builtin_macros_line() {
392 assert_snapshot!( 458 assert_snapshot!(
393 infer(r#" 459 infer(r#"
diff --git a/crates/ra_hir_ty/src/tests/method_resolution.rs b/crates/ra_hir_ty/src/tests/method_resolution.rs
index ab87f598a..558a70022 100644
--- a/crates/ra_hir_ty/src/tests/method_resolution.rs
+++ b/crates/ra_hir_ty/src/tests/method_resolution.rs
@@ -17,8 +17,8 @@ impl<T> [T] {
17#[lang = "slice_alloc"] 17#[lang = "slice_alloc"]
18impl<T> [T] {} 18impl<T> [T] {}
19 19
20fn test() { 20fn test(x: &[u8]) {
21 <[_]>::foo(b"foo"); 21 <[_]>::foo(x);
22} 22}
23"#), 23"#),
24 @r###" 24 @r###"
@@ -26,10 +26,11 @@ fn test() {
26 56..79 '{ ... }': T 26 56..79 '{ ... }': T
27 66..73 'loop {}': ! 27 66..73 'loop {}': !
28 71..73 '{}': () 28 71..73 '{}': ()
29 133..160 '{ ...o"); }': () 29 131..132 'x': &[u8]
30 139..149 '<[_]>::foo': fn foo<u8>(&[u8]) -> u8 30 141..163 '{ ...(x); }': ()
31 139..157 '<[_]>:..."foo")': u8 31 147..157 '<[_]>::foo': fn foo<u8>(&[u8]) -> u8
32 150..156 'b"foo"': &[u8] 32 147..160 '<[_]>::foo(x)': u8
33 158..159 'x': &[u8]
33 "### 34 "###
34 ); 35 );
35} 36}
@@ -983,7 +984,7 @@ fn test() { S2.into()<|>; }
983 984
984#[test] 985#[test]
985fn method_resolution_overloaded_method() { 986fn method_resolution_overloaded_method() {
986 test_utils::covers!(impl_self_type_match_without_receiver); 987 test_utils::mark::check!(impl_self_type_match_without_receiver);
987 let t = type_at( 988 let t = type_at(
988 r#" 989 r#"
989//- main.rs 990//- main.rs
@@ -1095,3 +1096,34 @@ fn test() { (S {}).method()<|>; }
1095 ); 1096 );
1096 assert_eq!(t, "()"); 1097 assert_eq!(t, "()");
1097} 1098}
1099
1100#[test]
1101fn dyn_trait_super_trait_not_in_scope() {
1102 assert_snapshot!(
1103 infer(r#"
1104mod m {
1105 pub trait SuperTrait {
1106 fn foo(&self) -> u32 { 0 }
1107 }
1108}
1109trait Trait: m::SuperTrait {}
1110
1111struct S;
1112impl m::SuperTrait for S {}
1113impl Trait for S {}
1114
1115fn test(d: &dyn Trait) {
1116 d.foo();
1117}
1118"#),
1119 @r###"
1120 52..56 'self': &Self
1121 65..70 '{ 0 }': u32
1122 67..68 '0': u32
1123 177..178 'd': &dyn Trait
1124 192..208 '{ ...o(); }': ()
1125 198..199 'd': &dyn Trait
1126 198..205 'd.foo()': u32
1127 "###
1128 );
1129}
diff --git a/crates/ra_hir_ty/src/tests/never_type.rs b/crates/ra_hir_ty/src/tests/never_type.rs
index a77209480..082c47208 100644
--- a/crates/ra_hir_ty/src/tests/never_type.rs
+++ b/crates/ra_hir_ty/src/tests/never_type.rs
@@ -1,4 +1,6 @@
1use super::type_at; 1use insta::assert_snapshot;
2
3use super::{infer_with_mismatches, type_at};
2 4
3#[test] 5#[test]
4fn infer_never1() { 6fn infer_never1() {
@@ -261,3 +263,176 @@ fn test(a: i32) {
261 ); 263 );
262 assert_eq!(t, "f64"); 264 assert_eq!(t, "f64");
263} 265}
266
267#[test]
268fn diverging_expression_1() {
269 let t = infer_with_mismatches(
270 r#"
271//- /main.rs
272fn test1() {
273 let x: u32 = return;
274}
275fn test2() {
276 let x: u32 = { return; };
277}
278fn test3() {
279 let x: u32 = loop {};
280}
281fn test4() {
282 let x: u32 = { loop {} };
283}
284fn test5() {
285 let x: u32 = { if true { loop {}; } else { loop {}; } };
286}
287fn test6() {
288 let x: u32 = { let y: u32 = { loop {}; }; };
289}
290"#,
291 true,
292 );
293 assert_snapshot!(t, @r###"
294 25..53 '{ ...urn; }': ()
295 35..36 'x': u32
296 44..50 'return': !
297 65..98 '{ ...; }; }': ()
298 75..76 'x': u32
299 84..95 '{ return; }': u32
300 86..92 'return': !
301 110..139 '{ ... {}; }': ()
302 120..121 'x': u32
303 129..136 'loop {}': !
304 134..136 '{}': ()
305 151..184 '{ ...} }; }': ()
306 161..162 'x': u32
307 170..181 '{ loop {} }': u32
308 172..179 'loop {}': !
309 177..179 '{}': ()
310 196..260 '{ ...} }; }': ()
311 206..207 'x': u32
312 215..257 '{ if t...}; } }': u32
313 217..255 'if tru... {}; }': u32
314 220..224 'true': bool
315 225..237 '{ loop {}; }': u32
316 227..234 'loop {}': !
317 232..234 '{}': ()
318 243..255 '{ loop {}; }': u32
319 245..252 'loop {}': !
320 250..252 '{}': ()
321 272..324 '{ ...; }; }': ()
322 282..283 'x': u32
323 291..321 '{ let ...; }; }': u32
324 297..298 'y': u32
325 306..318 '{ loop {}; }': u32
326 308..315 'loop {}': !
327 313..315 '{}': ()
328 "###);
329}
330
331#[test]
332fn diverging_expression_2() {
333 let t = infer_with_mismatches(
334 r#"
335//- /main.rs
336fn test1() {
337 // should give type mismatch
338 let x: u32 = { loop {}; "foo" };
339}
340"#,
341 true,
342 );
343 assert_snapshot!(t, @r###"
344 25..98 '{ ..." }; }': ()
345 68..69 'x': u32
346 77..95 '{ loop...foo" }': &str
347 79..86 'loop {}': !
348 84..86 '{}': ()
349 88..93 '"foo"': &str
350 77..95: expected u32, got &str
351 88..93: expected u32, got &str
352 "###);
353}
354
355#[test]
356fn diverging_expression_3_break() {
357 let t = infer_with_mismatches(
358 r#"
359//- /main.rs
360fn test1() {
361 // should give type mismatch
362 let x: u32 = { loop { break; } };
363}
364fn test2() {
365 // should give type mismatch
366 let x: u32 = { for a in b { break; }; };
367 // should give type mismatch as well
368 let x: u32 = { for a in b {}; };
369 // should give type mismatch as well
370 let x: u32 = { for a in b { return; }; };
371}
372fn test3() {
373 // should give type mismatch
374 let x: u32 = { while true { break; }; };
375 // should give type mismatch as well -- there's an implicit break, even if it's never hit
376 let x: u32 = { while true {}; };
377 // should give type mismatch as well
378 let x: u32 = { while true { return; }; };
379}
380"#,
381 true,
382 );
383 assert_snapshot!(t, @r###"
384 25..99 '{ ...} }; }': ()
385 68..69 'x': u32
386 77..96 '{ loop...k; } }': ()
387 79..94 'loop { break; }': ()
388 84..94 '{ break; }': ()
389 86..91 'break': !
390 77..96: expected u32, got ()
391 79..94: expected u32, got ()
392 111..357 '{ ...; }; }': ()
393 154..155 'x': u32
394 163..189 '{ for ...; }; }': ()
395 165..186 'for a ...eak; }': ()
396 169..170 'a': {unknown}
397 174..175 'b': {unknown}
398 176..186 '{ break; }': ()
399 178..183 'break': !
400 240..241 'x': u32
401 249..267 '{ for ... {}; }': ()
402 251..264 'for a in b {}': ()
403 255..256 'a': {unknown}
404 260..261 'b': {unknown}
405 262..264 '{}': ()
406 318..319 'x': u32
407 327..354 '{ for ...; }; }': ()
408 329..351 'for a ...urn; }': ()
409 333..334 'a': {unknown}
410 338..339 'b': {unknown}
411 340..351 '{ return; }': ()
412 342..348 'return': !
413 163..189: expected u32, got ()
414 249..267: expected u32, got ()
415 327..354: expected u32, got ()
416 369..668 '{ ...; }; }': ()
417 412..413 'x': u32
418 421..447 '{ whil...; }; }': ()
419 423..444 'while ...eak; }': ()
420 429..433 'true': bool
421 434..444 '{ break; }': ()
422 436..441 'break': !
423 551..552 'x': u32
424 560..578 '{ whil... {}; }': ()
425 562..575 'while true {}': ()
426 568..572 'true': bool
427 573..575 '{}': ()
428 629..630 'x': u32
429 638..665 '{ whil...; }; }': ()
430 640..662 'while ...urn; }': ()
431 646..650 'true': bool
432 651..662 '{ return; }': ()
433 653..659 'return': !
434 421..447: expected u32, got ()
435 560..578: expected u32, got ()
436 638..665: expected u32, got ()
437 "###);
438}
diff --git a/crates/ra_hir_ty/src/tests/patterns.rs b/crates/ra_hir_ty/src/tests/patterns.rs
index af291092d..fe62587c0 100644
--- a/crates/ra_hir_ty/src/tests/patterns.rs
+++ b/crates/ra_hir_ty/src/tests/patterns.rs
@@ -1,5 +1,5 @@
1use insta::assert_snapshot; 1use insta::assert_snapshot;
2use test_utils::covers; 2use test_utils::mark;
3 3
4use super::{infer, infer_with_mismatches}; 4use super::{infer, infer_with_mismatches};
5 5
@@ -197,7 +197,7 @@ fn test() {
197 197
198#[test] 198#[test]
199fn infer_pattern_match_ergonomics_ref() { 199fn infer_pattern_match_ergonomics_ref() {
200 covers!(match_ergonomics_ref); 200 mark::check!(match_ergonomics_ref);
201 assert_snapshot!( 201 assert_snapshot!(
202 infer(r#" 202 infer(r#"
203fn test() { 203fn test() {
@@ -369,6 +369,45 @@ fn test() {
369} 369}
370 370
371#[test] 371#[test]
372fn enum_variant_through_self_in_pattern() {
373 assert_snapshot!(
374 infer(r#"
375enum E {
376 A { x: usize },
377 B(usize),
378 C
379}
380
381impl E {
382 fn test() {
383 match (loop {}) {
384 Self::A { x } => { x; },
385 Self::B(x) => { x; },
386 Self::C => {},
387 };
388 }
389}
390"#),
391 @r###"
392 76..218 '{ ... }': ()
393 86..211 'match ... }': ()
394 93..100 'loop {}': !
395 98..100 '{}': ()
396 116..129 'Self::A { x }': E
397 126..127 'x': usize
398 133..139 '{ x; }': ()
399 135..136 'x': usize
400 153..163 'Self::B(x)': E
401 161..162 'x': usize
402 167..173 '{ x; }': ()
403 169..170 'x': usize
404 187..194 'Self::C': E
405 198..200 '{}': ()
406 "###
407 );
408}
409
410#[test]
372fn infer_generics_in_patterns() { 411fn infer_generics_in_patterns() {
373 assert_snapshot!( 412 assert_snapshot!(
374 infer(r#" 413 infer(r#"
@@ -481,3 +520,53 @@ fn main() {
481 105..107 '()': () 520 105..107 '()': ()
482 ") 521 ")
483} 522}
523
524#[test]
525fn match_ergonomics_in_closure_params() {
526 assert_snapshot!(
527 infer(r#"
528#[lang = "fn_once"]
529trait FnOnce<Args> {
530 type Output;
531}
532
533fn foo<T, U, F: FnOnce(T) -> U>(t: T, f: F) -> U { loop {} }
534
535fn test() {
536 foo(&(1, "a"), |&(x, y)| x); // normal, no match ergonomics
537 foo(&(1, "a"), |(x, y)| x);
538}
539"#),
540 @r###"
541 94..95 't': T
542 100..101 'f': F
543 111..122 '{ loop {} }': U
544 113..120 'loop {}': !
545 118..120 '{}': ()
546 134..233 '{ ... x); }': ()
547 140..143 'foo': fn foo<&(i32, &str), i32, |&(i32, &str)| -> i32>(&(i32, &str), |&(i32, &str)| -> i32) -> i32
548 140..167 'foo(&(...y)| x)': i32
549 144..153 '&(1, "a")': &(i32, &str)
550 145..153 '(1, "a")': (i32, &str)
551 146..147 '1': i32
552 149..152 '"a"': &str
553 155..166 '|&(x, y)| x': |&(i32, &str)| -> i32
554 156..163 '&(x, y)': &(i32, &str)
555 157..163 '(x, y)': (i32, &str)
556 158..159 'x': i32
557 161..162 'y': &str
558 165..166 'x': i32
559 204..207 'foo': fn foo<&(i32, &str), &i32, |&(i32, &str)| -> &i32>(&(i32, &str), |&(i32, &str)| -> &i32) -> &i32
560 204..230 'foo(&(...y)| x)': &i32
561 208..217 '&(1, "a")': &(i32, &str)
562 209..217 '(1, "a")': (i32, &str)
563 210..211 '1': i32
564 213..216 '"a"': &str
565 219..229 '|(x, y)| x': |&(i32, &str)| -> &i32
566 220..226 '(x, y)': (i32, &str)
567 221..222 'x': &i32
568 224..225 'y': &&str
569 228..229 'x': &i32
570 "###
571 );
572}
diff --git a/crates/ra_hir_ty/src/tests/regression.rs b/crates/ra_hir_ty/src/tests/regression.rs
index 8a1292c7a..1f004bd63 100644
--- a/crates/ra_hir_ty/src/tests/regression.rs
+++ b/crates/ra_hir_ty/src/tests/regression.rs
@@ -1,9 +1,10 @@
1use insta::assert_snapshot; 1use insta::assert_snapshot;
2use test_utils::covers; 2use ra_db::fixture::WithFixture;
3use test_utils::mark;
3 4
4use super::infer;
5use crate::test_db::TestDB; 5use crate::test_db::TestDB;
6use ra_db::fixture::WithFixture; 6
7use super::infer;
7 8
8#[test] 9#[test]
9fn bug_484() { 10fn bug_484() {
@@ -89,8 +90,8 @@ fn quux() {
89 90
90#[test] 91#[test]
91fn recursive_vars() { 92fn recursive_vars() {
92 covers!(type_var_cycles_resolve_completely); 93 mark::check!(type_var_cycles_resolve_completely);
93 covers!(type_var_cycles_resolve_as_possible); 94 mark::check!(type_var_cycles_resolve_as_possible);
94 assert_snapshot!( 95 assert_snapshot!(
95 infer(r#" 96 infer(r#"
96fn test() { 97fn test() {
@@ -112,8 +113,6 @@ fn test() {
112 113
113#[test] 114#[test]
114fn recursive_vars_2() { 115fn recursive_vars_2() {
115 covers!(type_var_cycles_resolve_completely);
116 covers!(type_var_cycles_resolve_as_possible);
117 assert_snapshot!( 116 assert_snapshot!(
118 infer(r#" 117 infer(r#"
119fn test() { 118fn test() {
@@ -170,7 +169,7 @@ fn write() {
170 169
171#[test] 170#[test]
172fn infer_std_crash_2() { 171fn infer_std_crash_2() {
173 covers!(type_var_resolves_to_int_var); 172 mark::check!(type_var_resolves_to_int_var);
174 // caused "equating two type variables, ...", taken from std 173 // caused "equating two type variables, ...", taken from std
175 assert_snapshot!( 174 assert_snapshot!(
176 infer(r#" 175 infer(r#"
@@ -535,6 +534,66 @@ fn foo(b: Bar) {
535} 534}
536 535
537#[test] 536#[test]
537fn issue_4235_name_conflicts() {
538 assert_snapshot!(
539 infer(r#"
540struct FOO {}
541static FOO:FOO = FOO {};
542
543impl FOO {
544 fn foo(&self) {}
545}
546
547fn main() {
548 let a = &FOO;
549 a.foo();
550}
551"#), @r###"
552 32..38 'FOO {}': FOO
553 64..68 'self': &FOO
554 70..72 '{}': ()
555 86..120 '{ ...o(); }': ()
556 96..97 'a': &FOO
557 100..104 '&FOO': &FOO
558 101..104 'FOO': FOO
559 110..111 'a': &FOO
560 110..117 'a.foo()': ()
561"###
562 );
563}
564
565#[test]
566fn issue_4465_dollar_crate_at_type() {
567 assert_snapshot!(
568 infer(r#"
569pub struct Foo {}
570pub fn anything<T>() -> T {
571 loop {}
572}
573macro_rules! foo {
574 () => {{
575 let r: $crate::Foo = anything();
576 r
577 }};
578}
579fn main() {
580 let _a = foo!();
581}
582"#), @r###"
583 45..60 '{ loop {} }': T
584 51..58 'loop {}': !
585 56..58 '{}': ()
586 !0..31 '{letr:...g();r}': Foo
587 !4..5 'r': Foo
588 !18..26 'anything': fn anything<Foo>() -> Foo
589 !18..28 'anything()': Foo
590 !29..30 'r': Foo
591 164..188 '{ ...!(); }': ()
592 174..176 '_a': Foo
593"###);
594}
595
596#[test]
538fn issue_4053_diesel_where_clauses() { 597fn issue_4053_diesel_where_clauses() {
539 assert_snapshot!( 598 assert_snapshot!(
540 infer(r#" 599 infer(r#"
diff --git a/crates/ra_hir_ty/src/tests/simple.rs b/crates/ra_hir_ty/src/tests/simple.rs
index 56abc65b8..88309157b 100644
--- a/crates/ra_hir_ty/src/tests/simple.rs
+++ b/crates/ra_hir_ty/src/tests/simple.rs
@@ -179,7 +179,7 @@ fn test(a: u32, b: isize, c: !, d: &str) {
179 17..18 'b': isize 179 17..18 'b': isize
180 27..28 'c': ! 180 27..28 'c': !
181 33..34 'd': &str 181 33..34 'd': &str
182 42..121 '{ ...f32; }': ! 182 42..121 '{ ...f32; }': ()
183 48..49 'a': u32 183 48..49 'a': u32
184 55..56 'b': isize 184 55..56 'b': isize
185 62..63 'c': ! 185 62..63 'c': !
@@ -385,6 +385,26 @@ fn test(a: &u32, b: &mut u32, c: *const u32, d: *mut u32) {
385} 385}
386 386
387#[test] 387#[test]
388fn infer_raw_ref() {
389 assert_snapshot!(
390 infer(r#"
391fn test(a: i32) {
392 &raw mut a;
393 &raw const a;
394}
395"#),
396 @r###"
397 9..10 'a': i32
398 17..54 '{ ...t a; }': ()
399 23..33 '&raw mut a': *mut i32
400 32..33 'a': i32
401 39..51 '&raw const a': *const i32
402 50..51 'a': i32
403 "###
404 );
405}
406
407#[test]
388fn infer_literals() { 408fn infer_literals() {
389 assert_snapshot!( 409 assert_snapshot!(
390 infer(r##" 410 infer(r##"
@@ -414,7 +434,7 @@ fn test() {
414 27..31 '5f32': f32 434 27..31 '5f32': f32
415 37..41 '5f64': f64 435 37..41 '5f64': f64
416 47..54 '"hello"': &str 436 47..54 '"hello"': &str
417 60..68 'b"bytes"': &[u8] 437 60..68 'b"bytes"': &[u8; _]
418 74..77 ''c'': char 438 74..77 ''c'': char
419 83..87 'b'b'': u8 439 83..87 'b'b'': u8
420 93..97 '3.14': f64 440 93..97 '3.14': f64
@@ -422,7 +442,7 @@ fn test() {
422 113..118 'false': bool 442 113..118 'false': bool
423 124..128 'true': bool 443 124..128 'true': bool
424 134..202 'r#" ... "#': &str 444 134..202 'r#" ... "#': &str
425 208..218 'br#"yolo"#': &[u8] 445 208..218 'br#"yolo"#': &[u8; _]
426 "### 446 "###
427 ); 447 );
428} 448}
@@ -576,6 +596,50 @@ impl S {
576} 596}
577 597
578#[test] 598#[test]
599fn infer_self_as_path() {
600 assert_snapshot!(
601 infer(r#"
602struct S1;
603struct S2(isize);
604enum E {
605 V1,
606 V2(u32),
607}
608
609impl S1 {
610 fn test() {
611 Self;
612 }
613}
614impl S2 {
615 fn test() {
616 Self(1);
617 }
618}
619impl E {
620 fn test() {
621 Self::V1;
622 Self::V2(1);
623 }
624}
625"#),
626 @r###"
627 87..108 '{ ... }': ()
628 97..101 'Self': S1
629 135..159 '{ ... }': ()
630 145..149 'Self': S2(isize) -> S2
631 145..152 'Self(1)': S2
632 150..151 '1': isize
633 185..231 '{ ... }': ()
634 195..203 'Self::V1': E
635 213..221 'Self::V2': V2(u32) -> E
636 213..224 'Self::V2(1)': E
637 222..223 '1': u32
638 "###
639 );
640}
641
642#[test]
579fn infer_binary_op() { 643fn infer_binary_op() {
580 assert_snapshot!( 644 assert_snapshot!(
581 infer(r#" 645 infer(r#"
@@ -893,7 +957,7 @@ fn main(foo: Foo) {
893 51..107 'if tru... }': () 957 51..107 'if tru... }': ()
894 54..58 'true': bool 958 54..58 'true': bool
895 59..67 '{ }': () 959 59..67 '{ }': ()
896 73..107 'if fal... }': () 960 73..107 'if fal... }': i32
897 76..81 'false': bool 961 76..81 'false': bool
898 82..107 '{ ... }': i32 962 82..107 '{ ... }': i32
899 92..95 'foo': Foo 963 92..95 'foo': Foo
@@ -935,7 +999,7 @@ fn foo() {
935 29..33 'true': bool 999 29..33 'true': bool
936 34..51 '{ ... }': i32 1000 34..51 '{ ... }': i32
937 44..45 '1': i32 1001 44..45 '1': i32
938 57..80 '{ ... }': ! 1002 57..80 '{ ... }': i32
939 67..73 'return': ! 1003 67..73 'return': !
940 90..93 '_x2': i32 1004 90..93 '_x2': i32
941 96..149 'if tru... }': i32 1005 96..149 'if tru... }': i32
@@ -951,7 +1015,7 @@ fn foo() {
951 186..190 'true': bool 1015 186..190 'true': bool
952 194..195 '3': i32 1016 194..195 '3': i32
953 205..206 '_': bool 1017 205..206 '_': bool
954 210..241 '{ ... }': ! 1018 210..241 '{ ... }': i32
955 224..230 'return': ! 1019 224..230 'return': !
956 257..260 '_x4': i32 1020 257..260 '_x4': i32
957 263..320 'match ... }': i32 1021 263..320 'match ... }': i32
@@ -1687,7 +1751,7 @@ fn foo() -> u32 {
1687 17..59 '{ ...; }; }': () 1751 17..59 '{ ...; }; }': ()
1688 27..28 'x': || -> usize 1752 27..28 'x': || -> usize
1689 31..56 '|| -> ...n 1; }': || -> usize 1753 31..56 '|| -> ...n 1; }': || -> usize
1690 43..56 '{ return 1; }': ! 1754 43..56 '{ return 1; }': usize
1691 45..53 'return 1': ! 1755 45..53 'return 1': !
1692 52..53 '1': usize 1756 52..53 '1': usize
1693 "### 1757 "###
@@ -1706,7 +1770,7 @@ fn foo() -> u32 {
1706 17..48 '{ ...; }; }': () 1770 17..48 '{ ...; }; }': ()
1707 27..28 'x': || -> () 1771 27..28 'x': || -> ()
1708 31..45 '|| { return; }': || -> () 1772 31..45 '|| { return; }': || -> ()
1709 34..45 '{ return; }': ! 1773 34..45 '{ return; }': ()
1710 36..42 'return': ! 1774 36..42 'return': !
1711 "### 1775 "###
1712 ); 1776 );
@@ -1755,3 +1819,181 @@ fn main() {
1755 "### 1819 "###
1756 ); 1820 );
1757} 1821}
1822
1823#[test]
1824fn effects_smoke_test() {
1825 assert_snapshot!(
1826 infer(r#"
1827fn main() {
1828 let x = unsafe { 92 };
1829 let y = async { async { () }.await };
1830 let z = try { () };
1831 let t = 'a: { 92 };
1832}
1833"#),
1834 @r###"
1835 11..131 '{ ...2 }; }': ()
1836 21..22 'x': i32
1837 32..38 '{ 92 }': i32
1838 34..36 '92': i32
1839 48..49 'y': {unknown}
1840 58..80 '{ asyn...wait }': {unknown}
1841 60..78 'async ....await': {unknown}
1842 66..72 '{ () }': ()
1843 68..70 '()': ()
1844 90..91 'z': {unknown}
1845 94..104 'try { () }': {unknown}
1846 98..104 '{ () }': ()
1847 100..102 '()': ()
1848 114..115 't': i32
1849 122..128 '{ 92 }': i32
1850 124..126 '92': i32
1851 "###
1852 )
1853}
1854
1855#[test]
1856fn infer_generic_from_later_assignment() {
1857 assert_snapshot!(
1858 infer(r#"
1859enum Option<T> { Some(T), None }
1860use Option::*;
1861
1862fn test() {
1863 let mut end = None;
1864 loop {
1865 end = Some(true);
1866 }
1867}
1868"#),
1869 @r###"
1870 60..130 '{ ... } }': ()
1871 70..77 'mut end': Option<bool>
1872 80..84 'None': Option<bool>
1873 90..128 'loop {... }': !
1874 95..128 '{ ... }': ()
1875 105..108 'end': Option<bool>
1876 105..121 'end = ...(true)': ()
1877 111..115 'Some': Some<bool>(bool) -> Option<bool>
1878 111..121 'Some(true)': Option<bool>
1879 116..120 'true': bool
1880 "###
1881 );
1882}
1883
1884#[test]
1885fn infer_loop_break_with_val() {
1886 assert_snapshot!(
1887 infer(r#"
1888enum Option<T> { Some(T), None }
1889use Option::*;
1890
1891fn test() {
1892 let x = loop {
1893 if false {
1894 break None;
1895 }
1896
1897 break Some(true);
1898 };
1899}
1900"#),
1901 @r###"
1902 60..169 '{ ... }; }': ()
1903 70..71 'x': Option<bool>
1904 74..166 'loop {... }': Option<bool>
1905 79..166 '{ ... }': ()
1906 89..133 'if fal... }': ()
1907 92..97 'false': bool
1908 98..133 '{ ... }': ()
1909 112..122 'break None': !
1910 118..122 'None': Option<bool>
1911 143..159 'break ...(true)': !
1912 149..153 'Some': Some<bool>(bool) -> Option<bool>
1913 149..159 'Some(true)': Option<bool>
1914 154..158 'true': bool
1915 "###
1916 );
1917}
1918
1919#[test]
1920fn infer_loop_break_without_val() {
1921 assert_snapshot!(
1922 infer(r#"
1923enum Option<T> { Some(T), None }
1924use Option::*;
1925
1926fn test() {
1927 let x = loop {
1928 if false {
1929 break;
1930 }
1931 };
1932}
1933"#),
1934 @r###"
1935 60..137 '{ ... }; }': ()
1936 70..71 'x': ()
1937 74..134 'loop {... }': ()
1938 79..134 '{ ... }': ()
1939 89..128 'if fal... }': ()
1940 92..97 'false': bool
1941 98..128 '{ ... }': ()
1942 112..117 'break': !
1943 "###
1944 );
1945}
1946
1947#[test]
1948fn infer_labelled_break_with_val() {
1949 assert_snapshot!(
1950 infer(r#"
1951fn foo() {
1952 let _x = || 'outer: loop {
1953 let inner = 'inner: loop {
1954 let i = Default::default();
1955 if (break 'outer i) {
1956 loop { break 'inner 5i8; };
1957 } else if true {
1958 break 'inner 6;
1959 }
1960 break 7;
1961 };
1962 break inner < 8;
1963 };
1964}
1965"#),
1966 @r###"
1967 10..336 '{ ... }; }': ()
1968 20..22 '_x': || -> bool
1969 25..333 '|| 'ou... }': || -> bool
1970 28..333 ''outer... }': bool
1971 41..333 '{ ... }': ()
1972 55..60 'inner': i8
1973 63..301 ''inner... }': i8
1974 76..301 '{ ... }': ()
1975 94..95 'i': bool
1976 98..114 'Defaul...efault': {unknown}
1977 98..116 'Defaul...ault()': bool
1978 130..270 'if (br... }': ()
1979 134..148 'break 'outer i': !
1980 147..148 'i': bool
1981 150..209 '{ ... }': ()
1982 168..194 'loop {...5i8; }': !
1983 173..194 '{ brea...5i8; }': ()
1984 175..191 'break ...er 5i8': !
1985 188..191 '5i8': i8
1986 215..270 'if tru... }': ()
1987 218..222 'true': bool
1988 223..270 '{ ... }': ()
1989 241..255 'break 'inner 6': !
1990 254..255 '6': i8
1991 283..290 'break 7': !
1992 289..290 '7': i8
1993 311..326 'break inner < 8': !
1994 317..322 'inner': i8
1995 317..326 'inner < 8': bool
1996 325..326 '8': i8
1997 "###
1998 );
1999}
diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs
index e555c879a..e8778d419 100644
--- a/crates/ra_hir_ty/src/tests/traits.rs
+++ b/crates/ra_hir_ty/src/tests/traits.rs
@@ -1,10 +1,11 @@
1use insta::assert_snapshot; 1use insta::assert_snapshot;
2
3use ra_db::fixture::WithFixture; 2use ra_db::fixture::WithFixture;
3use test_utils::mark;
4 4
5use super::{infer, infer_with_mismatches, type_at, type_at_pos};
6use crate::test_db::TestDB; 5use crate::test_db::TestDB;
7 6
7use super::{infer, infer_with_mismatches, type_at, type_at_pos};
8
8#[test] 9#[test]
9fn infer_await() { 10fn infer_await() {
10 let (db, pos) = TestDB::with_position( 11 let (db, pos) = TestDB::with_position(
@@ -301,7 +302,7 @@ fn test() {
301 302
302#[test] 303#[test]
303fn trait_default_method_self_bound_implements_trait() { 304fn trait_default_method_self_bound_implements_trait() {
304 test_utils::covers!(trait_self_implements_self); 305 mark::check!(trait_self_implements_self);
305 assert_snapshot!( 306 assert_snapshot!(
306 infer(r#" 307 infer(r#"
307trait Trait { 308trait Trait {
@@ -324,7 +325,6 @@ trait Trait {
324 325
325#[test] 326#[test]
326fn trait_default_method_self_bound_implements_super_trait() { 327fn trait_default_method_self_bound_implements_super_trait() {
327 test_utils::covers!(trait_self_implements_self);
328 assert_snapshot!( 328 assert_snapshot!(
329 infer(r#" 329 infer(r#"
330trait SuperTrait { 330trait SuperTrait {
@@ -1617,6 +1617,138 @@ fn test<F: FnOnce(u32, u64) -> u128>(f: F) {
1617} 1617}
1618 1618
1619#[test] 1619#[test]
1620fn fn_ptr_and_item() {
1621 assert_snapshot!(
1622 infer(r#"
1623#[lang="fn_once"]
1624trait FnOnce<Args> {
1625 type Output;
1626
1627 fn call_once(self, args: Args) -> Self::Output;
1628}
1629
1630trait Foo<T> {
1631 fn foo(&self) -> T;
1632}
1633
1634struct Bar<T>(T);
1635
1636impl<A1, R, F: FnOnce(A1) -> R> Foo<(A1, R)> for Bar<F> {
1637 fn foo(&self) -> (A1, R) {}
1638}
1639
1640enum Opt<T> { None, Some(T) }
1641impl<T> Opt<T> {
1642 fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Opt<U> {}
1643}
1644
1645fn test() {
1646 let bar: Bar<fn(u8) -> u32>;
1647 bar.foo();
1648
1649 let opt: Opt<u8>;
1650 let f: fn(u8) -> u32;
1651 opt.map(f);
1652}
1653"#),
1654 @r###"
165575..79 'self': Self
165681..85 'args': Args
1657140..144 'self': &Self
1658244..248 'self': &Bar<F>
1659261..263 '{}': ()
1660347..351 'self': Opt<T>
1661353..354 'f': F
1662369..371 '{}': ()
1663385..501 '{ ...(f); }': ()
1664395..398 'bar': Bar<fn(u8) -> u32>
1665424..427 'bar': Bar<fn(u8) -> u32>
1666424..433 'bar.foo()': {unknown}
1667444..447 'opt': Opt<u8>
1668466..467 'f': fn(u8) -> u32
1669488..491 'opt': Opt<u8>
1670488..498 'opt.map(f)': Opt<FnOnce::Output<fn(u8) -> u32, (u8,)>>
1671496..497 'f': fn(u8) -> u32
1672"###
1673 );
1674}
1675
1676#[test]
1677fn fn_trait_deref_with_ty_default() {
1678 assert_snapshot!(
1679 infer(r#"
1680#[lang = "deref"]
1681trait Deref {
1682 type Target;
1683
1684 fn deref(&self) -> &Self::Target;
1685}
1686
1687#[lang="fn_once"]
1688trait FnOnce<Args> {
1689 type Output;
1690
1691 fn call_once(self, args: Args) -> Self::Output;
1692}
1693
1694struct Foo;
1695
1696impl Foo {
1697 fn foo(&self) -> usize {}
1698}
1699
1700struct Lazy<T, F = fn() -> T>(F);
1701
1702impl<T, F> Lazy<T, F> {
1703 pub fn new(f: F) -> Lazy<T, F> {}
1704}
1705
1706impl<T, F: FnOnce() -> T> Deref for Lazy<T, F> {
1707 type Target = T;
1708}
1709
1710fn test() {
1711 let lazy1: Lazy<Foo, _> = Lazy::new(|| Foo);
1712 let r1 = lazy1.foo();
1713
1714 fn make_foo_fn() -> Foo {}
1715 let make_foo_fn_ptr: fn() -> Foo = make_foo_fn;
1716 let lazy2: Lazy<Foo, _> = Lazy::new(make_foo_fn_ptr);
1717 let r2 = lazy2.foo();
1718}
1719"#),
1720 @r###"
172165..69 'self': &Self
1722166..170 'self': Self
1723172..176 'args': Args
1724240..244 'self': &Foo
1725255..257 '{}': ()
1726335..336 'f': F
1727355..357 '{}': ()
1728444..690 '{ ...o(); }': ()
1729454..459 'lazy1': Lazy<Foo, fn() -> T>
1730476..485 'Lazy::new': fn new<Foo, fn() -> T>(fn() -> T) -> Lazy<Foo, fn() -> T>
1731476..493 'Lazy::...| Foo)': Lazy<Foo, fn() -> T>
1732486..492 '|| Foo': || -> T
1733489..492 'Foo': Foo
1734503..505 'r1': {unknown}
1735508..513 'lazy1': Lazy<Foo, fn() -> T>
1736508..519 'lazy1.foo()': {unknown}
1737561..576 'make_foo_fn_ptr': fn() -> Foo
1738592..603 'make_foo_fn': fn make_foo_fn() -> Foo
1739613..618 'lazy2': Lazy<Foo, fn() -> T>
1740635..644 'Lazy::new': fn new<Foo, fn() -> T>(fn() -> T) -> Lazy<Foo, fn() -> T>
1741635..661 'Lazy::...n_ptr)': Lazy<Foo, fn() -> T>
1742645..660 'make_foo_fn_ptr': fn() -> Foo
1743671..673 'r2': {unknown}
1744676..681 'lazy2': Lazy<Foo, fn() -> T>
1745676..687 'lazy2.foo()': {unknown}
1746550..552 '{}': ()
1747"###
1748 );
1749}
1750
1751#[test]
1620fn closure_1() { 1752fn closure_1() {
1621 assert_snapshot!( 1753 assert_snapshot!(
1622 infer(r#" 1754 infer(r#"
@@ -2055,7 +2187,7 @@ fn test<I: Iterator<Item: Iterator<Item = u32>>>() {
2055#[test] 2187#[test]
2056fn proc_macro_server_types() { 2188fn proc_macro_server_types() {
2057 assert_snapshot!( 2189 assert_snapshot!(
2058 infer_with_mismatches(r#" 2190 infer(r#"
2059macro_rules! with_api { 2191macro_rules! with_api {
2060 ($S:ident, $self:ident, $m:ident) => { 2192 ($S:ident, $self:ident, $m:ident) => {
2061 $m! { 2193 $m! {
@@ -2069,9 +2201,9 @@ macro_rules! with_api {
2069} 2201}
2070macro_rules! associated_item { 2202macro_rules! associated_item {
2071 (type TokenStream) => 2203 (type TokenStream) =>
2072 (type TokenStream: 'static + Clone;); 2204 (type TokenStream: 'static;);
2073 (type Group) => 2205 (type Group) =>
2074 (type Group: 'static + Clone;); 2206 (type Group: 'static;);
2075 ($($item:tt)*) => ($($item)*;) 2207 ($($item:tt)*) => ($($item)*;)
2076} 2208}
2077macro_rules! declare_server_traits { 2209macro_rules! declare_server_traits {
@@ -2083,21 +2215,23 @@ macro_rules! declare_server_traits {
2083 } 2215 }
2084 2216
2085 $(pub trait $name: Types { 2217 $(pub trait $name: Types {
2086 $(associated_item!(fn $method(&mut self, $($arg: $arg_ty),*) $(-> $ret_ty)?);)* 2218 $(associated_item!(fn $method($($arg: $arg_ty),*) $(-> $ret_ty)?);)*
2087 })* 2219 })*
2088 2220
2089 pub trait Server: Types $(+ $name)* {} 2221 pub trait Server: Types $(+ $name)* {}
2090 impl<S: Types $(+ $name)*> Server for S {} 2222 impl<S: Types $(+ $name)*> Server for S {}
2091 } 2223 }
2092} 2224}
2225
2093with_api!(Self, self_, declare_server_traits); 2226with_api!(Self, self_, declare_server_traits);
2094struct Group {} 2227struct G {}
2095struct TokenStream {} 2228struct T {}
2096struct Rustc; 2229struct Rustc;
2097impl Types for Rustc { 2230impl Types for Rustc {
2098 type TokenStream = TokenStream; 2231 type TokenStream = T;
2099 type Group = Group; 2232 type Group = G;
2100} 2233}
2234
2101fn make<T>() -> T { loop {} } 2235fn make<T>() -> T { loop {} }
2102impl TokenStream for Rustc { 2236impl TokenStream for Rustc {
2103 fn new() -> Self::TokenStream { 2237 fn new() -> Self::TokenStream {
@@ -2105,17 +2239,17 @@ impl TokenStream for Rustc {
2105 make() 2239 make()
2106 } 2240 }
2107} 2241}
2108"#, true), 2242"#),
2109 @r###" 2243 @r###"
2110 1115..1126 '{ loop {} }': T 2244 1062..1073 '{ loop {} }': T
2111 1117..1124 'loop {}': ! 2245 1064..1071 'loop {}': !
2112 1122..1124 '{}': () 2246 1069..1071 '{}': ()
2113 1190..1253 '{ ... }': {unknown} 2247 1137..1200 '{ ... }': T
2114 1204..1209 'group': {unknown} 2248 1151..1156 'group': G
2115 1225..1229 'make': fn make<{unknown}>() -> {unknown} 2249 1172..1176 'make': fn make<G>() -> G
2116 1225..1231 'make()': {unknown} 2250 1172..1178 'make()': G
2117 1241..1245 'make': fn make<{unknown}>() -> {unknown} 2251 1188..1192 'make': fn make<T>() -> T
2118 1241..1247 'make()': {unknown} 2252 1188..1194 'make()': T
2119 "### 2253 "###
2120 ); 2254 );
2121} 2255}
@@ -2468,3 +2602,199 @@ fn test(x: &dyn Foo) {
2468 "### 2602 "###
2469 ); 2603 );
2470} 2604}
2605
2606#[test]
2607fn builtin_copy() {
2608 assert_snapshot!(
2609 infer_with_mismatches(r#"
2610#[lang = "copy"]
2611trait Copy {}
2612
2613struct IsCopy;
2614impl Copy for IsCopy {}
</