diff --git a/crates/ra_hir_def/src/path.rs b/crates/ra_hir_def/src/path.rs
index ec9d13e8270..50f0cad94f2 100644
--- a/crates/ra_hir_def/src/path.rs
+++ b/crates/ra_hir_def/src/path.rs
@@ -342,6 +342,14 @@ pub mod known {
         )
     }
 
+    pub fn std_ops_neg() -> Path {
+        Path::from_simple_segments(PathKind::Abs, vec![name::STD, name::OPS, name::NEG_TYPE])
+    }
+
+    pub fn std_ops_not() -> Path {
+        Path::from_simple_segments(PathKind::Abs, vec![name::STD, name::OPS, name::NOT_TYPE])
+    }
+
     pub fn std_result_result() -> Path {
         Path::from_simple_segments(PathKind::Abs, vec![name::STD, name::RESULT, name::RESULT_TYPE])
     }
diff --git a/crates/ra_hir_expand/src/name.rs b/crates/ra_hir_expand/src/name.rs
index 4f2f702c01f..9e68dd98d70 100644
--- a/crates/ra_hir_expand/src/name.rs
+++ b/crates/ra_hir_expand/src/name.rs
@@ -152,6 +152,8 @@ pub const RANGE_INCLUSIVE_TYPE: Name = Name::new_inline_ascii(b"RangeInclusive")
 pub const RANGE_TO_INCLUSIVE_TYPE: Name = Name::new_inline_ascii(b"RangeToInclusive");
 pub const RANGE_TO_TYPE: Name = Name::new_inline_ascii(b"RangeTo");
 pub const RANGE_TYPE: Name = Name::new_inline_ascii(b"Range");
+pub const NEG_TYPE: Name = Name::new_inline_ascii(b"Neg");
+pub const NOT_TYPE: Name = Name::new_inline_ascii(b"Not");
 
 // Builtin Macros
 pub const FILE_MACRO: Name = Name::new_inline_ascii(b"file");
diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs
index 62d5c8803cc..a1201b3e479 100644
--- a/crates/ra_hir_ty/src/infer.rs
+++ b/crates/ra_hir_ty/src/infer.rs
@@ -36,8 +36,8 @@ use ra_prof::profile;
 use super::{
     primitive::{FloatTy, IntTy},
     traits::{Guidance, Obligation, ProjectionPredicate, Solution},
-    ApplicationTy, InEnvironment, ProjectionTy, TraitEnvironment, TraitRef, Ty, TypeCtor, TypeWalk,
-    Uncertain,
+    ApplicationTy, InEnvironment, ProjectionTy, Substs, TraitEnvironment, TraitRef, Ty, TypeCtor,
+    TypeWalk, Uncertain,
 };
 use crate::{db::HirDatabase, infer::diagnostics::InferenceDiagnostic};
 
@@ -433,6 +433,18 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
         self.db.trait_data(trait_).associated_type_by_name(&name::OK_TYPE)
     }
 
