22// Exceptions. See /LICENSE for license information.
33// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
44
5- use crate :: liberate_and_deanonymize_late_bound_regions;
5+ use crate :: { liberate_and_deanonymize_late_bound_regions, matches_qualified_name } ;
66use arc_anyhow:: { anyhow, bail, ensure, Result } ;
77use database:: BindingsGenerator ;
88use rustc_infer:: infer:: { InferCtxt , RegionVariableOrigin } ;
99use rustc_infer:: traits:: { Obligation , ObligationCause } ;
1010use rustc_middle:: ty:: { self , Ty , TyCtxt } ;
1111use rustc_span:: def_id:: DefId ;
12- use rustc_span:: symbol:: sym;
12+ use rustc_span:: symbol:: { sym, Symbol } ;
1313use rustc_trait_selection:: infer:: canonical:: ir:: TypingMode ;
1414use rustc_trait_selection:: infer:: TyCtxtInferExt ;
1515use rustc_trait_selection:: traits:: ObligationCtxt ;
@@ -36,6 +36,15 @@ pub fn get_generic_args<'tcx>(
3636 finder. generic_param_indices
3737 } ;
3838
39+ let params_used_in_return_type = {
40+ let mut finder = GenericParamsFinder :: default ( ) ;
41+ let fn_sig = tcx. fn_sig ( fn_def_id) . instantiate_identity ( ) ;
42+ let fn_sig = liberate_and_deanonymize_late_bound_regions ( tcx, fn_sig, fn_def_id) ;
43+ use rustc_type_ir:: TypeVisitable ;
44+ fn_sig. output ( ) . visit_with ( & mut finder) ;
45+ finder. generic_param_indices
46+ } ;
47+
3948 let replacements: HashMap < usize , ty:: GenericArg < ' tcx > > = ( 0 ..generics. count ( ) )
4049 . map ( |idx| {
4150 let param_def = generics. param_at ( idx, tcx) ;
@@ -50,14 +59,20 @@ pub fn get_generic_args<'tcx>(
5059 "No support for replacing an _unused_ generic type param: `{}`" ,
5160 param_def. name,
5261 ) ;
53- get_replacement_for_generic_type_param ( tcx, fn_def_id, predicates, param_def)
54- . map ( |ty| ty. into ( ) )
55- . ok_or_else ( || {
56- anyhow ! (
57- "No valid non-generic replacement for generic type param `{}`" ,
58- param_def. name,
59- )
60- } ) ?
62+ get_replacement_for_generic_type_param (
63+ db,
64+ fn_def_id,
65+ predicates,
66+ param_def,
67+ params_used_in_return_type. contains ( & param_def. index ) ,
68+ )
69+ . map ( |ty| ty. into ( ) )
70+ . ok_or_else ( || {
71+ anyhow ! (
72+ "No valid non-generic replacement for generic type param `{}`" ,
73+ param_def. name,
74+ )
75+ } ) ?
6176 }
6277 } ;
6378 Ok ( ( idx, replacement) )
@@ -79,32 +94,97 @@ pub fn get_generic_args<'tcx>(
7994/// If the returned type needs to use a new anonymous lifetime, then it will be generated
8095/// using the given `def_id` as its scope.
8196fn get_replacement_for_trait_predicate < ' tcx > (
82- tcx : TyCtxt < ' tcx > ,
97+ db : & BindingsGenerator < ' tcx > ,
8398 trait_predicate : ty:: TraitPredicate < ' tcx > ,
99+ predicates : ty:: GenericPredicates < ' tcx > ,
84100 new_anon_lifetime : impl Fn ( ) -> ty:: Region < ' tcx > ,
101+ is_used_in_return_type : bool ,
85102) -> Option < Ty < ' tcx > > {
103+ let tcx = db. tcx ( ) ;
86104 if trait_predicate. polarity != ty:: PredicatePolarity :: Positive {
87105 return None ;
88106 }
89107 let trait_ref = trait_predicate. trait_ref ;
90108
91109 // `args[0]` is `Self` / `T`. And when working with `Into<U>`, `AsRef<U>`, etc.
92110 // we typically want the first and only other generic argument - `U`.
93- let ty1 = trait_ref. args . get ( 1 ) . and_then ( |generic_arg| generic_arg. as_type ( ) ) ? ;
111+ let ty1 = trait_ref. args . get ( 1 ) . and_then ( |generic_arg| generic_arg. as_type ( ) ) ;
94112
95113 // `T: Into<U>` => `U`
96114 if tcx. is_diagnostic_item ( sym:: Into , trait_ref. def_id ) {
97- return Some ( ty1) ;
115+ return ty1;
98116 }
99117
100118 // `T: AsRef<U>` => `&U`
101119 if tcx. is_diagnostic_item ( sym:: AsRef , trait_ref. def_id ) {
102- return Some ( Ty :: new_imm_ref ( tcx, new_anon_lifetime ( ) , ty1) ) ;
120+ return Some ( Ty :: new_imm_ref ( tcx, new_anon_lifetime ( ) , ty1? ) ) ;
103121 }
104122
105123 // `T: AsMut<U>` => `&mut U`
106124 if tcx. is_diagnostic_item ( sym:: AsMut , trait_ref. def_id ) {
107- return Some ( Ty :: new_mut_ref ( tcx, new_anon_lifetime ( ) , ty1) ) ;
125+ return Some ( Ty :: new_mut_ref ( tcx, new_anon_lifetime ( ) , ty1?) ) ;
126+ }
127+
128+ // Support for Ctor trait (b/489315162)
129+ if matches_qualified_name ( db, trait_ref. def_id , & [ "ctor" , "Ctor" ] ) {
130+ if is_used_in_return_type {
131+ return None ;
132+ }
133+ // 1. Find the `DefId` of the `Output` associated type in the `Ctor` trait.
134+ let ctor_output_def_id = tcx
135+ . associated_items ( trait_ref. def_id )
136+ . in_definition_order ( )
137+ . find ( |item| {
138+ item. name ( ) == sym:: Output && matches ! ( item. kind, ty:: AssocKind :: Type { .. } )
139+ } )
140+ . map ( |item| item. def_id ) ?;
141+
142+ // 2. Iterate over the predicates and look for projections.
143+ let output_ty = predicates
144+ . predicates
145+ . iter ( )
146+ . filter_map ( |( clause, _) | {
147+ if let ty:: ClauseKind :: Projection ( projection_predicate) =
148+ clause. kind ( ) . skip_binder ( )
149+ {
150+ let projection_term = projection_predicate. projection_term ;
151+ if projection_term. def_id == ctor_output_def_id
152+ && projection_term. self_ty ( ) == trait_ref. self_ty ( )
153+ {
154+ return projection_predicate. term . as_type ( ) ;
155+ }
156+ }
157+ None
158+ } )
159+ . next ( ) ?;
160+
161+ // 3. Find DefIds for CtorNew and RvalueReference
162+ let ctor_crate = trait_ref. def_id . krate ;
163+ let public_paths = db. public_paths_by_def_id ( ctor_crate) ;
164+ let find_by_name = |name : & str | {
165+ let target_symbol = Symbol :: intern ( name) ;
166+ public_paths. iter ( ) . find_map ( |( def_id, paths) | {
167+ if paths. canonical ( ) . name == target_symbol {
168+ Some ( * def_id)
169+ } else {
170+ None
171+ }
172+ } )
173+ } ;
174+ let _ctor_new_def_id = find_by_name ( "CtorNew" ) ?;
175+ let rvalue_ref_def_id = find_by_name ( "RvalueReference" ) ?;
176+
177+ // 4. Construct RvalueReference<'_, Output>
178+ let anon_region = new_anon_lifetime ( ) ;
179+ let rvalue_ref_ty = Ty :: new_adt (
180+ tcx,
181+ tcx. adt_def ( rvalue_ref_def_id) ,
182+ tcx. mk_args ( & [ anon_region. into ( ) , output_ty. into ( ) ] ) ,
183+ ) ;
184+
185+ // TODO(b/489315162): Verify Output: CtorNew<RvalueReference<'_, Output>>
186+
187+ return Some ( rvalue_ref_ty) ;
108188 }
109189
110190 // TODO(b/281542952): Implement other replacements as needed.
@@ -146,11 +226,13 @@ fn is_valid_replacement_for_generic_type_param<'tcx>(
146226/// that may be constraining `T`. When multiple answers are possible, returns
147227/// the first one.
148228fn get_replacement_for_generic_type_param < ' tcx > (
149- tcx : TyCtxt < ' tcx > ,
229+ db : & BindingsGenerator < ' tcx > ,
150230 def_id : DefId ,
151231 predicates : ty:: GenericPredicates < ' tcx > ,
152232 generic_type_param : & ty:: GenericParamDef ,
233+ is_used_in_return_type : bool ,
153234) -> Option < Ty < ' tcx > > {
235+ let tcx = db. tcx ( ) ;
154236 // Look only at trait predicates involving this param (e.g. `T: SomeTrait`).
155237 let trait_predicates_for_this_generic_param = predicates
156238 . predicates
@@ -171,7 +253,13 @@ fn get_replacement_for_generic_type_param<'tcx>(
171253 // Find the first replacement that fits all the constraints.
172254 trait_predicates_for_this_generic_param
173255 . filter_map ( |trait_predicate| {
174- get_replacement_for_trait_predicate ( tcx, trait_predicate, new_anon_lifetime)
256+ get_replacement_for_trait_predicate (
257+ db,
258+ trait_predicate,
259+ predicates,
260+ new_anon_lifetime,
261+ is_used_in_return_type,
262+ )
175263 } )
176264 . find ( |new_ty| {
177265 is_valid_replacement_for_generic_type_param (
0 commit comments