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