@@ -1212,12 +1212,14 @@ impl<'a> InferenceContext<'a> {
12121212 }
12131213 }
12141214
1215- fn infer_field_access ( & mut self , tgt_expr : ExprId , expr : ExprId , name : & Name ) -> Ty {
1216- let receiver_ty = self . infer_expr_inner ( expr, & Expectation :: none ( ) ) ;
1217-
1215+ fn lookup_field (
1216+ & mut self ,
1217+ receiver_ty : & Ty ,
1218+ name : & Name ,
1219+ ) -> Option < ( Ty , Option < FieldId > , Vec < Adjustment > , bool ) > {
12181220 let mut autoderef = Autoderef :: new ( & mut self . table , receiver_ty. clone ( ) ) ;
12191221 let mut private_field = None ;
1220- let ty = autoderef. by_ref ( ) . find_map ( |( derefed_ty, _) | {
1222+ let res = autoderef. by_ref ( ) . find_map ( |( derefed_ty, _) | {
12211223 let ( field_id, parameters) = match derefed_ty. kind ( Interner ) {
12221224 TyKind :: Tuple ( _, substs) => {
12231225 return name. as_tuple_index ( ) . and_then ( |idx| {
@@ -1226,6 +1228,7 @@ impl<'a> InferenceContext<'a> {
12261228 . get ( idx)
12271229 . map ( |a| a. assert_ty_ref ( Interner ) )
12281230 . cloned ( )
1231+ . map ( |ty| ( None , ty) )
12291232 } ) ;
12301233 }
12311234 TyKind :: Adt ( AdtId ( hir_def:: AdtId :: StructId ( s) ) , parameters) => {
@@ -1244,58 +1247,81 @@ impl<'a> InferenceContext<'a> {
12441247 . is_visible_from ( self . db . upcast ( ) , self . resolver . module ( ) ) ;
12451248 if !is_visible {
12461249 if private_field. is_none ( ) {
1247- private_field = Some ( field_id) ;
1250+ private_field = Some ( ( field_id, parameters ) ) ;
12481251 }
12491252 return None ;
12501253 }
1251- // can't have `write_field_resolution` here because `self.table` is borrowed :(
1252- self . result . field_resolutions . insert ( tgt_expr, field_id) ;
12531254 let ty = self . db . field_types ( field_id. parent ) [ field_id. local_id ]
12541255 . clone ( )
12551256 . substitute ( Interner , & parameters) ;
1256- Some ( ty )
1257+ Some ( ( Some ( field_id ) , ty ) )
12571258 } ) ;
1258- let ty = match ty {
1259- Some ( ty) => {
1259+
1260+ Some ( match res {
1261+ Some ( ( field_id, ty) ) => {
1262+ let adjustments = auto_deref_adjust_steps ( & autoderef) ;
1263+ let ty = self . insert_type_vars ( ty) ;
1264+ let ty = self . normalize_associated_types_in ( ty) ;
1265+
1266+ ( ty, field_id, adjustments, true )
1267+ }
1268+ None => {
1269+ let ( field_id, subst) = private_field?;
12601270 let adjustments = auto_deref_adjust_steps ( & autoderef) ;
1261- self . write_expr_adj ( expr, adjustments) ;
1271+ let ty = self . db . field_types ( field_id. parent ) [ field_id. local_id ]
1272+ . clone ( )
1273+ . substitute ( Interner , & subst) ;
12621274 let ty = self . insert_type_vars ( ty) ;
12631275 let ty = self . normalize_associated_types_in ( ty) ;
1276+
1277+ ( ty, Some ( field_id) , adjustments, false )
1278+ }
1279+ } )
1280+ }
1281+
1282+ fn infer_field_access ( & mut self , tgt_expr : ExprId , receiver : ExprId , name : & Name ) -> Ty {
1283+ let receiver_ty = self . infer_expr_inner ( receiver, & Expectation :: none ( ) ) ;
1284+ match self . lookup_field ( & receiver_ty, name) {
1285+ Some ( ( ty, field_id, adjustments, is_public) ) => {
1286+ self . write_expr_adj ( receiver, adjustments) ;
1287+ if let Some ( field_id) = field_id {
1288+ self . result . field_resolutions . insert ( tgt_expr, field_id) ;
1289+ }
1290+ if !is_public {
1291+ if let Some ( field) = field_id {
1292+ // FIXME: Merge this diagnostic into UnresolvedField?
1293+ self . result
1294+ . diagnostics
1295+ . push ( InferenceDiagnostic :: PrivateField { expr : tgt_expr, field } ) ;
1296+ }
1297+ }
12641298 ty
12651299 }
1266- _ => {
1267- // Write down the first private field resolution if we found no field
1268- // This aids IDE features for private fields like goto def
1269- if let Some ( field) = private_field {
1270- self . result . field_resolutions . insert ( tgt_expr, field) ;
1271- // FIXME: Merge this diagnostic into UnresolvedField
1272- self . result
1273- . diagnostics
1274- . push ( InferenceDiagnostic :: PrivateField { expr : tgt_expr, field } ) ;
1275- } else {
1276- // no field found, try looking for a method of the same name
1300+ None => {
1301+ // no field found,
1302+ let method_with_same_name_exists = {
12771303 let canonicalized_receiver = self . canonicalize ( receiver_ty. clone ( ) ) ;
12781304 let traits_in_scope = self . resolver . traits_in_scope ( self . db . upcast ( ) ) ;
12791305
1280- let resolved = method_resolution:: lookup_method (
1306+ method_resolution:: lookup_method (
12811307 self . db ,
12821308 & canonicalized_receiver. value ,
12831309 self . trait_env . clone ( ) ,
12841310 & traits_in_scope,
12851311 VisibleFromModule :: Filter ( self . resolver . module ( ) ) ,
12861312 name,
1287- ) ;
1288- self . result . diagnostics . push ( InferenceDiagnostic :: UnresolvedField {
1289- expr : tgt_expr,
1290- receiver : receiver_ty,
1291- name : name. clone ( ) ,
1292- method_with_same_name_exists : resolved. is_some ( ) ,
1293- } ) ;
1294- }
1313+ )
1314+ . is_some ( )
1315+ } ;
1316+ self . result . diagnostics . push ( InferenceDiagnostic :: UnresolvedField {
1317+ expr : tgt_expr,
1318+ receiver : receiver_ty,
1319+ name : name. clone ( ) ,
1320+ method_with_same_name_exists,
1321+ } ) ;
12951322 self . err_ty ( )
12961323 }
1297- } ;
1298- ty
1324+ }
12991325 }
13001326
13011327 fn infer_method_call (
@@ -1335,11 +1361,30 @@ impl<'a> InferenceContext<'a> {
13351361 }
13361362 ( ty, self . db . value_ty ( func. into ( ) ) , substs)
13371363 }
1338- None => (
1339- receiver_ty,
1340- Binders :: empty ( Interner , self . err_ty ( ) ) ,
1341- Substitution :: empty ( Interner ) ,
1342- ) ,
1364+ None => {
1365+ let field_with_same_name_exists = match self . lookup_field ( & receiver_ty, method_name)
1366+ {
1367+ Some ( ( ty, field_id, adjustments, _public) ) => {
1368+ self . write_expr_adj ( receiver, adjustments) ;
1369+ if let Some ( field_id) = field_id {
1370+ self . result . field_resolutions . insert ( tgt_expr, field_id) ;
1371+ }
1372+ Some ( ty)
1373+ }
1374+ None => None ,
1375+ } ;
1376+ self . result . diagnostics . push ( InferenceDiagnostic :: UnresolvedMethodCall {
1377+ expr : tgt_expr,
1378+ receiver : receiver_ty. clone ( ) ,
1379+ name : method_name. clone ( ) ,
1380+ field_with_same_name : field_with_same_name_exists,
1381+ } ) ;
1382+ (
1383+ receiver_ty,
1384+ Binders :: empty ( Interner , self . err_ty ( ) ) ,
1385+ Substitution :: empty ( Interner ) ,
1386+ )
1387+ }
13431388 } ;
13441389 let method_ty = method_ty. substitute ( Interner , & substs) ;
13451390 self . register_obligations_for_call ( & method_ty) ;
0 commit comments