@@ -14,7 +14,7 @@ use rustc::hir::def_id::{DefId};
1414use rustc:: infer:: { InferCtxt } ;
1515use rustc:: ty:: { self , TyCtxt , ParamEnv } ;
1616use rustc:: ty:: maps:: Providers ;
17- use rustc:: mir:: { AssertMessage , BasicBlock , BorrowKind , Location , Lvalue } ;
17+ use rustc:: mir:: { AssertMessage , BasicBlock , BorrowKind , Location , Lvalue , Local } ;
1818use rustc:: mir:: { Mir , Mutability , Operand , Projection , ProjectionElem , Rvalue } ;
1919use rustc:: mir:: { Statement , StatementKind , Terminator , TerminatorKind } ;
2020use rustc:: mir:: transform:: { MirSource } ;
@@ -1080,49 +1080,52 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx>
10801080 // End-user visible description of `lvalue`
10811081 fn describe_lvalue ( & self , lvalue : & Lvalue ) -> String {
10821082 let mut buf = String :: new ( ) ;
1083- self . append_lvalue_to_string ( lvalue, & mut buf) ;
1083+ self . append_lvalue_to_string ( lvalue, & mut buf, None ) ;
10841084 buf
10851085 }
10861086
10871087 // 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 > ) {
10891089 match * lvalue {
10901090 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, "_" ) ;
10961092 }
10971093 Lvalue :: Static ( ref static_) => {
10981094 buf. push_str ( & format ! ( "{}" , & self . tcx. item_name( static_. def_id) ) ) ;
10991095 }
11001096 Lvalue :: Projection ( ref proj) => {
1097+ let mut autoderef = autoderef. unwrap_or ( false ) ;
11011098 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+ } ,
11041106 ProjectionElem :: Downcast ( ..) =>
11051107 ( "" , 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+ } ,
11201123 } ;
11211124 buf. push_str ( prefix) ;
1122- self . append_lvalue_to_string ( & proj. base , buf) ;
1125+ self . append_lvalue_to_string ( & proj. base , buf, Some ( autoderef ) ) ;
11231126 if let Some ( index) = index_operand {
11241127 buf. push_str ( "[" ) ;
1125- self . append_lvalue_to_string ( & Lvalue :: Local ( index) , buf) ;
1128+ self . append_local_to_string ( index, buf, ".." ) ;
11261129 buf. push_str ( "]" ) ;
11271130 } else {
11281131 buf. push_str ( & suffix) ;
@@ -1131,6 +1134,77 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx>
11311134 }
11321135 }
11331136
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+
11341208 // Retrieve span of given borrow from the current MIR representation
11351209 fn retrieve_borrow_span ( & self , borrow : & BorrowData ) -> Span {
11361210 self . mir . source_info ( borrow. location ) . span
0 commit comments