aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/hir_ty/src/infer.rs24
-rw-r--r--crates/hir_ty/src/infer/expr.rs18
-rw-r--r--crates/hir_ty/src/tests/simple.rs89
-rw-r--r--crates/vfs-notify/src/lib.rs17
-rw-r--r--docs/dev/style.md61
5 files changed, 185 insertions, 24 deletions
diff --git a/crates/hir_ty/src/infer.rs b/crates/hir_ty/src/infer.rs
index 9a7785c76..644ebd42d 100644
--- a/crates/hir_ty/src/infer.rs
+++ b/crates/hir_ty/src/infer.rs
@@ -22,7 +22,7 @@ use arena::map::ArenaMap;
22use hir_def::{ 22use hir_def::{
23 body::Body, 23 body::Body,
24 data::{ConstData, FunctionData, StaticData}, 24 data::{ConstData, FunctionData, StaticData},
25 expr::{BindingAnnotation, ExprId, PatId}, 25 expr::{ArithOp, BinaryOp, BindingAnnotation, ExprId, PatId},
26 lang_item::LangItemTarget, 26 lang_item::LangItemTarget,
27 path::{path, Path}, 27 path::{path, Path},
28 resolver::{HasResolver, Resolver, TypeNs}, 28 resolver::{HasResolver, Resolver, TypeNs},
@@ -586,6 +586,28 @@ impl<'a> InferenceContext<'a> {
586 self.db.trait_data(trait_).associated_type_by_name(&name![Output]) 586 self.db.trait_data(trait_).associated_type_by_name(&name![Output])
587 } 587 }
588 588
589 fn resolve_binary_op_output(&self, bop: &BinaryOp) -> Option<TypeAliasId> {
590 let lang_item = match bop {
591 BinaryOp::ArithOp(aop) => match aop {
592 ArithOp::Add => "add",
593 ArithOp::Sub => "sub",
594 ArithOp::Mul => "mul",
595 ArithOp::Div => "div",
596 ArithOp::Shl => "shl",
597 ArithOp::Shr => "shr",
598 ArithOp::Rem => "rem",
599 ArithOp::BitXor => "bitxor",
600 ArithOp::BitOr => "bitor",
601 ArithOp::BitAnd => "bitand",
602 },
603 _ => return None,
604 };
605
606 let trait_ = self.resolve_lang_item(lang_item)?.as_trait();
607
608 self.db.trait_data(trait_?).associated_type_by_name(&name![Output])
609 }
610
589 fn resolve_boxed_box(&self) -> Option<AdtId> { 611 fn resolve_boxed_box(&self) -> Option<AdtId> {
590 let struct_ = self.resolve_lang_item("owned_box")?.as_struct()?; 612 let struct_ = self.resolve_lang_item("owned_box")?.as_struct()?;
591 Some(struct_.into()) 613 Some(struct_.into())
diff --git a/crates/hir_ty/src/infer/expr.rs b/crates/hir_ty/src/infer/expr.rs
index 0a141b9cb..8ac4cf89a 100644
--- a/crates/hir_ty/src/infer/expr.rs
+++ b/crates/hir_ty/src/infer/expr.rs
@@ -12,6 +12,7 @@ use hir_def::{
12}; 12};
13use hir_expand::name::{name, Name}; 13use hir_expand::name::{name, Name};
14use syntax::ast::RangeOp; 14use syntax::ast::RangeOp;
15use test_utils::mark;
15 16
16use crate::{ 17use crate::{
17 autoderef, method_resolution, op, 18 autoderef, method_resolution, op,
@@ -531,13 +532,22 @@ impl<'a> InferenceContext<'a> {
531 _ => Expectation::none(), 532 _ => Expectation::none(),
532 }; 533 };
533 let lhs_ty = self.infer_expr(*lhs, &lhs_expectation); 534 let lhs_ty = self.infer_expr(*lhs, &lhs_expectation);
534 // FIXME: find implementation of trait corresponding to operation
535 // symbol and resolve associated `Output` type
536 let rhs_expectation = op::binary_op_rhs_expectation(*op, lhs_ty.clone()); 535 let rhs_expectation = op::binary_op_rhs_expectation(*op, lhs_ty.clone());
537 let rhs_ty = self.infer_expr(*rhs, &Expectation::has_type(rhs_expectation)); 536 let rhs_ty = self.infer_expr(*rhs, &Expectation::has_type(rhs_expectation));
538 537
539 // FIXME: similar as above, return ty is often associated trait type 538 let ret = op::binary_op_return_ty(*op, lhs_ty.clone(), rhs_ty.clone());
540 op::binary_op_return_ty(*op, lhs_ty, rhs_ty) 539
540 if ret == Ty::Unknown {
541 mark::hit!(infer_expr_inner_binary_operator_overload);
542
543 self.resolve_associated_type_with_params(
544 lhs_ty,
545 self.resolve_binary_op_output(op),
546 &[rhs_ty],
547 )
548 } else {
549 ret
550 }
541 } 551 }
542 _ => Ty::Unknown, 552 _ => Ty::Unknown,
543 }, 553 },
diff --git a/crates/hir_ty/src/tests/simple.rs b/crates/hir_ty/src/tests/simple.rs
index 5b07948f3..4f72582b6 100644
--- a/crates/hir_ty/src/tests/simple.rs
+++ b/crates/hir_ty/src/tests/simple.rs
@@ -1,4 +1,5 @@
1use expect_test::expect; 1use expect_test::expect;
2use test_utils::mark;
2 3
3use super::{check_infer, check_types}; 4use super::{check_infer, check_types};
4 5
@@ -2225,3 +2226,91 @@ fn generic_default_depending_on_other_type_arg_forward() {
2225 "#]], 2226 "#]],
2226 ); 2227 );
2227} 2228}
2229
2230#[test]
2231fn infer_operator_overload() {
2232 mark::check!(infer_expr_inner_binary_operator_overload);
2233
2234 check_infer(
2235 r#"
2236 struct V2([f32; 2]);
2237
2238 #[lang = "add"]
2239 pub trait Add<Rhs = Self> {
2240 /// The resulting type after applying the `+` operator.
2241 type Output;
2242
2243 /// Performs the `+` operation.
2244 #[must_use]
2245 fn add(self, rhs: Rhs) -> Self::Output;
2246 }
2247
2248 impl Add<V2> for V2 {
2249 type Output = V2;
2250
2251 fn add(self, rhs: V2) -> V2 {
2252 let x = self.0[0] + rhs.0[0];
2253 let y = self.0[1] + rhs.0[1];
2254 V2([x, y])
2255 }
2256 }
2257
2258 fn test() {
2259 let va = V2([0.0, 1.0]);
2260 let vb = V2([0.0, 1.0]);
2261
2262 let r = va + vb;
2263 }
2264
2265 "#,
2266 expect![[r#"
2267 207..211 'self': Self
2268 213..216 'rhs': Rhs
2269 299..303 'self': V2
2270 305..308 'rhs': V2
2271 320..422 '{ ... }': V2
2272 334..335 'x': f32
2273 338..342 'self': V2
2274 338..344 'self.0': [f32; _]
2275 338..347 'self.0[0]': {unknown}
2276 338..358 'self.0...s.0[0]': f32
2277 345..346 '0': i32
2278 350..353 'rhs': V2
2279 350..355 'rhs.0': [f32; _]
2280 350..358 'rhs.0[0]': {unknown}
2281 356..357 '0': i32
2282 372..373 'y': f32
2283 376..380 'self': V2
2284 376..382 'self.0': [f32; _]
2285 376..385 'self.0[1]': {unknown}
2286 376..396 'self.0...s.0[1]': f32
2287 383..384 '1': i32
2288 388..391 'rhs': V2
2289 388..393 'rhs.0': [f32; _]
2290 388..396 'rhs.0[1]': {unknown}
2291 394..395 '1': i32
2292 406..408 'V2': V2([f32; _]) -> V2
2293 406..416 'V2([x, y])': V2
2294 409..415 '[x, y]': [f32; _]
2295 410..411 'x': f32
2296 413..414 'y': f32
2297 436..519 '{ ... vb; }': ()
2298 446..448 'va': V2
2299 451..453 'V2': V2([f32; _]) -> V2
2300 451..465 'V2([0.0, 1.0])': V2
2301 454..464 '[0.0, 1.0]': [f32; _]
2302 455..458 '0.0': f32
2303 460..463 '1.0': f32
2304 475..477 'vb': V2
2305 480..482 'V2': V2([f32; _]) -> V2
2306 480..494 'V2([0.0, 1.0])': V2
2307 483..493 '[0.0, 1.0]': [f32; _]
2308 484..487 '0.0': f32
2309 489..492 '1.0': f32
2310 505..506 'r': V2
2311 509..511 'va': V2
2312 509..516 'va + vb': V2
2313 514..516 'vb': V2
2314 "#]],
2315 );
2316}
diff --git a/crates/vfs-notify/src/lib.rs b/crates/vfs-notify/src/lib.rs
index e1e36612a..c605bcf3c 100644
--- a/crates/vfs-notify/src/lib.rs
+++ b/crates/vfs-notify/src/lib.rs
@@ -165,14 +165,15 @@ impl NotifyActor {
165 let mut res = Vec::new(); 165 let mut res = Vec::new();
166 166
167 for root in dirs.include.iter() { 167 for root in dirs.include.iter() {
168 let walkdir = WalkDir::new(root).into_iter().filter_entry(|entry| { 168 let walkdir =
169 if !entry.file_type().is_dir() { 169 WalkDir::new(root).follow_links(true).into_iter().filter_entry(|entry| {
170 return true; 170 if !entry.file_type().is_dir() {
171 } 171 return true;
172 let path = AbsPath::assert(entry.path()); 172 }
173 root == path 173 let path = AbsPath::assert(entry.path());
174 || dirs.exclude.iter().chain(&dirs.include).all(|it| it != path) 174 root == path
175 }); 175 || dirs.exclude.iter().chain(&dirs.include).all(|it| it != path)
176 });
176 177
177 let files = walkdir.filter_map(|it| it.ok()).filter_map(|entry| { 178 let files = walkdir.filter_map(|it| it.ok()).filter_map(|entry| {
178 let is_dir = entry.file_type().is_dir(); 179 let is_dir = entry.file_type().is_dir();
diff --git a/docs/dev/style.md b/docs/dev/style.md
index 883a6845d..7a64a0d22 100644
--- a/docs/dev/style.md
+++ b/docs/dev/style.md
@@ -366,27 +366,66 @@ People read things from top to bottom, so place most important things first.
366 366
367Specifically, if all items except one are private, always put the non-private item on top. 367Specifically, if all items except one are private, always put the non-private item on top.
368 368
369Put `struct`s and `enum`s first, functions and impls last.
370
371Do
372
373```rust 369```rust
374// Good 370// Good
375struct Foo { 371pub(crate) fn frobnicate() {
376 bars: Vec<Bar> 372 Helper::act()
373}
374
375#[derive(Default)]
376struct Helper { stuff: i32 }
377
378impl Helper {
379 fn act(&self) {
380
381 }
382}
383
384// Not as good
385#[derive(Default)]
386struct Helper { stuff: i32 }
387
388pub(crate) fn frobnicate() {
389 Helper::act()
377} 390}
378 391
379struct Bar; 392impl Helper {
393 fn act(&self) {
394
395 }
396}
380``` 397```
381 398
382rather than 399If there's a mixture of private and public items, put public items first.
400If function bodies are folded in the editor, the source code should read as documentation for the public API.
401
402Put `struct`s and `enum`s first, functions and impls last. Order types declarations in top-down manner.
383 403
384```rust 404```rust
405// Good
406struct Parent {
407 children: Vec<Child>
408}
409
410struct Child;
411
412impl Parent {
413}
414
415impl Child {
416}
417
385// Not as good 418// Not as good
386struct Bar; 419struct Child;
387 420
388struct Foo { 421impl Child {
389 bars: Vec<Bar> 422}
423
424struct Parent {
425 children: Vec<Child>
426}
427
428impl Parent {
390} 429}
391``` 430```
392 431