+    fn resolve_ops_neg_output(&self) -> Option<TypeAliasId> {
+        let path = known::std_ops_neg();
+        let trait_ = self.resolver.resolve_known_trait(self.db, &path)?;
+        self.db.trait_data(trait_).associated_type_by_name(&name::OUTPUT_TYPE)
+    }
+
+    fn resolve_ops_not_output(&self) -> Option<TypeAliasId> {
+        let path = known::std_ops_not();
+        let trait_ = self.resolver.resolve_known_trait(self.db, &path)?;
+        self.db.trait_data(trait_).associated_type_by_name(&name::OUTPUT_TYPE)
+    }
+
     fn resolve_future_future_output(&self) -> Option<TypeAliasId> {
         let path = known::std_future_future();
         let trait_ = self.resolver.resolve_known_trait(self.db, &path)?;
diff --git a/crates/ra_hir_ty/src/infer/expr.rs b/crates/ra_hir_ty/src/infer/expr.rs
index 6110f5abd33..f8c00a7b4a3 100644
--- a/crates/ra_hir_ty/src/infer/expr.rs
+++ b/crates/ra_hir_ty/src/infer/expr.rs
@@ -332,31 +332,36 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
                     },
                     UnaryOp::Neg => {
                         match &inner_ty {
-                            Ty::Apply(a_ty) => match a_ty.ctor {
-                                TypeCtor::Int(Uncertain::Unknown)
-                                | TypeCtor::Int(Uncertain::Known(IntTy {
-                                    signedness: Signedness::Signed,
-                                    ..
-                                }))
-                                | TypeCtor::Float(..) => inner_ty,
-                                _ => Ty::Unknown,
-                            },
-                            Ty::Infer(InferTy::IntVar(..)) | Ty::Infer(InferTy::FloatVar(..)) => {
-                                inner_ty
-                            }
-                            // FIXME: resolve ops::Neg trait
-                            _ => Ty::Unknown,
+                            // Fast path for builtins
+                            Ty::Apply(ApplicationTy {
+                                ctor:
+                                    TypeCtor::Int(Uncertain::Known(IntTy {
+                                        signedness: Signedness::Signed,
+                                        ..
+                                    })),
+                                ..
+                            })
+                            | Ty::Apply(ApplicationTy {
+                                ctor: TypeCtor::Int(Uncertain::Unknown),
+                                ..
+                            })
+                            | Ty::Apply(ApplicationTy { ctor: TypeCtor::Float(_), .. })
+                            | Ty::Infer(InferTy::IntVar(..))
+                            | Ty::Infer(InferTy::FloatVar(..)) => inner_ty,
+                            // Otherwise we resolve via the std::ops::Neg trait
+                            _ => self
+                                .resolve_associated_type(inner_ty, self.resolve_ops_neg_output()),
                         }
                     }
                     UnaryOp::Not => {
                         match &inner_ty {
-                            Ty::Apply(a_ty) => match a_ty.ctor {
-                                TypeCtor::Bool | TypeCtor::Int(_) => inner_ty,
-                                _ => Ty::Unknown,
-                            },
-                            Ty::Infer(InferTy::IntVar(..)) => inner_ty,
-                            // FIXME: resolve ops::Not trait for inner_ty
-                            _ => Ty::Unknown,
+                            // Fast path for builtins
+                            Ty::Apply(ApplicationTy { ctor: TypeCtor::Bool, .. })
+                            | Ty::Apply(ApplicationTy { ctor: TypeCtor::Int(_), .. })
+                            | Ty::Infer(InferTy::IntVar(..)) => inner_ty,
+                            // Otherwise we resolve via the std::ops::Not trait
+                            _ => self
+                                .resolve_associated_type(inner_ty, self.resolve_ops_not_output()),
                         }
                     }
                 }
diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs
index 93c5f9a15a3..6139adb72e5 100644
--- a/crates/ra_hir_ty/src/tests/traits.rs
+++ b/crates/ra_hir_ty/src/tests/traits.rs
@@ -115,6 +115,70 @@ mod collections {
     assert_eq!("&str", type_at_pos(&db, pos));
 }
 
+#[test]
+fn infer_ops_neg() {
+    let (db, pos) = TestDB::with_position(
+        r#"
+//- /main.rs crate:main deps:std
+
+struct Bar;
+struct Foo;
+
+impl std::ops::Neg for Bar {
+    type Output = Foo;
+}
+
+fn test() {
+    let a = Bar;
+    let b = -a;
+    b<|>;
+}
+
+//- /std.rs crate:std
+
+#[prelude_import] use ops::*;
+mod ops {
+    pub trait Neg {
+        type Output;
+    }
+}
+"#,
+    );
+    assert_eq!("Foo", type_at_pos(&db, pos));
+}
+
+#[test]
+fn infer_ops_not() {
+    let (db, pos) = TestDB::with_position(
+        r#"
+//- /main.rs crate:main deps:std
+
+struct Bar;
+struct Foo;
+
+impl std::ops::Not for Bar {
+    type Output = Foo;
+}
+
+fn test() {
+    let a = Bar;
+    let b = !a;
+    b<|>;
+}
+
+//- /std.rs crate:std
+
+#[prelude_import] use ops::*;
+mod ops {
+    pub trait Not {
+        type Output;
+    }
+}
+"#,
+    );
+    assert_eq!("Foo", type_at_pos(&db, pos));
+}
+
 #[test]
 fn infer_from_bound_1() {
     assert_snapshot!(