@@ -27,7 +27,10 @@ use rustc_hir::def::{CtorOf, DefKind, Namespace, Res};
27
27
use rustc_hir:: def_id:: { DefId , LocalDefId } ;
28
28
use rustc_hir:: intravisit:: { walk_generics, Visitor as _} ;
29
29
use rustc_hir:: { GenericArg , GenericArgs , OpaqueTyOrigin } ;
30
+ use rustc_infer:: infer:: type_variable:: { TypeVariableOrigin , TypeVariableOriginKind } ;
30
31
use rustc_infer:: infer:: { InferCtxt , TyCtxtInferExt } ;
32
+ use rustc_infer:: traits:: ObligationCause ;
33
+ use rustc_middle:: infer:: unify_key:: { ConstVariableOrigin , ConstVariableOriginKind } ;
31
34
use rustc_middle:: middle:: stability:: AllowUnstable ;
32
35
use rustc_middle:: ty:: subst:: { self , GenericArgKind , InternalSubsts , SubstsRef } ;
33
36
use rustc_middle:: ty:: DynKind ;
@@ -39,12 +42,11 @@ use rustc_span::lev_distance::find_best_match_for_name;
39
42
use rustc_span:: symbol:: { kw, Ident , Symbol } ;
40
43
use rustc_span:: { sym, Span , DUMMY_SP } ;
41
44
use rustc_target:: spec:: abi;
42
- use rustc_trait_selection:: traits;
43
- use rustc_trait_selection:: traits:: astconv_object_safety_violations;
44
45
use rustc_trait_selection:: traits:: error_reporting:: {
45
46
report_object_safety_error, suggestions:: NextTypeParamName ,
46
47
} ;
47
48
use rustc_trait_selection:: traits:: wf:: object_region_bounds;
49
+ use rustc_trait_selection:: traits:: { self , astconv_object_safety_violations, ObligationCtxt } ;
48
50
49
51
use smallvec:: { smallvec, SmallVec } ;
50
52
use std:: collections:: BTreeSet ;
@@ -1944,7 +1946,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
1944
1946
Res :: Err
1945
1947
} ;
1946
1948
1947
- // Check if we have an enum variant.
1949
+ // Check if we have an enum variant or an inherent associated type .
1948
1950
let mut variant_resolution = None ;
1949
1951
if let Some ( adt_def) = self . probe_adt ( span, qself_ty) {
1950
1952
if adt_def. is_enum ( ) {
@@ -2043,23 +2045,15 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
2043
2045
}
2044
2046
}
2045
2047
2046
- // see if we can satisfy using an inherent associated type
2047
- for & impl_ in tcx. inherent_impls ( adt_def. did ( ) ) {
2048
- let Some ( assoc_ty_did) = self . lookup_assoc_ty ( assoc_ident, hir_ref_id, span, impl_) else {
2049
- continue ;
2050
- } ;
2051
- let ty:: Adt ( _, adt_substs) = qself_ty. kind ( ) else {
2052
- // FIXME(inherent_associated_types)
2053
- bug ! ( "unimplemented: non-adt self of inherent assoc ty" ) ;
2054
- } ;
2055
- let item_substs = self . create_substs_for_associated_item (
2056
- span,
2057
- assoc_ty_did,
2058
- assoc_segment,
2059
- adt_substs,
2060
- ) ;
2061
- let ty = tcx. type_of ( assoc_ty_did) . subst ( tcx, item_substs) ;
2062
- return Ok ( ( ty, DefKind :: AssocTy , assoc_ty_did) ) ;
2048
+ if let Some ( ( ty, did) ) = self . lookup_inherent_assoc_ty (
2049
+ assoc_ident,
2050
+ assoc_segment,
2051
+ adt_def. did ( ) ,
2052
+ qself_ty,
2053
+ hir_ref_id,
2054
+ span,
2055
+ ) ? {
2056
+ return Ok ( ( ty, DefKind :: AssocTy , did) ) ;
2063
2057
}
2064
2058
}
2065
2059
@@ -2202,6 +2196,172 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
2202
2196
Ok ( ( ty, DefKind :: AssocTy , assoc_ty_did) )
2203
2197
}
2204
2198
2199
+ fn lookup_inherent_assoc_ty (
2200
+ & self ,
2201
+ name : Ident ,
2202
+ segment : & hir:: PathSegment < ' _ > ,
2203
+ adt_did : DefId ,
2204
+ self_ty : Ty < ' tcx > ,
2205
+ block : hir:: HirId ,
2206
+ span : Span ,
2207
+ ) -> Result < Option < ( Ty < ' tcx > , DefId ) > , ErrorGuaranteed > {
2208
+ let tcx = self . tcx ( ) ;
2209
+
2210
+ let candidates: Vec < _ > = tcx
2211
+ . inherent_impls ( adt_did)
2212
+ . iter ( )
2213
+ . filter_map ( |& impl_| Some ( ( impl_, self . lookup_assoc_ty_unchecked ( name, block, impl_) ?) ) )
2214
+ . collect ( ) ;
2215
+
2216
+ if candidates. is_empty ( ) {
2217
+ return Ok ( None ) ;
2218
+ }
2219
+
2220
+ // In contexts that have no inference context, just make a new one.
2221
+ // We do need a local variable to store it, though.
2222
+ let infcx_;
2223
+ let infcx = match self . infcx ( ) {
2224
+ Some ( infcx) => infcx,
2225
+ None => {
2226
+ assert ! ( !self_ty. needs_infer( ) ) ;
2227
+ infcx_ = tcx. infer_ctxt ( ) . ignoring_regions ( ) . build ( ) ;
2228
+ & infcx_
2229
+ }
2230
+ } ;
2231
+
2232
+ let param_env = tcx. param_env ( block. owner . to_def_id ( ) ) ;
2233
+ let cause = ObligationCause :: misc ( span, block. owner . def_id ) ;
2234
+ let mut fulfillment_errors = Vec :: new ( ) ;
2235
+ let mut applicable_candidates: Vec < _ > = candidates
2236
+ . iter ( )
2237
+ . filter_map ( |& ( impl_, ( assoc_item, def_scope) ) | {
2238
+ infcx. probe ( |_| {
2239
+ let ocx = ObligationCtxt :: new_in_snapshot ( & infcx) ;
2240
+
2241
+ let impl_ty = tcx. type_of ( impl_) ;
2242
+ let impl_substs = infcx. fresh_item_substs ( impl_) ;
2243
+ let impl_ty = impl_ty. subst ( tcx, impl_substs) ;
2244
+ let impl_ty = ocx. normalize ( & cause, param_env, impl_ty) ;
2245
+
2246
+ // Check that the Self-types can be related.
2247
+ // FIXME(fmease): Should we use `eq` here?
2248
+ ocx. sup ( & ObligationCause :: dummy ( ) , param_env, impl_ty, self_ty) . ok ( ) ?;
2249
+
2250
+ // Check whether the impl imposes obligations we have to worry about.
2251
+ let impl_bounds = tcx. predicates_of ( impl_) ;
2252
+ let impl_bounds = impl_bounds. instantiate ( tcx, impl_substs) ;
2253
+
2254
+ let impl_bounds = ocx. normalize ( & cause, param_env, impl_bounds) ;
2255
+
2256
+ let impl_obligations = traits:: predicates_for_generics (
2257
+ |_, _| cause. clone ( ) ,
2258
+ param_env,
2259
+ impl_bounds,
2260
+ ) ;
2261
+
2262
+ ocx. register_obligations ( impl_obligations) ;
2263
+
2264
+ let mut errors = ocx. select_where_possible ( ) ;
2265
+ if !errors. is_empty ( ) {
2266
+ fulfillment_errors. append ( & mut errors) ;
2267
+ return None ;
2268
+ }
2269
+
2270
+ // FIXME(fmease): Unsolved vars can escape this InferCtxt snapshot.
2271
+ Some ( ( assoc_item, def_scope, infcx. resolve_vars_if_possible ( impl_substs) ) )
2272
+ } )
2273
+ } )
2274
+ . collect ( ) ;
2275
+
2276
+ if applicable_candidates. len ( ) > 1 {
2277
+ return Err ( self . complain_about_ambiguous_inherent_assoc_type (
2278
+ name,
2279
+ applicable_candidates. into_iter ( ) . map ( |( candidate, ..) | candidate) . collect ( ) ,
2280
+ span,
2281
+ ) ) ;
2282
+ }
2283
+
2284
+ if let Some ( ( assoc_item, def_scope, impl_substs) ) = applicable_candidates. pop ( ) {
2285
+ self . check_assoc_ty ( assoc_item, name, def_scope, block, span) ;
2286
+
2287
+ // FIXME(inherent_associated_types): To fully *confirm* the *probed* candidate, we still
2288
+ // need to relate the Self-type with fresh item substs & register region obligations for
2289
+ // regionck to prove/disprove.
2290
+
2291
+ let item_substs =
2292
+ self . create_substs_for_associated_item ( span, assoc_item, segment, impl_substs) ;
2293
+
2294
+ // FIXME(fmease, #106722): Check if the bounds on the parameters of the
2295
+ // associated type hold, if any.
2296
+ let ty = tcx. type_of ( assoc_item) . subst ( tcx, item_substs) ;
2297
+
2298
+ return Ok ( Some ( ( ty, assoc_item) ) ) ;
2299
+ }
2300
+
2301
+ Err ( self . complain_about_inherent_assoc_type_not_found (
2302
+ name,
2303
+ self_ty,
2304
+ candidates,
2305
+ fulfillment_errors,
2306
+ span,
2307
+ ) )
2308
+ }
2309
+
2310
+ fn lookup_assoc_ty (
2311
+ & self ,
2312
+ name : Ident ,
2313
+ block : hir:: HirId ,
2314
+ span : Span ,
2315
+ scope : DefId ,
2316
+ ) -> Option < DefId > {
2317
+ let ( item, def_scope) = self . lookup_assoc_ty_unchecked ( name, block, scope) ?;
2318
+ self . check_assoc_ty ( item, name, def_scope, block, span) ;
2319
+ Some ( item)
2320
+ }
2321
+
2322
+ fn lookup_assoc_ty_unchecked (
2323
+ & self ,
2324
+ name : Ident ,
2325
+ block : hir:: HirId ,
2326
+ scope : DefId ,
2327
+ ) -> Option < ( DefId , DefId ) > {
2328
+ let tcx = self . tcx ( ) ;
2329
+ let ( ident, def_scope) = tcx. adjust_ident_and_get_scope ( name, scope, block) ;
2330
+
2331
+ // We have already adjusted the item name above, so compare with `ident.normalize_to_macros_2_0()` instead
2332
+ // of calling `find_by_name_and_kind`.
2333
+ let item = tcx. associated_items ( scope) . in_definition_order ( ) . find ( |i| {
2334
+ i. kind . namespace ( ) == Namespace :: TypeNS
2335
+ && i. ident ( tcx) . normalize_to_macros_2_0 ( ) == ident
2336
+ } ) ?;
2337
+
2338
+ Some ( ( item. def_id , def_scope) )
2339
+ }
2340
+
2341
+ fn check_assoc_ty (
2342
+ & self ,
2343
+ item : DefId ,
2344
+ name : Ident ,
2345
+ def_scope : DefId ,
2346
+ block : hir:: HirId ,
2347
+ span : Span ,
2348
+ ) {
2349
+ let tcx = self . tcx ( ) ;
2350
+ let kind = DefKind :: AssocTy ;
2351
+
2352
+ if !tcx. visibility ( item) . is_accessible_from ( def_scope, tcx) {
2353
+ let kind = kind. descr ( item) ;
2354
+ let msg = format ! ( "{kind} `{name}` is private" ) ;
2355
+ let def_span = tcx. def_span ( item) ;
2356
+ tcx. sess
2357
+ . struct_span_err_with_code ( span, & msg, rustc_errors:: error_code!( E0624 ) )
2358
+ . span_label ( span, & format ! ( "private {kind}" ) )
2359
+ . span_label ( def_span, & format ! ( "{kind} defined here" ) )
2360
+ . emit ( ) ;
2361
+ }
2362
+ tcx. check_stability ( item, Some ( block) , span, None ) ;
2363
+ }
2364
+
2205
2365
fn probe_traits_that_match_assoc_ty (
2206
2366
& self ,
2207
2367
qself_ty : Ty < ' tcx > ,
@@ -2255,39 +2415,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
2255
2415
. collect ( )
2256
2416
}
2257
2417
2258
- fn lookup_assoc_ty (
2259
- & self ,
2260
- ident : Ident ,
2261
- block : hir:: HirId ,
2262
- span : Span ,
2263
- scope : DefId ,
2264
- ) -> Option < DefId > {
2265
- let tcx = self . tcx ( ) ;
2266
- let ( ident, def_scope) = tcx. adjust_ident_and_get_scope ( ident, scope, block) ;
2267
-
2268
- // We have already adjusted the item name above, so compare with `ident.normalize_to_macros_2_0()` instead
2269
- // of calling `find_by_name_and_kind`.
2270
- let item = tcx. associated_items ( scope) . in_definition_order ( ) . find ( |i| {
2271
- i. kind . namespace ( ) == Namespace :: TypeNS
2272
- && i. ident ( tcx) . normalize_to_macros_2_0 ( ) == ident
2273
- } ) ?;
2274
-
2275
- let kind = DefKind :: AssocTy ;
2276
- if !item. visibility ( tcx) . is_accessible_from ( def_scope, tcx) {
2277
- let kind = kind. descr ( item. def_id ) ;
2278
- let msg = format ! ( "{kind} `{ident}` is private" ) ;
2279
- let def_span = self . tcx ( ) . def_span ( item. def_id ) ;
2280
- tcx. sess
2281
- . struct_span_err_with_code ( span, & msg, rustc_errors:: error_code!( E0624 ) )
2282
- . span_label ( span, & format ! ( "private {kind}" ) )
2283
- . span_label ( def_span, & format ! ( "{kind} defined here" ) )
2284
- . emit ( ) ;
2285
- }
2286
- tcx. check_stability ( item. def_id , Some ( block) , span, None ) ;
2287
-
2288
- Some ( item. def_id )
2289
- }
2290
-
2291
2418
fn qpath_to_ty (
2292
2419
& self ,
2293
2420
span : Span ,
@@ -3375,3 +3502,36 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
3375
3502
}
3376
3503
}
3377
3504
}
3505
+
3506
+ pub trait InferCtxtExt < ' tcx > {
3507
+ fn fresh_item_substs ( & self , def_id : DefId ) -> SubstsRef < ' tcx > ;
3508
+ }
3509
+
3510
+ impl < ' tcx > InferCtxtExt < ' tcx > for InferCtxt < ' tcx > {
3511
+ fn fresh_item_substs ( & self , def_id : DefId ) -> SubstsRef < ' tcx > {
3512
+ InternalSubsts :: for_item ( self . tcx , def_id, |param, _| match param. kind {
3513
+ GenericParamDefKind :: Lifetime => self . tcx . lifetimes . re_erased . into ( ) ,
3514
+ GenericParamDefKind :: Type { .. } => self
3515
+ . next_ty_var ( TypeVariableOrigin {
3516
+ kind : TypeVariableOriginKind :: SubstitutionPlaceholder ,
3517
+ span : self . tcx . def_span ( def_id) ,
3518
+ } )
3519
+ . into ( ) ,
3520
+ GenericParamDefKind :: Const { .. } => {
3521
+ let span = self . tcx . def_span ( def_id) ;
3522
+ let origin = ConstVariableOrigin {
3523
+ kind : ConstVariableOriginKind :: SubstitutionPlaceholder ,
3524
+ span,
3525
+ } ;
3526
+ self . next_const_var (
3527
+ self . tcx
3528
+ . type_of ( param. def_id )
3529
+ . no_bound_vars ( )
3530
+ . expect ( "const parameter types cannot be generic" ) ,
3531
+ origin,
3532
+ )
3533
+ . into ( )
3534
+ }
3535
+ } )
3536
+ }
3537
+ }
0 commit comments