From 4bb31a72315806e2a71dab0874132b988d303e60 Mon Sep 17 00:00:00 2001
From: Nick Cameron <ncameron@mozilla.com>
Date: Tue, 21 Mar 2017 11:23:59 +1300
Subject: [PATCH] Block indenting for struct lit patterns

Now follows struct_lit_style (and most other struct_lit_ options).

Required a fair bit of refactoring and bug fixes.

Fixes #1311
---
 rfc-rustfmt.toml        |   2 +-
 src/config.rs           |   4 +-
 src/expr.rs             | 162 +++++++++++++++-------------------------
 src/items.rs            |  14 ++--
 src/lib.rs              |   8 ++
 src/lists.rs            |  81 +++++++++++++++++++-
 src/patterns.rs         | 114 +++++++++++++++++-----------
 tests/source/closure.rs |   8 ++
 tests/target/closure.rs |   8 ++
 9 files changed, 245 insertions(+), 156 deletions(-)

diff --git a/rfc-rustfmt.toml b/rfc-rustfmt.toml
index 11bfda45956..a46692917b8 100644
--- a/rfc-rustfmt.toml
+++ b/rfc-rustfmt.toml
@@ -1,4 +1,4 @@
 fn_args_layout = "Block"
 array_layout = "Block"
 where_style = "Rfc"
