@@ -1212,12 +1212,14 @@ impl<'a> InferenceContext<'a> {
1212
1212
}
1213
1213
}
1214
1214
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 ) > {
1218
1220
let mut autoderef = Autoderef :: new ( & mut self . table , receiver_ty. clone ( ) ) ;
1219
1221
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, _) | {
1221
1223
let ( field_id, parameters) = match derefed_ty. kind ( Interner ) {
1222
1224
TyKind :: Tuple ( _, substs) => {
1223
1225
return name. as_tuple_index ( ) . and_then ( |idx| {
@@ -1226,6 +1228,7 @@ impl<'a> InferenceContext<'a> {
1226
1228
. get ( idx)
1227
1229
. map ( |a| a. assert_ty_ref ( Interner ) )
1228
1230
. cloned ( )
1231
+ . map ( |ty| ( None , ty) )
1229
1232
} ) ;
1230
1233
}
1231
1234
TyKind :: Adt ( AdtId ( hir_def:: AdtId :: StructId ( s) ) , parameters) => {
@@ -1244,58 +1247,81 @@ impl<'a> InferenceContext<'a> {
1244
1247
. is_visible_from ( self . db . upcast ( ) , self . resolver . module ( ) ) ;
1245
1248
if !is_visible {
1246
1249
if private_field. is_none ( ) {
1247
- private_field = Some ( field_id) ;
1250
+ private_field = Some ( ( field_id, parameters ) ) ;
1248
1251
}
1249
1252
return None ;
1250
1253
}
1251
- // can't have `write_field_resolution` here because `self.table` is borrowed :(
1252
- self . result . field_resolutions . insert ( tgt_expr, field_id) ;
1253
1254
let ty = self . db . field_types ( field_id. parent ) [ field_id. local_id ]
1254
1255
. clone ( )
1255
1256
. substitute ( Interner , & parameters) ;
1256
- Some ( ty )
1257
+ Some ( ( Some ( field_id ) , ty ) )
1257
1258
} ) ;
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?;
1260
1270
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) ;
1262
1274
let ty = self . insert_type_vars ( ty) ;
1263
1275
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
+ }
1264
1298
ty
1265
1299
}
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 = {
1277
1303
let canonicalized_receiver = self . canonicalize ( receiver_ty. clone ( ) ) ;
1278
1304
let traits_in_scope = self . resolver . traits_in_scope ( self . db . upcast ( ) ) ;
1279
1305
1280
- let resolved = method_resolution:: lookup_method (
1306
+ method_resolution:: lookup_method (
1281
1307
self . db ,
1282
1308
& canonicalized_receiver. value ,
1283
1309
self . trait_env . clone ( ) ,
1284
1310
& traits_in_scope,
1285
1311
VisibleFromModule :: Filter ( self . resolver . module ( ) ) ,
1286
1312
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
+ } ) ;
1295
1322
self . err_ty ( )
1296
1323
}
1297
- } ;
1298
- ty
1324
+ }
1299
1325
}
1300
1326
1301
1327
fn infer_method_call (
@@ -1335,11 +1361,30 @@ impl<'a> InferenceContext<'a> {
1335
1361
}
1336
1362
( ty, self . db . value_ty ( func. into ( ) ) , substs)
1337
1363
}
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
+ }
1343
1388
} ;
1344
1389
let method_ty = method_ty. substitute ( Interner , & substs) ;
1345
1390
self . register_obligations_for_call ( & method_ty) ;
0 commit comments