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