@@ -24,6 +24,7 @@ use syntax::source_map::Span;
24
24
use syntax:: util:: lev_distance:: find_best_match_for_name;
25
25
use rustc:: hir;
26
26
use rustc:: hir:: { ExprKind , QPath } ;
27
+ use rustc:: hir:: def_id:: DefId ;
27
28
use rustc:: hir:: def:: { CtorKind , Res , DefKind } ;
28
29
use rustc:: hir:: ptr:: P ;
29
30
use rustc:: infer;
@@ -1336,116 +1337,182 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1336
1337
autoderef. unambiguous_final_ty ( self ) ;
1337
1338
1338
1339
if let Some ( ( did, field_ty) ) = private_candidate {
1339
- let struct_path = self . tcx ( ) . def_path_str ( did) ;
1340
- let mut err = struct_span_err ! ( self . tcx( ) . sess, expr. span, E0616 ,
1341
- "field `{}` of struct `{}` is private" ,
1342
- field, struct_path) ;
1343
- // Also check if an accessible method exists, which is often what is meant.
1344
- if self . method_exists ( field, expr_t, expr. hir_id , false )
1345
- && !self . expr_in_place ( expr. hir_id )
1346
- {
1347
- self . suggest_method_call (
1348
- & mut err,
1349
- & format ! ( "a method `{}` also exists, call it with parentheses" , field) ,
1350
- field,
1351
- expr_t,
1352
- expr. hir_id ,
1353
- ) ;
1354
- }
1355
- err. emit ( ) ;
1356
- field_ty
1357
- } else if field. name == kw:: Invalid {
1358
- self . tcx ( ) . types . err
1340
+ self . ban_private_field_access ( expr, expr_t, field, did) ;
1341
+ return field_ty;
1342
+ }
1343
+
1344
+ if field. name == kw:: Invalid {
1359
1345
} else if self . method_exists ( field, expr_t, expr. hir_id , true ) {
1360
- let mut err = type_error_struct ! ( self . tcx( ) . sess, field. span, expr_t, E0615 ,
1361
- "attempted to take value of method `{}` on type `{}`" ,
1362
- field, expr_t) ;
1363
-
1364
- if !self . expr_in_place ( expr. hir_id ) {
1365
- self . suggest_method_call (
1366
- & mut err,
1367
- "use parentheses to call the method" ,
1368
- field,
1369
- expr_t,
1370
- expr. hir_id
1371
- ) ;
1372
- } else {
1373
- err. help ( "methods are immutable and cannot be assigned to" ) ;
1346
+ self . ban_take_value_of_method ( expr, expr_t, field) ;
1347
+ } else if !expr_t. is_primitive_ty ( ) {
1348
+ let mut err = self . no_such_field_err ( field. span , field, expr_t) ;
1349
+
1350
+ match expr_t. sty {
1351
+ ty:: Adt ( def, _) if !def. is_enum ( ) => {
1352
+ self . suggest_fields_on_recordish ( & mut err, def, field) ;
1353
+ }
1354
+ ty:: Array ( _, len) => {
1355
+ self . maybe_suggest_array_indexing ( & mut err, expr, base, field, len) ;
1356
+ }
1357
+ ty:: RawPtr ( ..) => {
1358
+ self . suggest_first_deref_field ( & mut err, expr, base, field) ;
1359
+ }
1360
+ _ => { }
1361
+ }
1362
+
1363
+ if field. name == kw:: Await {
1364
+ // We know by construction that `<expr>.await` is either on Rust 2015
1365
+ // or results in `ExprKind::Await`. Suggest switching the edition to 2018.
1366
+ err. note ( "to `.await` a `Future`, switch to Rust 2018" ) ;
1367
+ err. help ( "set `edition = \" 2018\" ` in `Cargo.toml`" ) ;
1368
+ err. note ( "for more on editions, read https://doc.rust-lang.org/edition-guide" ) ;
1374
1369
}
1375
1370
1376
1371
err. emit ( ) ;
1377
- self . tcx ( ) . types . err
1378
1372
} else {
1379
- if !expr_t. is_primitive_ty ( ) {
1380
- let mut err = self . no_such_field_err ( field. span , field, expr_t) ;
1381
-
1382
- match expr_t. sty {
1383
- ty:: Adt ( def, _) if !def. is_enum ( ) => {
1384
- if let Some ( suggested_field_name) =
1385
- Self :: suggest_field_name ( def. non_enum_variant ( ) ,
1386
- & field. as_str ( ) , vec ! [ ] ) {
1387
- err. span_suggestion (
1388
- field. span ,
1389
- "a field with a similar name exists" ,
1390
- suggested_field_name. to_string ( ) ,
1391
- Applicability :: MaybeIncorrect ,
1392
- ) ;
1393
- } else {
1394
- err. span_label ( field. span , "unknown field" ) ;
1395
- let struct_variant_def = def. non_enum_variant ( ) ;
1396
- let field_names = self . available_field_names ( struct_variant_def) ;
1397
- if !field_names. is_empty ( ) {
1398
- err. note ( & format ! ( "available fields are: {}" ,
1399
- self . name_series_display( field_names) ) ) ;
1400
- }
1401
- } ;
1402
- }
1403
- ty:: Array ( _, len) => {
1404
- if let ( Some ( len) , Ok ( user_index) ) = (
1405
- len. try_eval_usize ( self . tcx , self . param_env ) ,
1406
- field. as_str ( ) . parse :: < u64 > ( )
1407
- ) {
1408
- let base = self . tcx . sess . source_map ( )
1409
- . span_to_snippet ( base. span )
1410
- . unwrap_or_else ( |_|
1411
- self . tcx . hir ( ) . hir_to_pretty_string ( base. hir_id ) ) ;
1412
- let help = "instead of using tuple indexing, use array indexing" ;
1413
- let suggestion = format ! ( "{}[{}]" , base, field) ;
1414
- let applicability = if len < user_index {
1415
- Applicability :: MachineApplicable
1416
- } else {
1417
- Applicability :: MaybeIncorrect
1418
- } ;
1419
- err. span_suggestion (
1420
- expr. span , help, suggestion, applicability
1421
- ) ;
1422
- }
1423
- }
1424
- ty:: RawPtr ( ..) => {
1425
- let base = self . tcx . sess . source_map ( )
1426
- . span_to_snippet ( base. span )
1427
- . unwrap_or_else ( |_| self . tcx . hir ( ) . hir_to_pretty_string ( base. hir_id ) ) ;
1428
- let msg = format ! ( "`{}` is a raw pointer; try dereferencing it" , base) ;
1429
- let suggestion = format ! ( "(*{}).{}" , base, field) ;
1430
- err. span_suggestion (
1431
- expr. span ,
1432
- & msg,
1433
- suggestion,
1434
- Applicability :: MaybeIncorrect ,
1435
- ) ;
1436
- }
1437
- _ => { }
1438
- }
1439
- err
1373
+ type_error_struct ! (
1374
+ self . tcx( ) . sess,
1375
+ field. span,
1376
+ expr_t,
1377
+ E0610 ,
1378
+ "`{}` is a primitive type and therefore doesn't have fields" ,
1379
+ expr_t
1380
+ )
1381
+ . emit ( ) ;
1382
+ }
1383
+
1384
+ self . tcx ( ) . types . err
1385
+ }
1386
+
1387
+ fn ban_private_field_access (
1388
+ & self ,
1389
+ expr : & hir:: Expr ,
1390
+ expr_t : Ty < ' tcx > ,
1391
+ field : ast:: Ident ,
1392
+ base_did : DefId ,
1393
+ ) {
1394
+ let struct_path = self . tcx ( ) . def_path_str ( base_did) ;
1395
+ let mut err = struct_span_err ! (
1396
+ self . tcx( ) . sess,
1397
+ expr. span,
1398
+ E0616 ,
1399
+ "field `{}` of struct `{}` is private" ,
1400
+ field,
1401
+ struct_path
1402
+ ) ;
1403
+ // Also check if an accessible method exists, which is often what is meant.
1404
+ if self . method_exists ( field, expr_t, expr. hir_id , false )
1405
+ && !self . expr_in_place ( expr. hir_id )
1406
+ {
1407
+ self . suggest_method_call (
1408
+ & mut err,
1409
+ & format ! ( "a method `{}` also exists, call it with parentheses" , field) ,
1410
+ field,
1411
+ expr_t,
1412
+ expr. hir_id ,
1413
+ ) ;
1414
+ }
1415
+ err. emit ( ) ;
1416
+ }
1417
+
1418
+ fn ban_take_value_of_method ( & self , expr : & hir:: Expr , expr_t : Ty < ' tcx > , field : ast:: Ident ) {
1419
+ let mut err = type_error_struct ! (
1420
+ self . tcx( ) . sess,
1421
+ field. span,
1422
+ expr_t,
1423
+ E0615 ,
1424
+ "attempted to take value of method `{}` on type `{}`" ,
1425
+ field,
1426
+ expr_t
1427
+ ) ;
1428
+
1429
+ if !self . expr_in_place ( expr. hir_id ) {
1430
+ self . suggest_method_call (
1431
+ & mut err,
1432
+ "use parentheses to call the method" ,
1433
+ field,
1434
+ expr_t,
1435
+ expr. hir_id
1436
+ ) ;
1437
+ } else {
1438
+ err. help ( "methods are immutable and cannot be assigned to" ) ;
1439
+ }
1440
+
1441
+ err. emit ( ) ;
1442
+ }
1443
+
1444
+ fn suggest_fields_on_recordish (
1445
+ & self ,
1446
+ err : & mut DiagnosticBuilder < ' _ > ,
1447
+ def : & ' tcx ty:: AdtDef ,
1448
+ field : ast:: Ident ,
1449
+ ) {
1450
+ if let Some ( suggested_field_name) =
1451
+ Self :: suggest_field_name ( def. non_enum_variant ( ) , & field. as_str ( ) , vec ! [ ] )
1452
+ {
1453
+ err. span_suggestion (
1454
+ field. span ,
1455
+ "a field with a similar name exists" ,
1456
+ suggested_field_name. to_string ( ) ,
1457
+ Applicability :: MaybeIncorrect ,
1458
+ ) ;
1459
+ } else {
1460
+ err. span_label ( field. span , "unknown field" ) ;
1461
+ let struct_variant_def = def. non_enum_variant ( ) ;
1462
+ let field_names = self . available_field_names ( struct_variant_def) ;
1463
+ if !field_names. is_empty ( ) {
1464
+ err. note ( & format ! ( "available fields are: {}" ,
1465
+ self . name_series_display( field_names) ) ) ;
1466
+ }
1467
+ }
1468
+ }
1469
+
1470
+ fn maybe_suggest_array_indexing (
1471
+ & self ,
1472
+ err : & mut DiagnosticBuilder < ' _ > ,
1473
+ expr : & hir:: Expr ,
1474
+ base : & hir:: Expr ,
1475
+ field : ast:: Ident ,
1476
+ len : & ty:: Const < ' tcx > ,
1477
+ ) {
1478
+ if let ( Some ( len) , Ok ( user_index) ) = (
1479
+ len. try_eval_usize ( self . tcx , self . param_env ) ,
1480
+ field. as_str ( ) . parse :: < u64 > ( )
1481
+ ) {
1482
+ let base = self . tcx . sess . source_map ( )
1483
+ . span_to_snippet ( base. span )
1484
+ . unwrap_or_else ( |_| self . tcx . hir ( ) . hir_to_pretty_string ( base. hir_id ) ) ;
1485
+ let help = "instead of using tuple indexing, use array indexing" ;
1486
+ let suggestion = format ! ( "{}[{}]" , base, field) ;
1487
+ let applicability = if len < user_index {
1488
+ Applicability :: MachineApplicable
1440
1489
} else {
1441
- type_error_struct ! ( self . tcx( ) . sess, field. span, expr_t, E0610 ,
1442
- "`{}` is a primitive type and therefore doesn't have fields" ,
1443
- expr_t)
1444
- } . emit ( ) ;
1445
- self . tcx ( ) . types . err
1490
+ Applicability :: MaybeIncorrect
1491
+ } ;
1492
+ err. span_suggestion ( expr. span , help, suggestion, applicability) ;
1446
1493
}
1447
1494
}
1448
1495
1496
+ fn suggest_first_deref_field (
1497
+ & self ,
1498
+ err : & mut DiagnosticBuilder < ' _ > ,
1499
+ expr : & hir:: Expr ,
1500
+ base : & hir:: Expr ,
1501
+ field : ast:: Ident ,
1502
+ ) {
1503
+ let base = self . tcx . sess . source_map ( )
1504
+ . span_to_snippet ( base. span )
1505
+ . unwrap_or_else ( |_| self . tcx . hir ( ) . hir_to_pretty_string ( base. hir_id ) ) ;
1506
+ let msg = format ! ( "`{}` is a raw pointer; try dereferencing it" , base) ;
1507
+ let suggestion = format ! ( "(*{}).{}" , base, field) ;
1508
+ err. span_suggestion (
1509
+ expr. span ,
1510
+ & msg,
1511
+ suggestion,
1512
+ Applicability :: MaybeIncorrect ,
1513
+ ) ;
1514
+ }
1515
+
1449
1516
fn no_such_field_err < T : Display > ( & self , span : Span , field : T , expr_t : & ty:: TyS < ' _ > )
1450
1517
-> DiagnosticBuilder < ' _ > {
1451
1518
type_error_struct ! ( self . tcx( ) . sess, span, expr_t, E0609 ,
0 commit comments