@@ -21,7 +21,6 @@ use crate::errors::{
2121} ;
2222use crate :: type_error_struct;
2323
24- use super :: suggest_call_constructor;
2524use crate :: errors:: { AddressOfTemporaryTaken , ReturnStmtOutsideOfFnBody , StructExprNonExhaustive } ;
2625use rustc_ast as ast;
2726use rustc_data_structures:: fx:: FxHashMap ;
@@ -44,7 +43,7 @@ use rustc_middle::middle::stability;
4443use rustc_middle:: ty:: adjustment:: { Adjust , Adjustment , AllowTwoPhase } ;
4544use rustc_middle:: ty:: error:: TypeError :: FieldMisMatch ;
4645use rustc_middle:: ty:: subst:: SubstsRef ;
47- use rustc_middle:: ty:: { self , AdtKind , DefIdTree , Ty , TypeVisitable } ;
46+ use rustc_middle:: ty:: { self , AdtKind , Ty , TypeVisitable } ;
4847use rustc_session:: parse:: feature_err;
4948use rustc_span:: hygiene:: DesugaringKind ;
5049use rustc_span:: lev_distance:: find_best_match_for_name;
@@ -2141,15 +2140,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
21412140 field : Ident ,
21422141 ) -> Ty < ' tcx > {
21432142 debug ! ( "check_field(expr: {:?}, base: {:?}, field: {:?})" , expr, base, field) ;
2144- let expr_t = self . check_expr ( base) ;
2145- let expr_t = self . structurally_resolved_type ( base. span , expr_t ) ;
2143+ let base_ty = self . check_expr ( base) ;
2144+ let base_ty = self . structurally_resolved_type ( base. span , base_ty ) ;
21462145 let mut private_candidate = None ;
2147- let mut autoderef = self . autoderef ( expr. span , expr_t ) ;
2148- while let Some ( ( base_t , _) ) = autoderef. next ( ) {
2149- debug ! ( "base_t : {:?}" , base_t ) ;
2150- match base_t . kind ( ) {
2146+ let mut autoderef = self . autoderef ( expr. span , base_ty ) ;
2147+ while let Some ( ( deref_base_ty , _) ) = autoderef. next ( ) {
2148+ debug ! ( "deref_base_ty : {:?}" , deref_base_ty ) ;
2149+ match deref_base_ty . kind ( ) {
21512150 ty:: Adt ( base_def, substs) if !base_def. is_enum ( ) => {
2152- debug ! ( "struct named {:?}" , base_t ) ;
2151+ debug ! ( "struct named {:?}" , deref_base_ty ) ;
21532152 let ( ident, def_scope) =
21542153 self . tcx . adjust_ident_and_get_scope ( field, base_def. did ( ) , self . body_id ) ;
21552154 let fields = & base_def. non_enum_variant ( ) . fields ;
@@ -2197,23 +2196,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
21972196 // (#90483) apply adjustments to avoid ExprUseVisitor from
21982197 // creating erroneous projection.
21992198 self . apply_adjustments ( base, adjustments) ;
2200- self . ban_private_field_access ( expr, expr_t , field, did) ;
2199+ self . ban_private_field_access ( expr, base_ty , field, did) ;
22012200 return field_ty;
22022201 }
22032202
22042203 if field. name == kw:: Empty {
2205- } else if self . method_exists ( field, expr_t , expr. hir_id , true ) {
2206- self . ban_take_value_of_method ( expr, expr_t , field) ;
2207- } else if !expr_t . is_primitive_ty ( ) {
2208- self . ban_nonexisting_field ( field, base, expr, expr_t ) ;
2204+ } else if self . method_exists ( field, base_ty , expr. hir_id , true ) {
2205+ self . ban_take_value_of_method ( expr, base_ty , field) ;
2206+ } else if !base_ty . is_primitive_ty ( ) {
2207+ self . ban_nonexisting_field ( field, base, expr, base_ty ) ;
22092208 } else {
22102209 let field_name = field. to_string ( ) ;
22112210 let mut err = type_error_struct ! (
22122211 self . tcx( ) . sess,
22132212 field. span,
2214- expr_t ,
2213+ base_ty ,
22152214 E0610 ,
2216- "`{expr_t }` is a primitive type and therefore doesn't have fields" ,
2215+ "`{base_ty }` is a primitive type and therefore doesn't have fields" ,
22172216 ) ;
22182217 let is_valid_suffix = |field : & str | {
22192218 if field == "f32" || field == "f64" {
@@ -2251,7 +2250,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
22512250 None
22522251 }
22532252 } ;
2254- if let ty:: Infer ( ty:: IntVar ( _) ) = expr_t . kind ( )
2253+ if let ty:: Infer ( ty:: IntVar ( _) ) = base_ty . kind ( )
22552254 && let ExprKind :: Lit ( Spanned {
22562255 node : ast:: LitKind :: Int ( _, ast:: LitIntType :: Unsuffixed ) ,
22572256 ..
@@ -2280,35 +2279,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
22802279 self . tcx ( ) . ty_error ( )
22812280 }
22822281
2283- fn check_call_constructor (
2284- & self ,
2285- err : & mut Diagnostic ,
2286- base : & ' tcx hir:: Expr < ' tcx > ,
2287- def_id : DefId ,
2288- ) {
2289- if let Some ( local_id) = def_id. as_local ( ) {
2290- let hir_id = self . tcx . hir ( ) . local_def_id_to_hir_id ( local_id) ;
2291- let node = self . tcx . hir ( ) . get ( hir_id) ;
2292-
2293- if let Some ( fields) = node. tuple_fields ( ) {
2294- let kind = match self . tcx . opt_def_kind ( local_id) {
2295- Some ( DefKind :: Ctor ( of, _) ) => of,
2296- _ => return ,
2297- } ;
2298-
2299- suggest_call_constructor ( base. span , kind, fields. len ( ) , err) ;
2300- }
2301- } else {
2302- // The logic here isn't smart but `associated_item_def_ids`
2303- // doesn't work nicely on local.
2304- if let DefKind :: Ctor ( of, _) = self . tcx . def_kind ( def_id) {
2305- let parent_def_id = self . tcx . parent ( def_id) ;
2306- let fields = self . tcx . associated_item_def_ids ( parent_def_id) ;
2307- suggest_call_constructor ( base. span , of, fields. len ( ) , err) ;
2308- }
2309- }
2310- }
2311-
23122282 fn suggest_await_on_field_access (
23132283 & self ,
23142284 err : & mut Diagnostic ,
@@ -2351,40 +2321,52 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
23512321
23522322 fn ban_nonexisting_field (
23532323 & self ,
2354- field : Ident ,
2324+ ident : Ident ,
23552325 base : & ' tcx hir:: Expr < ' tcx > ,
23562326 expr : & ' tcx hir:: Expr < ' tcx > ,
2357- expr_t : Ty < ' tcx > ,
2327+ base_ty : Ty < ' tcx > ,
23582328 ) {
23592329 debug ! (
2360- "ban_nonexisting_field: field={:?}, base={:?}, expr={:?}, expr_ty ={:?}" ,
2361- field , base, expr, expr_t
2330+ "ban_nonexisting_field: field={:?}, base={:?}, expr={:?}, base_ty ={:?}" ,
2331+ ident , base, expr, base_ty
23622332 ) ;
2363- let mut err = self . no_such_field_err ( field , expr_t , base. hir_id ) ;
2333+ let mut err = self . no_such_field_err ( ident , base_ty , base. hir_id ) ;
23642334
2365- match * expr_t . peel_refs ( ) . kind ( ) {
2335+ match * base_ty . peel_refs ( ) . kind ( ) {
23662336 ty:: Array ( _, len) => {
2367- self . maybe_suggest_array_indexing ( & mut err, expr, base, field , len) ;
2337+ self . maybe_suggest_array_indexing ( & mut err, expr, base, ident , len) ;
23682338 }
23692339 ty:: RawPtr ( ..) => {
2370- self . suggest_first_deref_field ( & mut err, expr, base, field ) ;
2340+ self . suggest_first_deref_field ( & mut err, expr, base, ident ) ;
23712341 }
23722342 ty:: Adt ( def, _) if !def. is_enum ( ) => {
2373- self . suggest_fields_on_recordish ( & mut err, def, field , expr. span ) ;
2343+ self . suggest_fields_on_recordish ( & mut err, def, ident , expr. span ) ;
23742344 }
23752345 ty:: Param ( param_ty) => {
23762346 self . point_at_param_definition ( & mut err, param_ty) ;
23772347 }
23782348 ty:: Opaque ( _, _) => {
2379- self . suggest_await_on_field_access ( & mut err, field, base, expr_t. peel_refs ( ) ) ;
2380- }
2381- ty:: FnDef ( def_id, _) => {
2382- self . check_call_constructor ( & mut err, base, def_id) ;
2349+ self . suggest_await_on_field_access ( & mut err, ident, base, base_ty. peel_refs ( ) ) ;
23832350 }
23842351 _ => { }
23852352 }
23862353
2387- if field. name == kw:: Await {
2354+ self . suggest_fn_call ( & mut err, base, base_ty, |output_ty| {
2355+ if let ty:: Adt ( def, _) = output_ty. kind ( ) && !def. is_enum ( ) {
2356+ def. non_enum_variant ( ) . fields . iter ( ) . any ( |field| {
2357+ field. ident ( self . tcx ) == ident
2358+ && field. vis . is_accessible_from ( expr. hir_id . owner . to_def_id ( ) , self . tcx )
2359+ } )
2360+ } else if let ty:: Tuple ( tys) = output_ty. kind ( )
2361+ && let Ok ( idx) = ident. as_str ( ) . parse :: < usize > ( )
2362+ {
2363+ idx < tys. len ( )
2364+ } else {
2365+ false
2366+ }
2367+ } ) ;
2368+
2369+ if ident. name == kw:: Await {
23882370 // We know by construction that `<expr>.await` is either on Rust 2015
23892371 // or results in `ExprKind::Await`. Suggest switching the edition to 2018.
23902372 err. note ( "to `.await` a `Future`, switch to Rust 2018 or later" ) ;
0 commit comments