1 // Copyright (C) 2020-2023 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
27 namespace Rust {
28 namespace TyTy {
29
30 class BaseType;
31 class ParamType;
32 class SubstitutionArgumentMappings;
33 class SubstitutionParamMapping
34 {
35 public:
36 SubstitutionParamMapping (const HIR::TypeParam &generic, ParamType *param);
37
38 SubstitutionParamMapping (const SubstitutionParamMapping &other);
39
40 std::string as_string () const;
41
42 bool fill_param_ty (SubstitutionArgumentMappings &subst_mappings,
43 Location locus);
44
45 SubstitutionParamMapping clone () const;
46
47 ParamType *get_param_ty ();
48
49 const ParamType *get_param_ty () const;
50
51 const HIR::TypeParam &get_generic_param () const;
52
53 // this is used for the backend to override the HirId ref of the param to
54 // what the concrete type is for the rest of the context
55 void override_context ();
56
57 bool needs_substitution () const;
58
59 Location get_param_locus () const;
60
61 bool param_has_default_ty () const;
62
63 BaseType *get_default_ty () const;
64
65 bool need_substitution () const;
66
67 private:
68 const HIR::TypeParam &generic;
69 ParamType *param;
70 };
71
72 class SubstitutionArg
73 {
74 public:
75 SubstitutionArg (const SubstitutionParamMapping *param, BaseType *argument);
76
77 // FIXME
78 // the copy constructors need removed - they are unsafe see
79 // TypeBoundPredicate
80 SubstitutionArg (const SubstitutionArg &other);
81
82 SubstitutionArg &operator= (const SubstitutionArg &other);
83
84 BaseType *get_tyty ();
85
86 const BaseType *get_tyty () const;
87
88 const SubstitutionParamMapping *get_param_mapping () const;
89
90 static SubstitutionArg error ();
91
92 bool is_error () const;
93
94 bool is_conrete () const;
95
96 std::string as_string () const;
97
98 private:
99 const SubstitutionParamMapping *param;
100 BaseType *argument;
101 };
102
103 typedef std::function<void (const ParamType &, const SubstitutionArg &)>
104 ParamSubstCb;
105 class SubstitutionArgumentMappings
106 {
107 public:
108 SubstitutionArgumentMappings (std::vector<SubstitutionArg> mappings,
109 std::map<std::string, BaseType *> binding_args,
110 Location locus,
111 ParamSubstCb param_subst_cb = nullptr,
112 bool trait_item_flag = false);
113
114 SubstitutionArgumentMappings (const SubstitutionArgumentMappings &other);
115 SubstitutionArgumentMappings &
116 operator= (const SubstitutionArgumentMappings &other);
117
118 SubstitutionArgumentMappings (SubstitutionArgumentMappings &&other) = default;
119 SubstitutionArgumentMappings &operator= (SubstitutionArgumentMappings &&other)
120 = default;
121
122 static SubstitutionArgumentMappings error ();
123
124 bool is_error () const;
125
126 bool get_argument_for_symbol (const ParamType *param_to_find,
127 SubstitutionArg *argument);
128
129 bool get_argument_at (size_t index, SubstitutionArg *argument);
130
131 // is_concrete means if the used args is non error, ie: non empty this will
132 // verify if actual real types have been put in place of are they still
133 // ParamTy
134 bool is_concrete () const;
135
136 Location get_locus () const;
137
138 size_t size () const;
139
140 bool is_empty () const;
141
142 std::vector<SubstitutionArg> &get_mappings ();
143
144 const std::vector<SubstitutionArg> &get_mappings () const;
145
146 std::map<std::string, BaseType *> &get_binding_args ();
147
148 const std::map<std::string, BaseType *> &get_binding_args () const;
149
150 std::string as_string () const;
151
152 void on_param_subst (const ParamType &p, const SubstitutionArg &a) const;
153
154 ParamSubstCb get_subst_cb () const;
155
156 bool trait_item_mode () const;
157
158 private:
159 std::vector<SubstitutionArg> mappings;
160 std::map<std::string, BaseType *> binding_args;
161 Location locus;
162 ParamSubstCb param_subst_cb;
163 bool trait_item_flag;
164 };
165
166 class SubstitutionRef
167 {
168 public:
169 SubstitutionRef (std::vector<SubstitutionParamMapping> substitutions,
170 SubstitutionArgumentMappings arguments);
171
172 bool has_substitutions () const;
173
174 std::string subst_as_string () const;
175
176 bool supports_associated_bindings () const;
177
178 // this is overridden in TypeBoundPredicate
179 // which support bindings we don't add them directly to the SubstitutionRef
180 // base class because this class represents the fn<X: Foo, Y: Bar>. The only
181 // construct which supports associated types
182 virtual size_t get_num_associated_bindings () const;
183
184 // this is overridden in TypeBoundPredicate
185 virtual TypeBoundPredicateItem
186 lookup_associated_type (const std::string &search);
187
188 size_t get_num_substitutions () const;
189
190 std::vector<SubstitutionParamMapping> &get_substs ();
191
192 const std::vector<SubstitutionParamMapping> &get_substs () const;
193
194 std::vector<SubstitutionParamMapping> clone_substs () const;
195
196 void override_context ();
197
198 bool needs_substitution () const;
199
200 bool was_substituted () const;
201
202 SubstitutionArgumentMappings &get_substitution_arguments ();
203 const SubstitutionArgumentMappings &get_substitution_arguments () const;
204
205 // this is the count of type params that are not substituted fuly
206 size_t num_required_substitutions () const;
207
208 // this is the count of type params that need substituted taking into account
209 // possible defaults
210 size_t min_required_substitutions () const;
211
212 // We are trying to subst <i32, f32> into Struct Foo<X,Y> {}
213 // in the case of Foo<i32,f32>{...}
214 //
215 // the substitions we have here define X,Y but the arguments have no bindings
216 // so its a matter of ordering
217 SubstitutionArgumentMappings
218 get_mappings_from_generic_args (HIR::GenericArgs &args);
219
220 // Recursive substitutions
221 // Foo <A,B> { a:A, b: B}; Bar <X,Y,Z>{a:X, b: Foo<Y,Z>}
222 //
223 // we have bindings for X Y Z and need to propagate the binding Y,Z into Foo
224 // Which binds to A,B
225 SubstitutionArgumentMappings
226 adjust_mappings_for_this (SubstitutionArgumentMappings &mappings);
227
228 // Are the mappings here actually bound to this type. For example imagine the
229 // case:
230 //
231 // struct Foo<T>(T);
232 // impl<T> Foo<T> {
233 // fn test(self) { ... }
234 // }
235 //
236 // In this case we have a generic ADT of Foo and an impl block of a generic T
237 // on Foo for the Self type. When we it comes to path resolution we can have:
238 //
239 // Foo::<i32>::test()
240 //
241 // This means the first segment of Foo::<i32> returns the ADT Foo<i32> not the
242 // Self ADT bound to the T from the impl block. This means when it comes to
243 // the next segment of test which resolves to the function we need to check
244 // wether the arguments in the struct definition of foo can be bound here
245 // before substituting the previous segments type here. This functions acts as
246 // a guard for the solve_mappings_from_receiver_for_self to handle the case
247 // where arguments are not bound. This is important for this next case:
248 //
249 // struct Baz<A, B>(A, B);
250 // impl Baz<i32, f32> {
251 // fn test<X>(a: X) -> X {
252 // a
253 // }
254 // }
255 //
256 // In this case Baz has been already substituted for the impl's Self to become
257 // ADT<i32, f32> so that the function test only has 1 generic argument of X.
258 // The path for this will be:
259 //
260 // Baz::test::<_>(123)
261 //
262 // So the first segment here will be Baz<_, _> to try and infer the arguments
263 // which will be taken from the impl's Self type in this case since it is
264 // already substituted and like the previous case the check to see if we need
265 // to inherit the previous segments generic arguments takes place but the
266 // generic arguments are not bound to this type as they have already been
267 // substituted.
268 //
269 // Its important to remember from the first example the FnType actually looks
270 // like:
271 //
272 // fn <T>test(self :Foo<T>(T))
273 //
274 // As the generic parameters are "bound" to each of the items in the impl
275 // block. So this check is about wether the arguments we have here can
276 // actually be bound to this type.
277 bool are_mappings_bound (SubstitutionArgumentMappings &mappings);
278
279 // struct Foo<A, B>(A, B);
280 //
281 // impl<T> Foo<T, f32>;
282 // -> fn test<X>(self, a: X) -> X
283 //
284 // We might invoke this via:
285 //
286 // a = Foo(123, 456f32);
287 // b = a.test::<bool>(false);
288 //
289 // we need to figure out relevant generic arguemts for self to apply to the
290 // fntype
291 SubstitutionArgumentMappings solve_mappings_from_receiver_for_self (
292 SubstitutionArgumentMappings &mappings) const;
293
294 // TODO comment
295 SubstitutionArgumentMappings
296 solve_missing_mappings_from_this (SubstitutionRef &ref, SubstitutionRef &to);
297
298 // TODO comment
299 BaseType *infer_substitions (Location locus);
300
301 // this clears any possible projections from higher ranked trait bounds which
302 // could be hanging around from a previous resolution
303 void prepare_higher_ranked_bounds ();
304
305 // FIXME
306 // this is bad name for this, i think it should be something like
307 // compute-higher-ranked-bounds
308 bool monomorphize ();
309
310 // TODO comment
311 virtual BaseType *handle_substitions (SubstitutionArgumentMappings &mappings)
312 = 0;
313
314 SubstitutionArgumentMappings get_used_arguments () const;
315
316 protected:
317 Resolver::AssociatedImplTrait *lookup_associated_impl (
318 const SubstitutionParamMapping &subst, const TypeBoundPredicate &bound,
319 const TyTy::BaseType *binding, bool *error_flag) const;
320
321 std::vector<SubstitutionParamMapping> substitutions;
322 SubstitutionArgumentMappings used_arguments;
323 };
324
325 } // namespace TyTy
326 } // namespace Rust
327 #endif // RUST_TYTY_SUBST_H