diff --git a/crates/ra_ide_api/src/completion.rs b/crates/ra_ide_api/src/completion.rs
index 855f5d9640f..565d57c3724 100644
--- a/crates/ra_ide_api/src/completion.rs
+++ b/crates/ra_ide_api/src/completion.rs
@@ -7,6 +7,7 @@ mod complete_keyword;
 mod complete_snippet;
 mod complete_path;
 mod complete_scope;
+mod complete_postfix;
 
 use ra_db::SyntaxDatabase;
 
@@ -57,6 +58,6 @@ pub(crate) fn completions(db: &db::RootDatabase, position: FilePosition) -> Opti
     complete_path::complete_path(&mut acc, &ctx);
     complete_scope::complete_scope(&mut acc, &ctx);
     complete_dot::complete_dot(&mut acc, &ctx);
-
+    complete_postfix::complete_postfix(&mut acc, &ctx);
     Some(acc)
 }
diff --git a/crates/ra_ide_api/src/completion/complete_postfix.rs b/crates/ra_ide_api/src/completion/complete_postfix.rs
new file mode 100644
index 00000000000..cf0252a00b4
--- /dev/null
+++ b/crates/ra_ide_api/src/completion/complete_postfix.rs
@@ -0,0 +1,95 @@
+use crate::{
+    completion::{
+        completion_item::{
+            Completions,
+            Builder,
+            CompletionKind,
+        },
+        completion_context::CompletionContext,
+    },
+    CompletionItem
+};
+use ra_syntax::{
+    ast::AstNode,
+    TextRange
+};
+use ra_text_edit::TextEditBuilder;
+
+fn postfix_snippet(ctx: &CompletionContext, label: &str, snippet: &str) -> Builder {
+    let replace_range = ctx.source_range();
+    let receiver_range = ctx
+        .dot_receiver
+        .expect("no receiver available")
+        .syntax()
+        .range();
+    let delete_range = TextRange::from_to(receiver_range.start(), replace_range.start());
+    let mut builder = TextEditBuilder::default();
+    builder.delete(delete_range);
+    CompletionItem::new(CompletionKind::Postfix, replace_range, label)
+        .snippet(snippet)
+        .text_edit(builder.finish())
+}
+
+pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) {
+    if let Some(dot_receiver) = ctx.dot_receiver {
+        let receiver_text = dot_receiver.syntax().text().to_string();
+        postfix_snippet(ctx, "not", "!not").add_to(acc);
+        postfix_snippet(ctx, "if", &format!("if {} {{$0}}", receiver_text)).add_to(acc);
+        postfix_snippet(
+            ctx,
+            "match",
+            &format!("match {} {{\n${{1:_}} => {{$0\\}},\n}}", receiver_text),
+        )
+        .add_to(acc);
+        postfix_snippet(ctx, "while", &format!("while {} {{\n$0\n}}", receiver_text)).add_to(acc);
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use crate::completion::completion_item::CompletionKind;
+    use crate::completion::completion_item::check_completion;
+
+    fn check_snippet_completion(code: &str, expected_completions: &str) {
+        check_completion(code, expected_completions, CompletionKind::Postfix);
+    }
+
+    #[test]
+    fn test_filter_postfix_completion1() {
+        check_snippet_completion(
+            "filter_postfix_completion1",
+            r#"
+            fn main() {
+                let bar = "a";
+                bar.<|>
+            }
+            "#,
+        );
+    }
+
+    #[test]
+    fn test_filter_postfix_completion2() {
+        check_snippet_completion(
+            "filter_postfix_completion2",
+            r#"
+            fn main() {
+                let bar = "a";
+                bar.i<|>
+            }
+            "#,
+        );
+    }
+
+    #[test]
+    fn test_filter_postfix_completion3() {
+        check_snippet_completion(
+            "filter_postfix_completion3",
+            r#"
+            fn main() {
+                let bar = "a";
+                bar.if<|>
+            }
+            "#,
+        );
+    }
+}
diff --git a/crates/ra_ide_api/src/completion/completion_item.rs b/crates/ra_ide_api/src/completion/completion_item.rs
index f46d9e58125..c892ad84674 100644
--- a/crates/ra_ide_api/src/completion/completion_item.rs
+++ b/crates/ra_ide_api/src/completion/completion_item.rs
@@ -18,7 +18,12 @@ pub struct CompletionItem {
     lookup: Option<String>,
     insert_text: Option<String>,
     insert_text_format: InsertTextFormat,
+    /// Where completion occurs. `source_range` must contain the completion offset.
+    /// `insert_text` should start with what `source_range` points to, or VSCode
+    /// will filter out the completion silently.
     source_range: TextRange,
+    /// Additional text edit, ranges in `text_edit` must never intersect with `source_range`.
+    /// Or VSCode will drop it silently.
     text_edit: Option<TextEdit>,
 }
 
@@ -49,6 +54,7 @@ pub(crate) enum CompletionKind {
     /// "Secret sauce" completions.
     Magic,
     Snippet,
+    Postfix,
 }
 
 #[derive(Debug, PartialEq, Eq, Copy, Clone)]
diff --git a/crates/ra_ide_api/src/completion/snapshots/completion_item__completion_postfix.snap b/crates/ra_ide_api/src/completion/snapshots/completion_item__filter_postfix_completion1.snap
similarity index 67%
rename from crates/ra_ide_api/src/completion/snapshots/completion_item__completion_postfix.snap
rename to crates/ra_ide_api/src/completion/snapshots/completion_item__filter_postfix_completion1.snap
index 60b5a7424b9..a0abd00cc0a 100644
--- a/crates/ra_ide_api/src/completion/snapshots/completion_item__completion_postfix.snap
+++ b/crates/ra_ide_api/src/completion/snapshots/completion_item__filter_postfix_completion1.snap
@@ -1,4 +1,4 @@
-Created: 2019-01-19T13:50:41.824939+00:00
+Created: 2019-01-21T05:12:32.815475+00:00
 Creator: insta@0.1.4
 Source: crates/ra_ide_api/src/completion/completion_item.rs
 
@@ -9,18 +9,16 @@ Source: crates/ra_ide_api/src/completion/completion_item.rs
         kind: None,
         detail: None,
         lookup: None,
-        insert_text_format: Snippet,
-        text_edit: Some(
-            AtomTextEdit {
-                delete: [78; 78),
-                insert: "!not"
-            }
+        insert_text: Some(
+            "!not"
         ),
-        additional_text_edits: Some(
+        insert_text_format: Snippet,
+        source_range: [76; 76),
+        text_edit: Some(
             TextEdit {
                 atoms: [
                     AtomTextEdit {
-                        delete: [72; 78),
+                        delete: [72; 76),
                         insert: ""
                     }
                 ]
@@ -33,18 +31,16 @@ Source: crates/ra_ide_api/src/completion/completion_item.rs
         kind: None,
         detail: None,
         lookup: None,
-        insert_text_format: Snippet,
-        text_edit: Some(
-            AtomTextEdit {
-                delete: [78; 78),
-                insert: "if bar {$0}"
-            }
+        insert_text: Some(
+            "if bar {$0}"
         ),
-        additional_text_edits: Some(
+        insert_text_format: Snippet,
+        source_range: [76; 76),
+        text_edit: Some(
             TextEdit {
                 atoms: [
                     AtomTextEdit {
-                        delete: [72; 78),
+                        delete: [72; 76),
                         insert: ""
                     }
                 ]
@@ -57,18 +53,16 @@ Source: crates/ra_ide_api/src/completion/completion_item.rs
         kind: None,
         detail: None,
         lookup: None,
-        insert_text_format: Snippet,
-        text_edit: Some(
-            AtomTextEdit {
-                delete: [78; 78),
-                insert: "match bar {\n${1:_} => {$0\\},\n}"
-            }
+        insert_text: Some(
+            "match bar {\n${1:_} => {$0\\},\n}"
         ),
-        additional_text_edits: Some(
+        insert_text_format: Snippet,
+        source_range: [76; 76),
+        text_edit: Some(
             TextEdit {
                 atoms: [
                     AtomTextEdit {
-                        delete: [72; 78),
+                        delete: [72; 76),
                         insert: ""
                     }
                 ]
@@ -81,18 +75,16 @@ Source: crates/ra_ide_api/src/completion/completion_item.rs
         kind: None,
         detail: None,
         lookup: None,
-        insert_text_format: Snippet,
-        text_edit: Some(
-            AtomTextEdit {
-                delete: [78; 78),
-                insert: "while bar {\n$0\n}"
-            }
+        insert_text: Some(
+            "while bar {\n$0\n}"
         ),
-        additional_text_edits: Some(
+        insert_text_format: Snippet,
+        source_range: [76; 76),
+        text_edit: Some(
             TextEdit {
                 atoms: [
                     AtomTextEdit {
-                        delete: [72; 78),
+                        delete: [72; 76),
                         insert: ""
                     }
                 ]
diff --git a/crates/ra_ide_api/src/completion/snapshots/completion_item__filter_postfix_completion2.snap b/crates/ra_ide_api/src/completion/snapshots/completion_item__filter_postfix_completion2.snap
new file mode 100644
index 00000000000..3b3ee8d433d
--- /dev/null
+++ b/crates/ra_ide_api/src/completion/snapshots/completion_item__filter_postfix_completion2.snap
@@ -0,0 +1,94 @@
+Created: 2019-01-21T05:12:32.816092+00:00
+Creator: insta@0.1.4
+Source: crates/ra_ide_api/src/completion/completion_item.rs
+
+[
+    CompletionItem {
+        completion_kind: Postfix,
+        label: "not",
+        kind: None,
+        detail: None,
+        lookup: None,
+        insert_text: Some(
+            "!not"
+        ),
+        insert_text_format: Snippet,
+        source_range: [76; 77),
+        text_edit: Some(
+            TextEdit {
+                atoms: [
+                    AtomTextEdit {
+                        delete: [72; 76),
+                        insert: ""
+                    }
+                ]
+            }
+        )
+    },
+    CompletionItem {
+        completion_kind: Postfix,
+        label: "if",
+        kind: None,
+        detail: None,
+        lookup: None,
+        insert_text: Some(
+            "if bar {$0}"
+        ),
+        insert_text_format: Snippet,
+        source_range: [76; 77),
+        text_edit: Some(
+            TextEdit {
+                atoms: [
+                    AtomTextEdit {
+                        delete: [72; 76),
+                        insert: ""
+                    }
+                ]
+            }
+        )
+    },
+    CompletionItem {
+        completion_kind: Postfix,
+        label: "match",
+        kind: None,
+        detail: None,
+        lookup: None,
+        insert_text: Some(
+            "match bar {\n${1:_} => {$0\\},\n}"
+        ),
+        insert_text_format: Snippet,
+        source_range: [76; 77),
+        text_edit: Some(
+            TextEdit {
+                atoms: [
+                    AtomTextEdit {
+                        delete: [72; 76),
+                        insert: ""
+                    }
+                ]
+            }
+        )
+    },
+    CompletionItem {
+        completion_kind: Postfix,
+        label: "while",
+        kind: None,
+        detail: None,
+        lookup: None,
+        insert_text: Some(
+            "while bar {\n$0\n}"
+        ),
+        insert_text_format: Snippet,
+        source_range: [76; 77),
+        text_edit: Some(
+            TextEdit {
+                atoms: [
+                    AtomTextEdit {
+                        delete: [72; 76),
+                        insert: ""
+                    }
+                ]
+            }
+        )
+    }
+]
diff --git a/crates/ra_ide_api/src/completion/snapshots/completion_item__filter_postfix_completion3.snap b/crates/ra_ide_api/src/completion/snapshots/completion_item__filter_postfix_completion3.snap
new file mode 100644
index 00000000000..31e8f008c06
--- /dev/null
+++ b/crates/ra_ide_api/src/completion/snapshots/completion_item__filter_postfix_completion3.snap
@@ -0,0 +1,94 @@
+Created: 2019-01-21T05:19:05.341730+00:00
+Creator: insta@0.1.4
+Source: crates/ra_ide_api/src/completion/completion_item.rs
+
+[
+    CompletionItem {
+        completion_kind: Postfix,
+        label: "not",
+        kind: None,
+        detail: None,
+        lookup: None,
+        insert_text: Some(
+            "!not"
+        ),
+        insert_text_format: Snippet,
+        source_range: [76; 78),
+        text_edit: Some(
+            TextEdit {
+                atoms: [
+                    AtomTextEdit {
+                        delete: [72; 76),
+                        insert: ""
+                    }
+                ]
+            }
+        )
+    },
+    CompletionItem {
+        completion_kind: Postfix,
+        label: "if",
+        kind: None,
+        detail: None,
+        lookup: None,
+        insert_text: Some(
+            "if bar {$0}"
+        ),
+        insert_text_format: Snippet,
+        source_range: [76; 78),
+        text_edit: Some(
+            TextEdit {
+                atoms: [
+                    AtomTextEdit {
+                        delete: [72; 76),
+                        insert: ""
+                    }
+                ]
+            }
+        )
+    },
+    CompletionItem {
+        completion_kind: Postfix,
+        label: "match",
+        kind: None,
+        detail: None,
+        lookup: None,
+        insert_text: Some(
+            "match bar {\n${1:_} => {$0\\},\n}"
+        ),
+        insert_text_format: Snippet,
+        source_range: [76; 78),
+        text_edit: Some(
+            TextEdit {
+                atoms: [
+                    AtomTextEdit {
+                        delete: [72; 76),
+                        insert: ""
+                    }
+                ]
+            }
+        )
+    },
+    CompletionItem {
+        completion_kind: Postfix,
+        label: "while",
+        kind: None,
+        detail: None,
+        lookup: None,
+        insert_text: Some(
+            "while bar {\n$0\n}"
+        ),
+        insert_text_format: Snippet,
+        source_range: [76; 78),
+        text_edit: Some(
+            TextEdit {
+                atoms: [
+                    AtomTextEdit {
+                        delete: [72; 76),
+                        insert: ""
+                    }
+                ]
+            }
+        )
+    }
+]