@@ -16,6 +16,7 @@ use rustc_ast_pretty::pprust;
1616use rustc_errors:: { Applicability , DiagnosticBuilder , PResult } ;
1717use rustc_span:: source_map:: { self , Span , Spanned } ;
1818use rustc_span:: symbol:: { kw, sym, Ident , Symbol } ;
19+ use rustc_span:: { BytePos , Pos } ;
1920use std:: mem;
2021use tracing:: debug;
2122
@@ -839,9 +840,10 @@ impl<'a> Parser<'a> {
839840 }
840841 use FloatComponent :: * ;
841842
843+ let float_str = float. as_str ( ) ;
842844 let mut components = Vec :: new ( ) ;
843845 let mut ident_like = String :: new ( ) ;
844- for c in float . as_str ( ) . chars ( ) {
846+ for c in float_str . chars ( ) {
845847 if c == '_' || c. is_ascii_alphanumeric ( ) {
846848 ident_like. push ( c) ;
847849 } else if matches ! ( c, '.' | '+' | '-' ) {
@@ -857,30 +859,54 @@ impl<'a> Parser<'a> {
857859 components. push ( IdentLike ( ident_like) ) ;
858860 }
859861
860- // FIXME: Make the span more precise.
862+ // With proc macros the span can refer to anything, the source may be too short,
863+ // or too long, or non-ASCII. It only makes sense to break our span into components
864+ // if its underlying text is identical to our float literal.
861865 let span = self . token . span ;
866+ let can_take_span_apart =
867+ || self . span_to_snippet ( span) . as_deref ( ) == Ok ( float_str) . as_deref ( ) ;
868+
862869 match & * components {
863870 // 1e2
864871 [ IdentLike ( i) ] => {
865872 self . parse_tuple_field_access_expr ( lo, base, Symbol :: intern ( & i) , suffix, None )
866873 }
867874 // 1.
868875 [ IdentLike ( i) , Punct ( '.' ) ] => {
876+ let ( ident_span, dot_span) = if can_take_span_apart ( ) {
877+ let ( span, ident_len) = ( span. data ( ) , BytePos :: from_usize ( i. len ( ) ) ) ;
878+ let ident_span = span. with_hi ( span. lo + ident_len) ;
879+ let dot_span = span. with_lo ( span. lo + ident_len) ;
880+ ( ident_span, dot_span)
881+ } else {
882+ ( span, span)
883+ } ;
869884 assert ! ( suffix. is_none( ) ) ;
870885 let symbol = Symbol :: intern ( & i) ;
871- self . token = Token :: new ( token:: Ident ( symbol, false ) , span ) ;
872- let next_token = Token :: new ( token:: Dot , span ) ;
886+ self . token = Token :: new ( token:: Ident ( symbol, false ) , ident_span ) ;
887+ let next_token = Token :: new ( token:: Dot , dot_span ) ;
873888 self . parse_tuple_field_access_expr ( lo, base, symbol, None , Some ( next_token) )
874889 }
875890 // 1.2 | 1.2e3
876891 [ IdentLike ( i1) , Punct ( '.' ) , IdentLike ( i2) ] => {
892+ let ( ident1_span, dot_span, ident2_span) = if can_take_span_apart ( ) {
893+ let ( span, ident1_len) = ( span. data ( ) , BytePos :: from_usize ( i1. len ( ) ) ) ;
894+ let ident1_span = span. with_hi ( span. lo + ident1_len) ;
895+ let dot_span = span
896+ . with_lo ( span. lo + ident1_len)
897+ . with_hi ( span. lo + ident1_len + BytePos ( 1 ) ) ;
898+ let ident2_span = self . token . span . with_lo ( span. lo + ident1_len + BytePos ( 1 ) ) ;
899+ ( ident1_span, dot_span, ident2_span)
900+ } else {
901+ ( span, span, span)
902+ } ;
877903 let symbol1 = Symbol :: intern ( & i1) ;
878- self . token = Token :: new ( token:: Ident ( symbol1, false ) , span ) ;
879- let next_token1 = Token :: new ( token:: Dot , span ) ;
904+ self . token = Token :: new ( token:: Ident ( symbol1, false ) , ident1_span ) ;
905+ let next_token1 = Token :: new ( token:: Dot , dot_span ) ;
880906 let base1 =
881907 self . parse_tuple_field_access_expr ( lo, base, symbol1, None , Some ( next_token1) ) ;
882908 let symbol2 = Symbol :: intern ( & i2) ;
883- let next_token2 = Token :: new ( token:: Ident ( symbol2, false ) , span ) ;
909+ let next_token2 = Token :: new ( token:: Ident ( symbol2, false ) , ident2_span ) ;
884910 self . bump_with ( next_token2) ; // `.`
885911 self . parse_tuple_field_access_expr ( lo, base1, symbol2, suffix, None )
886912 }
0 commit comments