Branch data Line data Source code
1 : : // Copyright (C) 2020-2025 Free Software Foundation, Inc.
2 : :
3 : : // This file is part of GCC.
4 : :
5 : : // GCC is free software; you can redistribute it and/or modify it under
6 : : // the terms of the GNU General Public License as published by the Free
7 : : // Software Foundation; either version 3, or (at your option) any later
8 : : // version.
9 : :
10 : : // GCC is distributed in the hope that it will be useful, but WITHOUT ANY
11 : : // WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 : : // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 : : // for more details.
14 : :
15 : : // You should have received a copy of the GNU General Public License
16 : : // along with GCC; see the file COPYING3. If not see
17 : : // <http://www.gnu.org/licenses/>.
18 : :
19 : : #ifndef RUST_TYTY_SUBST_H
20 : : #define RUST_TYTY_SUBST_H
21 : :
22 : : #include "rust-system.h"
23 : : #include "rust-location.h"
24 : : #include "rust-hir-full-decls.h"
25 : : #include "rust-tyty-bounds.h"
26 : : #include "rust-tyty-region.h"
27 : : #include "rust-ast.h"
28 : : #include "optional.h"
29 : :
30 : : namespace Rust {
31 : : namespace TyTy {
32 : :
33 : : class ParamType;
34 : : class BaseGeneric;
35 : :
36 : 68358892 : struct RegionConstraints
37 : : {
38 : : /** 'a: 'b */
39 : : std::vector<std::pair<Region, Region>> region_region;
40 : : /** T: 'a */
41 : : std::vector<std::pair<ParamType *, Region>> type_region;
42 : : };
43 : :
44 : : class BaseType;
45 : : class SubstitutionArgumentMappings;
46 : : class SubstitutionParamMapping
47 : : {
48 : : public:
49 : : SubstitutionParamMapping (HIR::GenericParam &generic, BaseGeneric *param);
50 : :
51 : : SubstitutionParamMapping (const SubstitutionParamMapping &other);
52 : :
53 : : std::string as_string () const;
54 : :
55 : : bool fill_param_ty (SubstitutionArgumentMappings &subst_mappings,
56 : : location_t locus, bool needs_bounds_check = true);
57 : :
58 : : SubstitutionParamMapping clone () const;
59 : :
60 : : BaseGeneric *get_param_ty ();
61 : : const BaseGeneric *get_param_ty () const;
62 : :
63 : : HIR::GenericParam &get_generic_param ();
64 : : const HIR::GenericParam &get_generic_param () const;
65 : :
66 : : Identifier get_type_representation () const;
67 : :
68 : : // this is used for the backend to override the HirId ref of the param to
69 : : // what the concrete type is for the rest of the context
70 : : void override_context ();
71 : :
72 : : bool needs_substitution () const;
73 : :
74 : : location_t get_param_locus () const;
75 : :
76 : : bool param_has_default_ty () const;
77 : :
78 : : BaseType *get_default_ty () const;
79 : :
80 : : bool need_substitution () const;
81 : :
82 : : private:
83 : : HIR::GenericParam &generic;
84 : : BaseGeneric *param;
85 : : };
86 : :
87 : : /**
88 : : * Represents the part of the parameter list that contains lifetime
89 : : * parameters.
90 : : *
91 : : * ```
92 : : * Foo<'a, 'b, i32, 8>
93 : : * ^^^^^^
94 : : * ```
95 : : *
96 : : * It has fixed size based on the number of lifetime parameters and they are
97 : : * indexed based on their order.
98 : : *
99 : : * All regions are initially set to unresolved. When type instantiation is
100 : : * encountered, all explicitly mentioned lifetimes are resolved to bound
101 : : * lifetimes. The remaining unresolved lifetimes are set to anonymous. During
102 : : * BIR construction, all lifetimes are replaced with free region variables.
103 : : * Inference of anonymous regions happens automatically using BIR subtyping
104 : : * pass.
105 : : */
106 : 406985760 : class RegionParamList
107 : : {
108 : : std::vector<Region> regions;
109 : :
110 : : public:
111 : 67844518 : RegionParamList (size_t num_regions) : regions (num_regions) {}
112 : :
113 : : Region *begin () { return regions.data (); }
114 : : Region *end () { return regions.data () + regions.size (); }
115 : 1 : Region &operator[] (size_t index) { return regions.at (index); }
116 : 44 : const Region &operator[] (size_t index) const { return regions.at (index); }
117 : 2986 : WARN_UNUSED_RESULT const Region *begin () const { return regions.data (); }
118 : 2986 : WARN_UNUSED_RESULT const Region *end () const
119 : : {
120 : 3017 : return regions.data () + regions.size ();
121 : : }
122 : 16787 : size_t size () const { return regions.size (); }
123 : :
124 : : /**
125 : : * Takes regions from the `subst` parameter and fills the rest with anonymous
126 : : * regions.
127 : : */
128 : 9104 : static RegionParamList from_subst (size_t num_regions,
129 : : std::vector<Region> subst)
130 : : {
131 : 9104 : RegionParamList list (num_regions);
132 : 9126 : for (size_t i = 0; i < MIN (num_regions, subst.size ()); i++)
133 : 44 : list.regions.at (i) = subst.at (i);
134 : 9107 : for (size_t i = subst.size (); i < num_regions; i++)
135 : : {
136 : 3 : list.regions.at (i) = Region::make_anonymous ();
137 : : }
138 : 9104 : return list;
139 : : }
140 : : };
141 : :
142 : : class SubstitutionArg
143 : : {
144 : : public:
145 : : SubstitutionArg (const SubstitutionParamMapping *param, BaseType *argument);
146 : :
147 : : // FIXME
148 : : // the copy constructors need removed - they are unsafe see
149 : : // TypeBoundPredicate
150 : : SubstitutionArg (const SubstitutionArg &other);
151 : :
152 : : SubstitutionArg &operator= (const SubstitutionArg &other);
153 : :
154 : : BaseType *get_tyty () const;
155 : :
156 : : const SubstitutionParamMapping *get_param_mapping () const;
157 : :
158 : : const BaseGeneric *get_param_ty () const;
159 : :
160 : : static SubstitutionArg error ();
161 : :
162 : : bool is_error () const;
163 : :
164 : : bool is_conrete () const;
165 : :
166 : : std::string as_string () const;
167 : :
168 : : private:
169 : : const SubstitutionParamMapping *param;
170 : : const BaseGeneric *original_param;
171 : : BaseType *argument;
172 : : };
173 : :
174 : : typedef std::function<void (const ParamType &, const SubstitutionArg &)>
175 : : ParamSubstCb;
176 : : class SubstitutionArgumentMappings
177 : : {
178 : : public:
179 : : SubstitutionArgumentMappings (std::vector<SubstitutionArg> mappings,
180 : : std::map<std::string, BaseType *> binding_args,
181 : : RegionParamList regions, location_t locus,
182 : : ParamSubstCb param_subst_cb = nullptr,
183 : : bool trait_item_flag = false,
184 : : bool error_flag = false);
185 : :
186 : : SubstitutionArgumentMappings (const SubstitutionArgumentMappings &other);
187 : : SubstitutionArgumentMappings &
188 : : operator= (const SubstitutionArgumentMappings &other);
189 : :
190 : 180869 : SubstitutionArgumentMappings (SubstitutionArgumentMappings &&other) = default;
191 : 67678459 : SubstitutionArgumentMappings &operator= (SubstitutionArgumentMappings &&other)
192 : : = default;
193 : :
194 : : static SubstitutionArgumentMappings error ();
195 : :
196 : : /** Creates empty substitution argument mappings with unresolved regions */
197 : : static SubstitutionArgumentMappings empty (size_t num_regions = 0);
198 : :
199 : : static RegionParamList
200 : 5274 : regions_from_nullable_args (SubstitutionArgumentMappings *args)
201 : : {
202 : 5274 : if (args == nullptr)
203 : 4302 : return RegionParamList (0);
204 : :
205 : 972 : return args->get_regions ();
206 : : }
207 : :
208 : : bool is_error () const;
209 : :
210 : : bool get_argument_for_symbol (const BaseGeneric *param_to_find,
211 : : SubstitutionArg *argument) const;
212 : :
213 : : /** Return type parameter index for symbol */
214 : : tl::optional<size_t> find_symbol (const ParamType ¶m_to_find) const;
215 : :
216 : : bool get_argument_at (size_t index, SubstitutionArg *argument);
217 : :
218 : : // is_concrete means if the used args is non error, ie: non empty this will
219 : : // verify if actual real types have been put in place of are they still
220 : : // ParamTy
221 : : bool is_concrete () const;
222 : :
223 : : location_t get_locus () const;
224 : :
225 : : size_t size () const;
226 : :
227 : : bool is_empty () const;
228 : :
229 : : std::vector<SubstitutionArg> &get_mappings ();
230 : :
231 : : const std::vector<SubstitutionArg> &get_mappings () const;
232 : :
233 : : std::map<std::string, BaseType *> &get_binding_args ();
234 : :
235 : : const std::map<std::string, BaseType *> &get_binding_args () const;
236 : :
237 : : const RegionParamList &get_regions () const;
238 : : RegionParamList &get_mut_regions ();
239 : :
240 : : std::string as_string () const;
241 : :
242 : : void on_param_subst (const ParamType &p, const SubstitutionArg &a) const;
243 : :
244 : : ParamSubstCb get_subst_cb () const;
245 : :
246 : : bool trait_item_mode () const;
247 : :
248 : : private:
249 : : std::vector<SubstitutionArg> mappings;
250 : : std::map<std::string, BaseType *> binding_args;
251 : : RegionParamList regions;
252 : : location_t locus;
253 : : ParamSubstCb param_subst_cb;
254 : : bool trait_item_flag;
255 : : bool error_flag;
256 : : };
257 : :
258 : : class TypeBoundPredicateItem;
259 : : class SubstitutionRef
260 : : {
261 : : public:
262 : : SubstitutionRef (std::vector<SubstitutionParamMapping> substitutions,
263 : : SubstitutionArgumentMappings arguments,
264 : : RegionConstraints region_constraints);
265 : :
266 : : bool has_substitutions () const;
267 : :
268 : : std::string subst_as_string () const;
269 : :
270 : : bool supports_associated_bindings () const;
271 : :
272 : : // this is overridden in TypeBoundPredicate
273 : : // which support bindings we don't add them directly to the SubstitutionRef
274 : : // base class because this class represents the fn<X: Foo, Y: Bar>. The only
275 : : // construct which supports associated types
276 : : virtual size_t get_num_associated_bindings () const;
277 : :
278 : : // this is overridden in TypeBoundPredicate
279 : : virtual TypeBoundPredicateItem
280 : : lookup_associated_type (const std::string &search);
281 : :
282 : : size_t get_num_substitutions () const;
283 : :
284 : : size_t get_num_lifetime_params () const;
285 : :
286 : : size_t get_num_type_params () const;
287 : :
288 : : std::vector<SubstitutionParamMapping> &get_substs ();
289 : :
290 : : const std::vector<SubstitutionParamMapping> &get_substs () const;
291 : :
292 : : std::vector<SubstitutionParamMapping> clone_substs () const;
293 : :
294 : : void override_context ();
295 : :
296 : : bool needs_substitution () const;
297 : :
298 : : bool was_substituted () const;
299 : :
300 : : SubstitutionArgumentMappings &get_substitution_arguments ();
301 : : const SubstitutionArgumentMappings &get_substitution_arguments () const;
302 : :
303 : : // this is the count of type params that are not substituted fuly
304 : : size_t num_required_substitutions () const;
305 : :
306 : : // this is the count of type params that need substituted taking into account
307 : : // possible defaults
308 : : size_t min_required_substitutions () const;
309 : :
310 : : // We are trying to subst <i32, f32> into Struct Foo<X,Y> {}
311 : : // in the case of Foo<i32,f32>{...}
312 : : //
313 : : // the substitions we have here define X,Y but the arguments have no bindings
314 : : // so its a matter of ordering
315 : : SubstitutionArgumentMappings
316 : : get_mappings_from_generic_args (HIR::GenericArgs &args,
317 : : const std::vector<Region> ®ions);
318 : :
319 : : // Recursive substitutions
320 : : // Foo <A,B> { a:A, b: B}; Bar <X,Y,Z>{a:X, b: Foo<Y,Z>}
321 : : //
322 : : // we have bindings for X Y Z and need to propagate the binding Y,Z into Foo
323 : : // Which binds to A,B
324 : : SubstitutionArgumentMappings
325 : : adjust_mappings_for_this (SubstitutionArgumentMappings &mappings,
326 : : bool trait_mode = false);
327 : :
328 : : // Are the mappings here actually bound to this type. For example imagine the
329 : : // case:
330 : : //
331 : : // struct Foo<T>(T);
332 : : // impl<T> Foo<T> {
333 : : // fn test(self) { ... }
334 : : // }
335 : : //
336 : : // In this case we have a generic ADT of Foo and an impl block of a generic T
337 : : // on Foo for the Self type. When we it comes to path resolution we can have:
338 : : //
339 : : // Foo::<i32>::test()
340 : : //
341 : : // This means the first segment of Foo::<i32> returns the ADT Foo<i32> not the
342 : : // Self ADT bound to the T from the impl block. This means when it comes to
343 : : // the next segment of test which resolves to the function we need to check
344 : : // wether the arguments in the struct definition of foo can be bound here
345 : : // before substituting the previous segments type here. This functions acts as
346 : : // a guard for the solve_mappings_from_receiver_for_self to handle the case
347 : : // where arguments are not bound. This is important for this next case:
348 : : //
349 : : // struct Baz<A, B>(A, B);
350 : : // impl Baz<i32, f32> {
351 : : // fn test<X>(a: X) -> X {
352 : : // a
353 : : // }
354 : : // }
355 : : //
356 : : // In this case Baz has been already substituted for the impl's Self to become
357 : : // ADT<i32, f32> so that the function test only has 1 generic argument of X.
358 : : // The path for this will be:
359 : : //
360 : : // Baz::test::<_>(123)
361 : : //
362 : : // So the first segment here will be Baz<_, _> to try and infer the arguments
363 : : // which will be taken from the impl's Self type in this case since it is
364 : : // already substituted and like the previous case the check to see if we need
365 : : // to inherit the previous segments generic arguments takes place but the
366 : : // generic arguments are not bound to this type as they have already been
367 : : // substituted.
368 : : //
369 : : // Its important to remember from the first example the FnType actually looks
370 : : // like:
371 : : //
372 : : // fn <T>test(self :Foo<T>(T))
373 : : //
374 : : // As the generic parameters are "bound" to each of the items in the impl
375 : : // block. So this check is about wether the arguments we have here can
376 : : // actually be bound to this type.
377 : : bool are_mappings_bound (SubstitutionArgumentMappings &mappings);
378 : :
379 : : // struct Foo<A, B>(A, B);
380 : : //
381 : : // impl<T> Foo<T, f32>;
382 : : // -> fn test<X>(self, a: X) -> X
383 : : //
384 : : // We might invoke this via:
385 : : //
386 : : // a = Foo(123, 456f32);
387 : : // b = a.test::<bool>(false);
388 : : //
389 : : // we need to figure out relevant generic arguemts for self to apply to the
390 : : // fntype
391 : : SubstitutionArgumentMappings solve_mappings_from_receiver_for_self (
392 : : SubstitutionArgumentMappings &mappings) const;
393 : :
394 : : // Given a type such as:
395 : : //
396 : : // fn<X,Y>(a:&X, b:Y) -> (...)
397 : : //
398 : : // This function will inject implicit inference variables for the type
399 : : // parameters X and Y
400 : : BaseType *infer_substitions (location_t locus);
401 : :
402 : : // this clears any possible projections from higher ranked trait bounds which
403 : : // could be hanging around from a previous resolution
404 : : void prepare_higher_ranked_bounds ();
405 : :
406 : : // FIXME
407 : : // this is bad name for this, i think it should be something like
408 : : // compute-higher-ranked-bounds
409 : : bool monomorphize ();
410 : :
411 : : // TODO comment
412 : : virtual BaseType *handle_substitions (SubstitutionArgumentMappings &mappings)
413 : : = 0;
414 : :
415 : : WARN_UNUSED_RESULT const SubstitutionArgumentMappings &
416 : : get_used_arguments () const;
417 : :
418 : : WARN_UNUSED_RESULT tl::optional<SubstitutionArg> get_arg_at (size_t i) const;
419 : :
420 : : const RegionConstraints &get_region_constraints () const;
421 : :
422 : : protected:
423 : : std::vector<SubstitutionParamMapping> substitutions;
424 : : SubstitutionArgumentMappings used_arguments;
425 : : RegionConstraints region_constraints;
426 : : };
427 : :
428 : : } // namespace TyTy
429 : : } // namespace Rust
430 : : #endif // RUST_TYTY_SUBST_H
|