@@ -21,7 +21,6 @@ use crate::errors::{
21
21
} ;
22
22
use crate :: type_error_struct;
23
23
24
- use super :: suggest_call_constructor;
25
24
use crate :: errors:: { AddressOfTemporaryTaken , ReturnStmtOutsideOfFnBody , StructExprNonExhaustive } ;
26
25
use rustc_ast as ast;
27
26
use rustc_data_structures:: fx:: FxHashMap ;
@@ -44,7 +43,7 @@ use rustc_middle::middle::stability;
44
43
use rustc_middle:: ty:: adjustment:: { Adjust , Adjustment , AllowTwoPhase } ;
45
44
use rustc_middle:: ty:: error:: TypeError :: FieldMisMatch ;
46
45
use rustc_middle:: ty:: subst:: SubstsRef ;
47
- use rustc_middle:: ty:: { self , AdtKind , DefIdTree , Ty , TypeVisitable } ;
46
+ use rustc_middle:: ty:: { self , AdtKind , Ty , TypeVisitable } ;
48
47
use rustc_session:: parse:: feature_err;
49
48
use rustc_span:: hygiene:: DesugaringKind ;
50
49
use rustc_span:: lev_distance:: find_best_match_for_name;
@@ -2141,15 +2140,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
2141
2140
field : Ident ,
2142
2141
) -> Ty < ' tcx > {
2143
2142
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 ) ;
2146
2145
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 ( ) {
2151
2150
ty:: Adt ( base_def, substs) if !base_def. is_enum ( ) => {
2152
- debug ! ( "struct named {:?}" , base_t ) ;
2151
+ debug ! ( "struct named {:?}" , deref_base_ty ) ;
2153
2152
let ( ident, def_scope) =
2154
2153
self . tcx . adjust_ident_and_get_scope ( field, base_def. did ( ) , self . body_id ) ;
2155
2154
let fields = & base_def. non_enum_variant ( ) . fields ;
@@ -2197,23 +2196,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
2197
2196
// (#90483) apply adjustments to avoid ExprUseVisitor from
2198
2197
// creating erroneous projection.
2199
2198
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) ;
2201
2200
return field_ty;
2202
2201
}
2203
2202
2204
2203
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 ) ;
2209
2208
} else {
2210
2209
let field_name = field. to_string ( ) ;
2211
2210
let mut err = type_error_struct ! (
2212
2211
self . tcx( ) . sess,
2213
2212
field. span,
2214
- expr_t ,
2213
+ base_ty ,
2215
2214
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" ,
2217
2216
) ;
2218
2217
let is_valid_suffix = |field : & str | {
2219
2218
if field == "f32" || field == "f64" {
@@ -2251,7 +2250,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
2251
2250
None
2252
2251
}
2253
2252
} ;
2254
- if let ty:: Infer ( ty:: IntVar ( _) ) = expr_t . kind ( )
2253
+ if let ty:: Infer ( ty:: IntVar ( _) ) = base_ty . kind ( )
2255
2254
&& let ExprKind :: Lit ( Spanned {
2256
2255
node : ast:: LitKind :: Int ( _, ast:: LitIntType :: Unsuffixed ) ,
2257
2256
..
@@ -2280,35 +2279,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
2280
2279
self . tcx ( ) . ty_error ( )
2281
2280
}
2282
2281
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
-
2312
2282
fn suggest_await_on_field_access (
2313
2283
& self ,
2314
2284
err : & mut Diagnostic ,
@@ -2351,40 +2321,52 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
2351
2321
2352
2322
fn ban_nonexisting_field (
2353
2323
& self ,
2354
- field : Ident ,
2324
+ ident : Ident ,
2355
2325
base : & ' tcx hir:: Expr < ' tcx > ,
2356
2326
expr : & ' tcx hir:: Expr < ' tcx > ,
2357
- expr_t : Ty < ' tcx > ,
2327
+ base_ty : Ty < ' tcx > ,
2358
2328
) {
2359
2329
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
2362
2332
) ;
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 ) ;
2364
2334
2365
- match * expr_t . peel_refs ( ) . kind ( ) {
2335
+ match * base_ty . peel_refs ( ) . kind ( ) {
2366
2336
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) ;
2368
2338
}
2369
2339
ty:: RawPtr ( ..) => {
2370
- self . suggest_first_deref_field ( & mut err, expr, base, field ) ;
2340
+ self . suggest_first_deref_field ( & mut err, expr, base, ident ) ;
2371
2341
}
2372
2342
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 ) ;
2374
2344
}
2375
2345
ty:: Param ( param_ty) => {
2376
2346
self . point_at_param_definition ( & mut err, param_ty) ;
2377
2347
}
2378
2348
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 ( ) ) ;
2383
2350
}
2384
2351
_ => { }
2385
2352
}
2386
2353
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 {
2388
2370
// We know by construction that `<expr>.await` is either on Rust 2015
2389
2371
// or results in `ExprKind::Await`. Suggest switching the edition to 2018.
2390
2372
err. note ( "to `.await` a `Future`, switch to Rust 2018 or later" ) ;
0 commit comments