@@ -2692,33 +2692,46 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
2692
2692
None
2693
2693
}
2694
2694
2695
- // Check field access expressions
2695
+ /// Check field access expressions, this works for both structs and tuples.
2696
+ /// Returns the Ty of the field.
2697
+ ///
2698
+ /// ```not_rust
2699
+ /// base.field
2700
+ /// ^^^^^^^^^^ expr
2701
+ /// ^^^^ base
2702
+ /// ^^^^^ field
2703
+ /// ```
2696
2704
fn check_expr_field (
2697
2705
& self ,
2698
2706
expr : & ' tcx hir:: Expr < ' tcx > ,
2699
2707
base : & ' tcx hir:: Expr < ' tcx > ,
2700
2708
field : Ident ,
2709
+ // The expected type hint of the field.
2701
2710
expected : Expectation < ' tcx > ,
2702
2711
) -> Ty < ' tcx > {
2703
2712
debug ! ( "check_field(expr: {:?}, base: {:?}, field: {:?})" , expr, base, field) ;
2704
2713
let base_ty = self . check_expr ( base) ;
2705
2714
let base_ty = self . structurally_resolve_type ( base. span , base_ty) ;
2715
+
2716
+ // Whether we are trying to access a private field. Used for error reporting.
2706
2717
let mut private_candidate = None ;
2718
+
2719
+ // Field expressions automatically deref
2707
2720
let mut autoderef = self . autoderef ( expr. span , base_ty) ;
2708
2721
while let Some ( ( deref_base_ty, _) ) = autoderef. next ( ) {
2709
2722
debug ! ( "deref_base_ty: {:?}" , deref_base_ty) ;
2710
2723
match deref_base_ty. kind ( ) {
2711
2724
ty:: Adt ( base_def, args) if !base_def. is_enum ( ) => {
2712
2725
debug ! ( "struct named {:?}" , deref_base_ty) ;
2713
- let body_hir_id = self . tcx . local_def_id_to_hir_id ( self . body_id ) ;
2714
- let ( ident, def_scope) =
2715
- self . tcx . adjust_ident_and_get_scope ( field, base_def. did ( ) , body_hir_id) ;
2716
-
2717
2726
// we don't care to report errors for a struct if the struct itself is tainted
2718
2727
if let Err ( guar) = base_def. non_enum_variant ( ) . has_errors ( ) {
2719
2728
return Ty :: new_error ( self . tcx ( ) , guar) ;
2720
2729
}
2721
2730
2731
+ let fn_body_hir_id = self . tcx . local_def_id_to_hir_id ( self . body_id ) ;
2732
+ let ( ident, def_scope) =
2733
+ self . tcx . adjust_ident_and_get_scope ( field, base_def. did ( ) , fn_body_hir_id) ;
2734
+
2722
2735
if let Some ( ( idx, field) ) = self . find_adt_field ( * base_def, ident) {
2723
2736
self . write_field_index ( expr. hir_id , idx) ;
2724
2737
@@ -2752,6 +2765,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
2752
2765
_ => { }
2753
2766
}
2754
2767
}
2768
+ // We failed to check the expression, report an error.
2769
+
2770
+ // Emits an error if we deref an infer variable, like calling `.field` on a base type of &_.
2755
2771
self . structurally_resolve_type ( autoderef. span ( ) , autoderef. final_ty ( false ) ) ;
2756
2772
2757
2773
if let Some ( ( adjustments, did) ) = private_candidate {
@@ -2776,6 +2792,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
2776
2792
expr. hir_id ,
2777
2793
expected. only_has_type ( self ) ,
2778
2794
) {
2795
+ // If taking a method instead of calling it
2779
2796
self . ban_take_value_of_method ( expr, base_ty, field)
2780
2797
} else if !base_ty. is_primitive_ty ( ) {
2781
2798
self . ban_nonexisting_field ( field, base, expr, base_ty)
0 commit comments