-generics_indent = "Tabbed"
+generics_indent = "Block"
diff --git a/src/config.rs b/src/config.rs
index 91438a00f08..92a5aa7611e 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -320,7 +320,7 @@ create_config! {
     tab_spaces: usize, 4, "Number of spaces per tab";
     fn_call_width: usize, 60,
         "Maximum width of the args of a function call before falling back to vertical formatting";
-    struct_lit_width: usize, 16,
+    struct_lit_width: usize, 18,
         "Maximum width in the body of a struct lit before falling back to vertical formatting";
     struct_variant_width: usize, 35,
         "Maximum width in the body of a struct variant before falling back to vertical formatting";
@@ -380,7 +380,7 @@ create_config! {
     wrap_match_arms: bool, true, "Wrap multiline match arms in blocks";
     match_block_trailing_comma: bool, false,
         "Put a trailing comma after a block based match arm (non-block arms are not affected)";
-    closure_block_indent_threshold: isize, 5, "How many lines a closure must have before it is \
+    closure_block_indent_threshold: isize, 7, "How many lines a closure must have before it is \
                                                block indented. -1 means never use block indent.";
     space_before_type_annotation: bool, false,
         "Leave a space before the colon in a type annotation";
diff --git a/src/expr.rs b/src/expr.rs
index 9e1237bd7c2..aa4988740dc 100644
--- a/src/expr.rs
+++ b/src/expr.rs
@@ -19,7 +19,8 @@ use {Indent, Shape, Spanned};
 use codemap::SpanUtils;
 use rewrite::{Rewrite, RewriteContext};
 use lists::{write_list, itemize_list, ListFormatting, SeparatorTactic, ListTactic,
-            DefinitiveListTactic, definitive_tactic, ListItem, format_item_list};
+            DefinitiveListTactic, definitive_tactic, ListItem, format_item_list,
+            struct_lit_shape, struct_lit_tactic, shape_for_tactic, struct_lit_formatting};
 use string::{StringFormat, rewrite_string};
 use utils::{extra_offset, last_line_width, wrap_str, binary_search, first_line_width,
             semicolon_for_stmt, trimmed_last_line_width, left_most_sub_expr, stmt_expr};
@@ -658,8 +659,7 @@ impl Rewrite for ast::Stmt {
     fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
         let result = match self.node {
             ast::StmtKind::Local(ref local) => {
-                local.rewrite(context,
-                              Shape::legacy(context.config.max_width, shape.indent))
+                local.rewrite(context, shape)
             }
             ast::StmtKind::Expr(ref ex) |
             ast::StmtKind::Semi(ref ex) => {
@@ -893,7 +893,6 @@ impl<'a> Rewrite for ControlFlow<'a> {
             block_width
         };
 
-        // TODO this .block() - not what we want if we are actually visually indented
         let block_shape = Shape { width: block_width, ..shape };
         let block_str = try_opt!(self.block.rewrite(context, block_shape));
 
@@ -1120,8 +1119,9 @@ fn rewrite_match(context: &RewriteContext,
     }
 
     // `match `cond` {`
-    let cond_budget = try_opt!(shape.width.checked_sub(8));
-    let cond_str = try_opt!(cond.rewrite(context, Shape::legacy(cond_budget, shape.indent + 6)));
+    let cond_shape = try_opt!(shape.shrink_left(6));
+    let cond_shape = try_opt!(cond_shape.sub_width(2));
+    let cond_str = try_opt!(cond.rewrite(context, cond_shape));
     let alt_block_sep = String::from("\n") + &shape.indent.block_only().to_string(context.config);
     let block_sep = match context.config.control_brace_style {
         ControlBraceStyle::AlwaysSameLine => " ",
@@ -1563,7 +1563,11 @@ fn rewrite_call_inner<R>(context: &RewriteContext,
     let callee = callee.borrow();
     // FIXME using byte lens instead of char lens (and probably all over the
     // place too)
-    let callee_str = match callee.rewrite(context, Shape { width: max_callee_width, ..shape }) {
+    let callee_str = match callee.rewrite(context,
+                                          Shape {
+                                              width: max_callee_width,
+                                              ..shape
+                                          }) {
         Some(string) => {
             if !string.contains('\n') && string.len() > max_callee_width {
                 panic!("{:?} {}", string, max_callee_width);
@@ -1731,115 +1735,71 @@ fn rewrite_struct_lit<'a>(context: &RewriteContext,
     let path_shape = try_opt!(shape.sub_width(2));
     let path_str = try_opt!(rewrite_path(context, PathContext::Expr, None, path, path_shape));
 
-    // Foo { a: Foo } - indent is +3, width is -5.
-    let h_shape = shape.sub_width(path_str.len() + 5);
-    let v_shape = match context.config.struct_lit_style {
-        IndentStyle::Visual => {
-            try_opt!(try_opt!(shape.shrink_left(path_str.len() + 3)).sub_width(2))
-        }
-        IndentStyle::Block => {
-            let shape = shape.block_indent(context.config.tab_spaces);
-            Shape {
-                width: try_opt!(context.config.max_width.checked_sub(shape.indent.width())),
-                ..shape
-            }
-        }
-    };
+    if fields.len() == 0 && base.is_none() {
+        return Some(format!("{} {{}}", path_str));
+    }
 
     let field_iter = fields.into_iter()
         .map(StructLitField::Regular)
         .chain(base.into_iter().map(StructLitField::Base));
 
+    // Foo { a: Foo } - indent is +3, width is -5.
+    let (h_shape, v_shape) = try_opt!(struct_lit_shape(shape, context, path_str.len() + 3, 2));
+
+    let span_lo = |item: &StructLitField| match *item {
+        StructLitField::Regular(field) => field.span.lo,
+        StructLitField::Base(expr) => {
+            let last_field_hi = fields.last().map_or(span.lo, |field| field.span.hi);
+            let snippet = context.snippet(mk_sp(last_field_hi, expr.span.lo));
+            let pos = snippet.find_uncommented("..").unwrap();
+            last_field_hi + BytePos(pos as u32)
+        }
+    };
+    let span_hi = |item: &StructLitField| match *item {
+        StructLitField::Regular(field) => field.span.hi,
+        StructLitField::Base(expr) => expr.span.hi,
+    };
+    let rewrite = |item: &StructLitField| match *item {
+        StructLitField::Regular(field) => {
+            // The 1 taken from the v_budget is for the comma.
+            rewrite_field(context, field, try_opt!(v_shape.sub_width(1)))
+        }
+        StructLitField::Base(expr) => {
+            // 2 = ..
+            expr.rewrite(context, try_opt!(v_shape.shrink_left(2))).map(|s| format!("..{}", s))
+        }
+    };
+
     let items = itemize_list(context.codemap,
                              field_iter,
                              "}",
-                             |item| match *item {
-                                 StructLitField::Regular(field) => field.span.lo,
-                                 StructLitField::Base(expr) => {
-        let last_field_hi = fields.last().map_or(span.lo, |field| field.span.hi);
-        let snippet = context.snippet(mk_sp(last_field_hi, expr.span.lo));
-        let pos = snippet.find_uncommented("..").unwrap();
-        last_field_hi + BytePos(pos as u32)
-    }
-                             },
-                             |item| match *item {
-                                 StructLitField::Regular(field) => field.span.hi,
-                                 StructLitField::Base(expr) => expr.span.hi,
-                             },
-                             |item| {
-        match *item {
-            StructLitField::Regular(field) => {
-                // The 1 taken from the v_budget is for the comma.
-                rewrite_field(context, field, try_opt!(v_shape.sub_width(1)))
-            }
-            StructLitField::Base(expr) => {
-                // 2 = ..
-                expr.rewrite(context, try_opt!(v_shape.shrink_left(2))).map(|s| format!("..{}", s))
-            }
-        }
-    },
+                             span_lo,
+                             span_hi,
+                             rewrite,
                              context.codemap.span_after(span, "{"),
                              span.hi);
     let item_vec = items.collect::<Vec<_>>();
 
-    let tactic = if let Some(h_shape) = h_shape {
-        let mut prelim_tactic = match (context.config.struct_lit_style, fields.len()) {
-            (IndentStyle::Visual, 1) => ListTactic::HorizontalVertical,
-            _ => context.config.struct_lit_multiline_style.to_list_tactic(),
-        };
+    let tactic = struct_lit_tactic(h_shape, context, &item_vec);
+    let nested_shape = shape_for_tactic(tactic, h_shape, v_shape);
+    let fmt = struct_lit_formatting(nested_shape, tactic, context, base.is_some());
 
-        if prelim_tactic == ListTactic::HorizontalVertical && fields.len() > 1 {
-            prelim_tactic = ListTactic::LimitedHorizontalVertical(context.config.struct_lit_width);
-        }
-
-        definitive_tactic(&item_vec, prelim_tactic, h_shape.width)
-    } else {
-        DefinitiveListTactic::Vertical
-    };
-
-    let nested_shape = match tactic {
-        DefinitiveListTactic::Horizontal => h_shape.unwrap(),
-        _ => v_shape,
-    };
-
-    let ends_with_newline = context.config.struct_lit_style != IndentStyle::Visual &&
-                            tactic == DefinitiveListTactic::Vertical;
-
-    let fmt = ListFormatting {
-        tactic: tactic,
-        separator: ",",
-        trailing_separator: if base.is_some() {
-            SeparatorTactic::Never
-        } else {
-            context.config.trailing_comma
-        },
-        shape: nested_shape,
-        ends_with_newline: ends_with_newline,
-        config: context.config,
-    };
     let fields_str = try_opt!(write_list(&item_vec, &fmt));
+    let fields_str = if context.config.struct_lit_style == IndentStyle::Block &&
+                        (fields_str.contains('\n') ||
+                         context.config.struct_lit_multiline_style == MultilineStyle::ForceMulti ||
+                         fields_str.len() > h_shape.map(|s| s.width).unwrap_or(0)) {
+        format!("\n{}{}\n{}",
+                v_shape.indent.to_string(context.config),
+                fields_str,
+                shape.indent.to_string(context.config))
+    } else {
+        // One liner or visual indent.
+        format!(" {} ", fields_str)
+    };
 
-    // Empty struct.
-    if fields_str.is_empty() {
-        return Some(format!("{} {{}}", path_str));
-    }
+    Some(format!("{} {{{}}}", path_str, fields_str))
 
-    // One liner or visual indent.
-    if context.config.struct_lit_style == IndentStyle::Visual ||
-       (context.config.struct_lit_multiline_style != MultilineStyle::ForceMulti &&
-        !fields_str.contains('\n') &&
-        fields_str.len() <= h_shape.map(|s| s.width).unwrap_or(0)) {
-        return Some(format!("{} {{ {} }}", path_str, fields_str));
-    }
-
-    // Multiple lines.
-    let inner_indent = v_shape.indent.to_string(context.config);
-    let outer_indent = shape.indent.to_string(context.config);
-    Some(format!("{} {{\n{}{}\n{}}}",
-                 path_str,
-                 inner_indent,
-                 fields_str,
-                 outer_indent))
     // FIXME if context.config.struct_lit_style == Visual, but we run out
     // of space, we should fall back to BlockIndent.
 }
@@ -1996,7 +1956,7 @@ pub fn rewrite_assign_rhs<S: Into<String>>(context: &RewriteContext,
     let max_width = try_opt!(shape.width.checked_sub(last_line_width + 1));
     let rhs = ex.rewrite(context,
                          Shape::offset(max_width,
-                                       shape.indent.block_only(),
+                                       shape.indent,
                                        shape.indent.alignment + last_line_width + 1));
 
     fn count_line_breaks(src: &str) -> usize {
diff --git a/src/items.rs b/src/items.rs
index 69acab70f34..06c5552121f 100644
--- a/src/items.rs
+++ b/src/items.rs
@@ -37,12 +37,11 @@ impl Rewrite for ast::Local {
                shape.width,
                shape.indent);
         let mut result = "let ".to_owned();
-        let pattern_offset = shape.indent + result.len();
-        // 1 = ;
-        let pattern_width = try_opt!(shape.width.checked_sub(pattern_offset.width() + 1));
 
-        let pat_str = try_opt!(self.pat.rewrite(&context,
-                                                Shape::legacy(pattern_width, pattern_offset)));
+        let pat_shape = try_opt!(shape.offset_left(result.len()));
+        // 1 = ;
+        let pat_shape = try_opt!(pat_shape.sub_width(1));
+        let pat_str = try_opt!(self.pat.rewrite(&context, pat_shape));
         result.push_str(&pat_str);
 
         // String that is placed within the assignment pattern and expression.
@@ -71,12 +70,13 @@ impl Rewrite for ast::Local {
 
         if let Some(ref ex) = self.init {
             // 1 = trailing semicolon;
-            let budget = try_opt!(shape.width.checked_sub(shape.indent.block_only().width() + 1));
+            //let budget = try_opt!(shape.width.checked_sub(shape.indent.block_only().width() + 1));
+            let nested_shape = try_opt!(shape.sub_width(1));
 
             result = try_opt!(rewrite_assign_rhs(&context,
                                                  result,
                                                  ex,
-                                                 Shape::legacy(budget, shape.indent.block_only())));
+                                                 nested_shape));
         }
 
         result.push(';');
diff --git a/src/lib.rs b/src/lib.rs
index f37466bebfc..aa93061602e 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -330,6 +330,14 @@ impl Shape {
              })
     }
 
+    pub fn offset_left(&self, width: usize) -> Option<Shape> {
+        Some(Shape {
+                 width: try_opt!(self.width.checked_sub(width)),
+                 indent: self.indent,
+                 offset: self.offset + width,
+             })
+    }
+
     pub fn used_width(&self) -> usize {
         self.indent.block_indent + self.offset
     }
diff --git a/src/lists.rs b/src/lists.rs
index 5c25c8b1cea..2bdb9cee695 100644
--- a/src/lists.rs
+++ b/src/lists.rs
@@ -15,7 +15,8 @@ use syntax::codemap::{self, CodeMap, BytePos};
 
 use {Indent, Shape};
 use comment::{FindUncommented, rewrite_comment, find_comment_end};
-use config::Config;
+use config::{Config, IndentStyle};
+use rewrite::RewriteContext;
 
 #[derive(Eq, PartialEq, Debug, Copy, Clone)]
 /// Formatting tactic for lists. This will be cast down to a
@@ -502,3 +503,81 @@ fn comment_len(comment: Option<&str>) -> usize {
         None => 0,
     }
 }
+
+// Compute horizontal and vertical shapes for a struct-lit-like thing.
+pub fn struct_lit_shape(shape: Shape,
+                        context: &RewriteContext,
+                        prefix_width: usize,
+                        suffix_width: usize)
+                        -> Option<(Option<Shape>, Shape)> {
+    let v_shape = match context.config.struct_lit_style {
+        IndentStyle::Visual => {
+            try_opt!(try_opt!(shape.shrink_left(prefix_width)).sub_width(suffix_width))
+        }
+        IndentStyle::Block => {
+            let shape = shape.block_indent(context.config.tab_spaces);
+            Shape {
+                width: try_opt!(context.config.max_width.checked_sub(shape.indent.width())),
+                ..shape
+            }
+        }
+    };
+    let h_shape = shape.sub_width(prefix_width + suffix_width);
+    Some((h_shape, v_shape))
+}
+
+// Compute the tactic for the internals of a struct-lit-like thing.
+pub fn struct_lit_tactic(h_shape: Option<Shape>,
+                         context: &RewriteContext,
+                         items: &[ListItem])
+                         -> DefinitiveListTactic {
+    if let Some(h_shape) = h_shape {
+        let mut prelim_tactic = match (context.config.struct_lit_style, items.len()) {
+            (IndentStyle::Visual, 1) => ListTactic::HorizontalVertical,
+            _ => context.config.struct_lit_multiline_style.to_list_tactic(),
+        };
+
+        if prelim_tactic == ListTactic::HorizontalVertical && items.len() > 1 {
+            prelim_tactic = ListTactic::LimitedHorizontalVertical(context.config.struct_lit_width);
+        }
+
+        definitive_tactic(items, prelim_tactic, h_shape.width)
+    } else {
+        DefinitiveListTactic::Vertical
+    }
+}
+
+// Given a tactic and possible shapes for horizontal and vertical layout,
+// come up with the actual shape to use.
+pub fn shape_for_tactic(tactic: DefinitiveListTactic,
+                        h_shape: Option<Shape>,
+                        v_shape: Shape)
+                        -> Shape {
+    match tactic {
+        DefinitiveListTactic::Horizontal => h_shape.unwrap(),
+        _ => v_shape,
+    }
+}
+
+// Create a ListFormatting object for formatting the internals of a
+// struct-lit-like thing, that is a series of fields.
+pub fn struct_lit_formatting<'a>(shape: Shape,
+                                 tactic: DefinitiveListTactic,
+                                 context: &'a RewriteContext,
+                                 force_no_trailing_comma: bool)
+                                 -> ListFormatting<'a> {
+    let ends_with_newline = context.config.struct_lit_style != IndentStyle::Visual &&
+                            tactic == DefinitiveListTactic::Vertical;
+    ListFormatting {
+        tactic: tactic,
+        separator: ",",
+        trailing_separator: if force_no_trailing_comma {
+            SeparatorTactic::Never
+        } else {
+            context.config.trailing_comma
+        },
+        shape: shape,
+        ends_with_newline: ends_with_newline,
+        config: context.config,
+    }
+}
diff --git a/src/patterns.rs b/src/patterns.rs
index c1b3de56cfb..18def6bfb64 100644
--- a/src/patterns.rs
+++ b/src/patterns.rs
@@ -10,9 +10,11 @@
 
 use Shape;
 use codemap::SpanUtils;
+use config::{IndentStyle, MultilineStyle};
 use rewrite::{Rewrite, RewriteContext};
 use utils::{wrap_str, format_mutability};
-use lists::{format_item_list, itemize_list, ListItem};
+use lists::{format_item_list, itemize_list, ListItem, struct_lit_shape, struct_lit_tactic,
+            shape_for_tactic, struct_lit_formatting, write_list};
 use expr::{rewrite_unary_prefix, rewrite_pair};
 use types::{rewrite_path, PathContext};
 use super::Spanned;
@@ -112,48 +114,7 @@ impl Rewrite for Pat {
                 wrap_str(result, context.config.max_width, shape)
             }
             PatKind::Struct(ref path, ref fields, elipses) => {
-                let path = try_opt!(rewrite_path(context, PathContext::Expr, None, path, shape));
-
-                let (elipses_str, terminator) = if elipses { (", ..", "..") } else { ("", "}") };
-
-                // 5 = `{` plus space before and after plus `}` plus space before.
-                let budget = try_opt!(shape.width.checked_sub(path.len() + 5 + elipses_str.len()));
-                // FIXME Using visual indenting, should use block or visual to match
-                // struct lit preference (however, in practice I think it is rare
-                // for struct patterns to be multi-line).
-                // 3 = `{` plus space before and after.
-                let offset = shape.indent + path.len() + 3;
-
-                let items =
-                    itemize_list(context.codemap,
-                                 fields.iter(),
-                                 terminator,
-                                 |f| f.span.lo,
-                                 |f| f.span.hi,
-                                 |f| f.node.rewrite(context, Shape::legacy(budget, offset)),
-                                 context.codemap.span_after(self.span, "{"),
-                                 self.span.hi);
-                let mut field_string = try_opt!(format_item_list(items,
-                                                                 Shape::legacy(budget, offset),
-                                                                 context.config));
-                if elipses {
-                    if field_string.contains('\n') {
-                        field_string.push_str(",\n");
-                        field_string.push_str(&offset.to_string(context.config));
-                        field_string.push_str("..");
-                    } else {
-                        if !field_string.is_empty() {
-                            field_string.push_str(", ");
-                        }
-                        field_string.push_str("..");
-                    }
-                }
-
-                if field_string.is_empty() {
-                    Some(format!("{} {{}}", path))
-                } else {
-                    Some(format!("{} {{ {} }}", path, field_string))
-                }
+                rewrite_struct_pat(path, fields, elipses, self.span, context, shape)
             }
             // FIXME(#819) format pattern macros.
             PatKind::Mac(..) => {
@@ -163,6 +124,72 @@ impl Rewrite for Pat {
     }
 }
 
+fn rewrite_struct_pat(path: &ast::Path,
+                      fields: &[codemap::Spanned<ast::FieldPat>],
+                      elipses: bool,
+                      span: Span,
+                      context: &RewriteContext,
+                      shape: Shape)
+                      -> Option<String> {
+    let path_shape = try_opt!(shape.sub_width(2));
+    let path_str = try_opt!(rewrite_path(context, PathContext::Expr, None, path, path_shape));
+
+    if fields.len() == 0 && !elipses {
+        return Some(format!("{} {{}}", path_str));
+    }
+
+    let (elipses_str, terminator) = if elipses { (", ..", "..") } else { ("", "}") };
+
+    // 3 = ` { `, 2 = ` }`.
+    let (h_shape, v_shape) =
+        try_opt!(struct_lit_shape(shape, context, path_str.len() + 3, elipses_str.len() + 2));
+
+    let items = itemize_list(context.codemap,
+                             fields.iter(),
+                             terminator,
+                             |f| f.span.lo,
+                             |f| f.span.hi,
+                             |f| f.node.rewrite(context, v_shape),
+                             context.codemap.span_after(span, "{"),
+                             span.hi);
+    let item_vec = items.collect::<Vec<_>>();
+
+    let tactic = struct_lit_tactic(h_shape, context, &item_vec);
+    let nested_shape = shape_for_tactic(tactic, h_shape, v_shape);
+    let fmt = struct_lit_formatting(nested_shape, tactic, context, false);
+
+    let mut fields_str = try_opt!(write_list(&item_vec, &fmt));
+
+    if elipses {
+        if fields_str.contains('\n') {
+            fields_str.push_str("\n");
+            fields_str.push_str(&nested_shape.indent.to_string(context.config));
+            fields_str.push_str("..");
+        } else {
+            if !fields_str.is_empty() {
+                fields_str.push_str(", ");
+            }
+            fields_str.push_str("..");
+        }
+    }
+
+
+    let fields_str = if context.config.struct_lit_style == IndentStyle::Block &&
+                        (fields_str.contains('\n') ||
+                         context.config.struct_lit_multiline_style == MultilineStyle::ForceMulti ||
+                         fields_str.len() > h_shape.map(|s| s.width).unwrap_or(0)) {
+        format!("\n{}{}\n{}",
+                v_shape.indent.to_string(context.config),
+                fields_str,
+                shape.indent.to_string(context.config))
+    } else {
+        // One liner or visual indent.
+        format!(" {} ", fields_str)
+    };
+
+    Some(format!("{} {{{}}}", path_str, fields_str))
+}
+
 impl Rewrite for FieldPat {
     fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
         let pat = self.pat.rewrite(context, shape);
@@ -176,7 +203,6 @@ impl Rewrite for FieldPat {
     }
 }
 
-
 enum TuplePatField<'a> {
     Pat(&'a ptr::P<ast::Pat>),
     Dotdot(Span),
diff --git a/tests/source/closure.rs b/tests/source/closure.rs
index b95f961405a..c9968a996f4 100644
--- a/tests/source/closure.rs
+++ b/tests/source/closure.rs
@@ -81,3 +81,11 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> {
         }
     }
 }
+
+fn foo() {
+    lifetimes_iter___map(|lasdfasfd| {
+        let hi = if l.bounds.is_empty() {
+            l.lifetime.span.hi
+        };
+    });
+}
diff --git a/tests/target/closure.rs b/tests/target/closure.rs
index a3d9cfe863b..ad6b48aeac9 100644
--- a/tests/target/closure.rs
+++ b/tests/target/closure.rs
@@ -98,3 +98,11 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> {
         }
     }
 }
+
+fn foo() {
+    lifetimes_iter___map(|lasdfasfd| {
+                             let hi = if l.bounds.is_empty() {
+                                 l.lifetime.span.hi
+                             };
+                         });
+}