@@ -16,6 +16,7 @@ use rustc_ast_pretty::pprust;
16
16
use rustc_errors:: { Applicability , DiagnosticBuilder , PResult } ;
17
17
use rustc_span:: source_map:: { self , Span , Spanned } ;
18
18
use rustc_span:: symbol:: { kw, sym, Ident , Symbol } ;
19
+ use rustc_span:: { BytePos , Pos } ;
19
20
use std:: mem;
20
21
use tracing:: debug;
21
22
@@ -839,9 +840,10 @@ impl<'a> Parser<'a> {
839
840
}
840
841
use FloatComponent :: * ;
841
842
843
+ let float_str = float. as_str ( ) ;
842
844
let mut components = Vec :: new ( ) ;
843
845
let mut ident_like = String :: new ( ) ;
844
- for c in float . as_str ( ) . chars ( ) {
846
+ for c in float_str . chars ( ) {
845
847
if c == '_' || c. is_ascii_alphanumeric ( ) {
846
848
ident_like. push ( c) ;
847
849
} else if matches ! ( c, '.' | '+' | '-' ) {
@@ -857,30 +859,54 @@ impl<'a> Parser<'a> {
857
859
components. push ( IdentLike ( ident_like) ) ;
858
860
}
859
861
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.
861
865
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
+
862
869
match & * components {
863
870
// 1e2
864
871
[ IdentLike ( i) ] => {
865
872
self . parse_tuple_field_access_expr ( lo, base, Symbol :: intern ( & i) , suffix, None )
866
873
}
867
874
// 1.
868
875
[ 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
+ } ;
869
884
assert ! ( suffix. is_none( ) ) ;
870
885
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 ) ;
873
888
self . parse_tuple_field_access_expr ( lo, base, symbol, None , Some ( next_token) )
874
889
}
875
890
// 1.2 | 1.2e3
876
891
[ 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
+ } ;
877
903
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 ) ;
880
906
let base1 =
881
907
self . parse_tuple_field_access_expr ( lo, base, symbol1, None , Some ( next_token1) ) ;
882
908
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 ) ;
884
910
self . bump_with ( next_token2) ; // `.`
885
911
self . parse_tuple_field_access_expr ( lo, base1, symbol2, suffix, None )
886
912
}
0 commit comments