@@ -14,7 +14,7 @@ use rustc::hir::def_id::{DefId};
14
14
use rustc:: infer:: { InferCtxt } ;
15
15
use rustc:: ty:: { self , TyCtxt , ParamEnv } ;
16
16
use rustc:: ty:: maps:: Providers ;
17
- use rustc:: mir:: { AssertMessage , BasicBlock , BorrowKind , Location , Lvalue } ;
17
+ use rustc:: mir:: { AssertMessage , BasicBlock , BorrowKind , Location , Lvalue , Local } ;
18
18
use rustc:: mir:: { Mir , Mutability , Operand , Projection , ProjectionElem , Rvalue } ;
19
19
use rustc:: mir:: { Statement , StatementKind , Terminator , TerminatorKind } ;
20
20
use rustc:: mir:: transform:: { MirSource } ;
@@ -1080,49 +1080,52 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx>
1080
1080
// End-user visible description of `lvalue`
1081
1081
fn describe_lvalue ( & self , lvalue : & Lvalue ) -> String {
1082
1082
let mut buf = String :: new ( ) ;
1083
- self . append_lvalue_to_string ( lvalue, & mut buf) ;
1083
+ self . append_lvalue_to_string ( lvalue, & mut buf, None ) ;
1084
1084
buf
1085
1085
}
1086
1086
1087
1087
// Appends end-user visible description of `lvalue` to `buf`.
1088
- fn append_lvalue_to_string ( & self , lvalue : & Lvalue , buf : & mut String ) {
1088
+ fn append_lvalue_to_string ( & self , lvalue : & Lvalue , buf : & mut String , autoderef : Option < bool > ) {
1089
1089
match * lvalue {
1090
1090
Lvalue :: Local ( local) => {
1091
- let local = & self . mir . local_decls [ local] ;
1092
- match local. name {
1093
- Some ( name) => buf. push_str ( & format ! ( "{}" , name) ) ,
1094
- None => buf. push_str ( "_" ) ,
1095
- }
1091
+ self . append_local_to_string ( local, buf, "_" ) ;
1096
1092
}
1097
1093
Lvalue :: Static ( ref static_) => {
1098
1094
buf. push_str ( & format ! ( "{}" , & self . tcx. item_name( static_. def_id) ) ) ;
1099
1095
}
1100
1096
Lvalue :: Projection ( ref proj) => {
1097
+ let mut autoderef = autoderef. unwrap_or ( false ) ;
1101
1098
let ( prefix, suffix, index_operand) = match proj. elem {
1102
- ProjectionElem :: Deref =>
1103
- ( "(*" , format ! ( ")" ) , None ) ,
1099
+ ProjectionElem :: Deref => {
1100
+ if autoderef {
1101
+ ( "" , format ! ( "" ) , None )
1102
+ } else {
1103
+ ( "(*" , format ! ( ")" ) , None )
1104
+ }
1105
+ } ,
1104
1106
ProjectionElem :: Downcast ( ..) =>
1105
1107
( "" , format ! ( "" ) , None ) , // (dont emit downcast info)
1106
- ProjectionElem :: Field ( field, _ty) =>
1107
- ( "" , format ! ( ".{}" , field. index( ) ) , None ) , // FIXME: report name of field
1108
- ProjectionElem :: Index ( index) =>
1109
- ( "" , format ! ( "" ) , Some ( index) ) ,
1110
- ProjectionElem :: ConstantIndex { offset, min_length, from_end : true } =>
1111
- ( "" , format ! ( "[{} of {}]" , offset, min_length) , None ) ,
1112
- ProjectionElem :: ConstantIndex { offset, min_length, from_end : false } =>
1113
- ( "" , format ! ( "[-{} of {}]" , offset, min_length) , None ) ,
1114
- ProjectionElem :: Subslice { from, to : 0 } =>
1115
- ( "" , format ! ( "[{}:]" , from) , None ) ,
1116
- ProjectionElem :: Subslice { from : 0 , to } =>
1117
- ( "" , format ! ( "[:-{}]" , to) , None ) ,
1118
- ProjectionElem :: Subslice { from, to } =>
1119
- ( "" , format ! ( "[{}:-{}]" , from, to) , None ) ,
1108
+ ProjectionElem :: Field ( field, _ty) => {
1109
+ autoderef = true ;
1110
+ ( "" , format ! ( ".{}" , self . describe_field( & proj. base, field. index( ) ) ) , None )
1111
+ } ,
1112
+ ProjectionElem :: Index ( index) => {
1113
+ autoderef = true ;
1114
+ ( "" , format ! ( "" ) , Some ( index) )
1115
+ } ,
1116
+ ProjectionElem :: ConstantIndex { .. } | ProjectionElem :: Subslice { .. } => {
1117
+ autoderef = true ;
1118
+ // Since it isn't possible to borrow an element on a particular index and
1119
+ // then use another while the borrow is held, don't output indices details
1120
+ // to avoid confusing the end-user
1121
+ ( "" , format ! ( "[..]" ) , None )
1122
+ } ,
1120
1123
} ;
1121
1124
buf. push_str ( prefix) ;
1122
- self . append_lvalue_to_string ( & proj. base , buf) ;
1125
+ self . append_lvalue_to_string ( & proj. base , buf, Some ( autoderef ) ) ;
1123
1126
if let Some ( index) = index_operand {
1124
1127
buf. push_str ( "[" ) ;
1125
- self . append_lvalue_to_string ( & Lvalue :: Local ( index) , buf) ;
1128
+ self . append_local_to_string ( index, buf, ".." ) ;
1126
1129
buf. push_str ( "]" ) ;
1127
1130
} else {
1128
1131
buf. push_str ( & suffix) ;
@@ -1131,6 +1134,77 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx>
1131
1134
}
1132
1135
}
1133
1136
1137
+ // Appends end-user visible description of the `local` lvalue to `buf`. If `local` doesn't have
1138
+ // a name, then `none_string` is appended instead
1139
+ fn append_local_to_string ( & self , local_index : Local , buf : & mut String , none_string : & str ) {
1140
+ let local = & self . mir . local_decls [ local_index] ;
1141
+ match local. name {
1142
+ Some ( name) => buf. push_str ( & format ! ( "{}" , name) ) ,
1143
+ None => buf. push_str ( none_string)
1144
+ }
1145
+ }
1146
+
1147
+ // End-user visible description of the `field_index`nth field of `base`
1148
+ fn describe_field ( & self , base : & Lvalue , field_index : usize ) -> String {
1149
+ match * base {
1150
+ Lvalue :: Local ( local) => {
1151
+ let local = & self . mir . local_decls [ local] ;
1152
+ self . describe_field_from_ty ( & local. ty , field_index)
1153
+ } ,
1154
+ Lvalue :: Static ( ref static_) => {
1155
+ self . describe_field_from_ty ( & static_. ty , field_index)
1156
+ } ,
1157
+ Lvalue :: Projection ( ref proj) => {
1158
+ match proj. elem {
1159
+ ProjectionElem :: Deref =>
1160
+ self . describe_field ( & proj. base , field_index) ,
1161
+ ProjectionElem :: Downcast ( def, variant_index) =>
1162
+ format ! ( "{}" , def. variants[ variant_index] . fields[ field_index] . name) ,
1163
+ ProjectionElem :: Field ( _, field_type) =>
1164
+ self . describe_field_from_ty ( & field_type, field_index) ,
1165
+ ProjectionElem :: Index ( ..)
1166
+ | ProjectionElem :: ConstantIndex { .. }
1167
+ | ProjectionElem :: Subslice { .. } =>
1168
+ format ! ( "{}" , self . describe_field( & proj. base, field_index) ) ,
1169
+ }
1170
+ }
1171
+ }
1172
+ }
1173
+
1174
+ // End-user visible description of the `field_index`nth field of `ty`
1175
+ fn describe_field_from_ty ( & self , ty : & ty:: Ty , field_index : usize ) -> String {
1176
+ if ty. is_box ( ) {
1177
+ // If the type is a box, the field is described from the boxed type
1178
+ self . describe_field_from_ty ( & ty. boxed_ty ( ) , field_index)
1179
+ }
1180
+ else {
1181
+ match ty. sty {
1182
+ ty:: TyAdt ( def, _) => {
1183
+ if def. is_enum ( ) {
1184
+ format ! ( "{}" , field_index)
1185
+ }
1186
+ else {
1187
+ format ! ( "{}" , def. struct_variant( ) . fields[ field_index] . name)
1188
+ }
1189
+ } ,
1190
+ ty:: TyTuple ( _, _) => {
1191
+ format ! ( "{}" , field_index)
1192
+ } ,
1193
+ ty:: TyRef ( _, tnm) | ty:: TyRawPtr ( tnm) => {
1194
+ self . describe_field_from_ty ( & tnm. ty , field_index)
1195
+ } ,
1196
+ ty:: TyArray ( ty, _) | ty:: TySlice ( ty) => {
1197
+ self . describe_field_from_ty ( & ty, field_index)
1198
+ }
1199
+ _ => {
1200
+ // Might need a revision when the fields in trait RFC is implemented
1201
+ // (https://github.com/rust-lang/rfcs/pull/1546)
1202
+ bug ! ( "End-user description not implemented for field access on `{:?}`" , ty. sty) ;
1203
+ }
1204
+ }
1205
+ }
1206
+ }
1207
+
1134
1208
// Retrieve span of given borrow from the current MIR representation
1135
1209
fn retrieve_borrow_span ( & self , borrow : & BorrowData ) -> Span {
1136
1210
self . mir . source_info ( borrow. location ) . span
0 commit comments