]>
Commit | Line | Data |
---|---|---|
83ffe9cd | 1 | // Copyright (C) 2020-2023 Free Software Foundation, Inc. |
06688fe4 PH |
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 | #include "rust-autoderef.h" | |
20 | #include "rust-hir-path-probe.h" | |
21 | #include "rust-hir-dot-operator.h" | |
22 | #include "rust-hir-trait-resolve.h" | |
23 | ||
24 | namespace Rust { | |
25 | namespace Resolver { | |
26 | ||
27 | static bool | |
28 | resolve_operator_overload_fn ( | |
29 | Analysis::RustLangItem::ItemType lang_item_type, const TyTy::BaseType *ty, | |
30 | TyTy::FnType **resolved_fn, HIR::ImplItem **impl_item, | |
31 | Adjustment::AdjustmentType *requires_ref_adjustment); | |
32 | ||
33 | TyTy::BaseType * | |
34 | Adjuster::adjust_type (const std::vector<Adjustment> &adjustments) | |
35 | { | |
36 | if (adjustments.size () == 0) | |
37 | return base->clone (); | |
38 | ||
39 | return adjustments.back ().get_expected ()->clone (); | |
40 | } | |
41 | ||
42 | Adjustment | |
43 | Adjuster::try_deref_type (const TyTy::BaseType *ty, | |
44 | Analysis::RustLangItem::ItemType deref_lang_item) | |
45 | { | |
46 | HIR::ImplItem *impl_item = nullptr; | |
47 | TyTy::FnType *fn = nullptr; | |
48 | Adjustment::AdjustmentType requires_ref_adjustment | |
49 | = Adjustment::AdjustmentType::ERROR; | |
50 | bool operator_overloaded | |
51 | = resolve_operator_overload_fn (deref_lang_item, ty, &fn, &impl_item, | |
52 | &requires_ref_adjustment); | |
53 | if (!operator_overloaded) | |
54 | { | |
55 | return Adjustment::get_error (); | |
56 | } | |
57 | ||
58 | auto resolved_base = fn->get_return_type ()->clone (); | |
59 | bool is_valid_type = resolved_base->get_kind () == TyTy::TypeKind::REF; | |
60 | if (!is_valid_type) | |
61 | return Adjustment::get_error (); | |
62 | ||
63 | TyTy::ReferenceType *ref_base | |
64 | = static_cast<TyTy::ReferenceType *> (resolved_base); | |
65 | ||
66 | Adjustment::AdjustmentType adjustment_type | |
67 | = Adjustment::AdjustmentType::ERROR; | |
68 | switch (deref_lang_item) | |
69 | { | |
70 | case Analysis::RustLangItem::ItemType::DEREF: | |
71 | adjustment_type = Adjustment::AdjustmentType::DEREF; | |
72 | break; | |
73 | ||
74 | case Analysis::RustLangItem::ItemType::DEREF_MUT: | |
75 | adjustment_type = Adjustment::AdjustmentType::DEREF_MUT; | |
76 | break; | |
77 | ||
78 | default: | |
79 | break; | |
80 | } | |
81 | ||
82 | return Adjustment::get_op_overload_deref_adjustment (adjustment_type, ty, | |
83 | ref_base, fn, impl_item, | |
84 | requires_ref_adjustment); | |
85 | } | |
86 | ||
87 | Adjustment | |
88 | Adjuster::try_raw_deref_type (const TyTy::BaseType *ty) | |
89 | { | |
90 | bool is_valid_type = ty->get_kind () == TyTy::TypeKind::REF; | |
91 | if (!is_valid_type) | |
92 | return Adjustment::get_error (); | |
93 | ||
94 | const TyTy::ReferenceType *ref_base | |
95 | = static_cast<const TyTy::ReferenceType *> (ty); | |
96 | auto infered = ref_base->get_base ()->clone (); | |
97 | ||
98 | return Adjustment (Adjustment::AdjustmentType::INDIRECTION, ty, infered); | |
99 | } | |
100 | ||
101 | Adjustment | |
102 | Adjuster::try_unsize_type (const TyTy::BaseType *ty) | |
103 | { | |
104 | bool is_valid_type = ty->get_kind () == TyTy::TypeKind::ARRAY; | |
105 | if (!is_valid_type) | |
106 | return Adjustment::get_error (); | |
107 | ||
108 | auto mappings = Analysis::Mappings::get (); | |
109 | auto context = TypeCheckContext::get (); | |
110 | ||
111 | const auto ref_base = static_cast<const TyTy::ArrayType *> (ty); | |
112 | auto slice_elem = ref_base->get_element_type (); | |
113 | ||
114 | auto slice | |
115 | = new TyTy::SliceType (mappings->get_next_hir_id (), ty->get_ident ().locus, | |
116 | TyTy::TyVar (slice_elem->get_ref ())); | |
117 | context->insert_implicit_type (slice); | |
118 | ||
119 | return Adjustment (Adjustment::AdjustmentType::UNSIZE, ty, slice); | |
120 | } | |
121 | ||
122 | static bool | |
123 | resolve_operator_overload_fn ( | |
124 | Analysis::RustLangItem::ItemType lang_item_type, const TyTy::BaseType *ty, | |
125 | TyTy::FnType **resolved_fn, HIR::ImplItem **impl_item, | |
126 | Adjustment::AdjustmentType *requires_ref_adjustment) | |
127 | { | |
128 | auto context = TypeCheckContext::get (); | |
129 | auto mappings = Analysis::Mappings::get (); | |
130 | ||
131 | // look up lang item for arithmetic type | |
132 | std::string associated_item_name | |
133 | = Analysis::RustLangItem::ToString (lang_item_type); | |
134 | DefId respective_lang_item_id = UNKNOWN_DEFID; | |
135 | bool lang_item_defined | |
136 | = mappings->lookup_lang_item (lang_item_type, &respective_lang_item_id); | |
137 | ||
138 | if (!lang_item_defined) | |
139 | return false; | |
140 | ||
141 | auto segment = HIR::PathIdentSegment (associated_item_name); | |
142 | auto candidate | |
143 | = MethodResolver::Probe (ty, HIR::PathIdentSegment (associated_item_name), | |
144 | true); | |
145 | ||
146 | bool have_implementation_for_lang_item = !candidate.is_error (); | |
147 | if (!have_implementation_for_lang_item) | |
148 | return false; | |
149 | ||
150 | // Get the adjusted self | |
151 | Adjuster adj (ty); | |
152 | TyTy::BaseType *adjusted_self = adj.adjust_type (candidate.adjustments); | |
153 | ||
154 | // is this the case we are recursive | |
155 | // handle the case where we are within the impl block for this | |
156 | // lang_item otherwise we end up with a recursive operator overload | |
157 | // such as the i32 operator overload trait | |
158 | TypeCheckContextItem &fn_context = context->peek_context (); | |
159 | if (fn_context.get_type () == TypeCheckContextItem::ItemType::IMPL_ITEM) | |
160 | { | |
161 | auto &impl_item = fn_context.get_impl_item (); | |
162 | HIR::ImplBlock *parent = impl_item.first; | |
163 | HIR::Function *fn = impl_item.second; | |
164 | ||
165 | if (parent->has_trait_ref () | |
166 | && fn->get_function_name ().compare (associated_item_name) == 0) | |
167 | { | |
168 | TraitReference *trait_reference | |
169 | = TraitResolver::Lookup (*parent->get_trait_ref ().get ()); | |
170 | if (!trait_reference->is_error ()) | |
171 | { | |
172 | TyTy::BaseType *lookup = nullptr; | |
173 | bool ok = context->lookup_type (fn->get_mappings ().get_hirid (), | |
174 | &lookup); | |
175 | rust_assert (ok); | |
176 | rust_assert (lookup->get_kind () == TyTy::TypeKind::FNDEF); | |
177 | ||
178 | TyTy::FnType *fntype = static_cast<TyTy::FnType *> (lookup); | |
179 | rust_assert (fntype->is_method ()); | |
180 | ||
181 | bool is_lang_item_impl | |
182 | = trait_reference->get_mappings ().get_defid () | |
183 | == respective_lang_item_id; | |
184 | bool self_is_lang_item_self | |
185 | = fntype->get_self_type ()->is_equal (*adjusted_self); | |
186 | bool recursive_operator_overload | |
187 | = is_lang_item_impl && self_is_lang_item_self; | |
188 | ||
189 | if (recursive_operator_overload) | |
190 | return false; | |
191 | } | |
192 | } | |
193 | } | |
194 | ||
195 | TyTy::BaseType *lookup_tyty = candidate.candidate.ty; | |
196 | ||
197 | // rust only support impl item deref operator overloading ie you must have an | |
198 | // impl block for it | |
199 | rust_assert (candidate.candidate.type | |
200 | == PathProbeCandidate::CandidateType::IMPL_FUNC); | |
201 | *impl_item = candidate.candidate.item.impl.impl_item; | |
202 | ||
203 | rust_assert (lookup_tyty->get_kind () == TyTy::TypeKind::FNDEF); | |
204 | TyTy::BaseType *lookup = lookup_tyty; | |
205 | TyTy::FnType *fn = static_cast<TyTy::FnType *> (lookup); | |
206 | rust_assert (fn->is_method ()); | |
207 | ||
208 | if (fn->needs_substitution ()) | |
209 | { | |
210 | if (ty->get_kind () == TyTy::TypeKind::ADT) | |
211 | { | |
212 | const TyTy::ADTType *adt = static_cast<const TyTy::ADTType *> (ty); | |
213 | ||
214 | auto s = fn->get_self_type ()->get_root (); | |
215 | rust_assert (s->can_eq (adt, false)); | |
216 | rust_assert (s->get_kind () == TyTy::TypeKind::ADT); | |
217 | const TyTy::ADTType *self_adt | |
218 | = static_cast<const TyTy::ADTType *> (s); | |
219 | ||
220 | // we need to grab the Self substitutions as the inherit type | |
221 | // parameters for this | |
222 | if (self_adt->needs_substitution ()) | |
223 | { | |
224 | rust_assert (adt->was_substituted ()); | |
225 | ||
226 | TyTy::SubstitutionArgumentMappings used_args_in_prev_segment | |
227 | = GetUsedSubstArgs::From (adt); | |
228 | ||
229 | TyTy::SubstitutionArgumentMappings inherit_type_args | |
230 | = self_adt->solve_mappings_from_receiver_for_self ( | |
231 | used_args_in_prev_segment); | |
232 | ||
233 | // there may or may not be inherited type arguments | |
234 | if (!inherit_type_args.is_error ()) | |
235 | { | |
236 | // need to apply the inherited type arguments to the | |
237 | // function | |
238 | lookup = fn->handle_substitions (inherit_type_args); | |
239 | } | |
240 | } | |
241 | } | |
242 | else | |
243 | { | |
244 | rust_assert (candidate.adjustments.size () < 2); | |
245 | ||
246 | // lets infer the params for this we could probably fix this up by | |
247 | // actually just performing a substitution of a single param but this | |
248 | // seems more generic i think. | |
249 | // | |
250 | // this is the case where we had say Foo<&Bar>> and we have derefed to | |
251 | // the &Bar and we are trying to match a method self of Bar which | |
252 | // requires another deref which is matched to the deref trait impl of | |
253 | // &&T so this requires another reference and deref call | |
254 | ||
255 | lookup = fn->infer_substitions (Location ()); | |
256 | rust_assert (lookup->get_kind () == TyTy::TypeKind::FNDEF); | |
257 | fn = static_cast<TyTy::FnType *> (lookup); | |
258 | fn->get_self_type ()->unify (adjusted_self); | |
259 | lookup = fn; | |
260 | } | |
261 | } | |
262 | ||
263 | if (candidate.adjustments.size () > 0) | |
264 | *requires_ref_adjustment = candidate.adjustments.at (0).get_type (); | |
265 | ||
266 | *resolved_fn = static_cast<TyTy::FnType *> (lookup); | |
267 | ||
268 | return true; | |
269 | } | |
270 | ||
271 | AutoderefCycle::AutoderefCycle (bool autoderef_flag) | |
272 | : autoderef_flag (autoderef_flag) | |
273 | {} | |
274 | ||
275 | AutoderefCycle::~AutoderefCycle () {} | |
276 | ||
277 | void | |
278 | AutoderefCycle::try_hook (const TyTy::BaseType &) | |
279 | {} | |
280 | ||
281 | bool | |
282 | AutoderefCycle::cycle (const TyTy::BaseType *receiver) | |
283 | { | |
284 | const TyTy::BaseType *r = receiver; | |
285 | while (true) | |
286 | { | |
287 | if (try_autoderefed (r)) | |
288 | return true; | |
289 | ||
290 | // 4. deref to to 1, if cannot deref then quit | |
291 | if (autoderef_flag) | |
292 | return false; | |
293 | ||
294 | // try unsize | |
295 | Adjustment unsize = Adjuster::try_unsize_type (r); | |
296 | if (!unsize.is_error ()) | |
297 | { | |
298 | adjustments.push_back (unsize); | |
299 | auto unsize_r = unsize.get_expected (); | |
300 | ||
301 | if (try_autoderefed (unsize_r)) | |
302 | return true; | |
303 | ||
304 | adjustments.pop_back (); | |
305 | } | |
306 | ||
307 | Adjustment deref | |
308 | = Adjuster::try_deref_type (r, Analysis::RustLangItem::ItemType::DEREF); | |
309 | if (!deref.is_error ()) | |
310 | { | |
311 | auto deref_r = deref.get_expected (); | |
312 | adjustments.push_back (deref); | |
313 | ||
314 | if (try_autoderefed (deref_r)) | |
315 | return true; | |
316 | ||
317 | adjustments.pop_back (); | |
318 | } | |
319 | ||
320 | Adjustment deref_mut = Adjuster::try_deref_type ( | |
321 | r, Analysis::RustLangItem::ItemType::DEREF_MUT); | |
322 | if (!deref_mut.is_error ()) | |
323 | { | |
324 | auto deref_r = deref_mut.get_expected (); | |
325 | adjustments.push_back (deref_mut); | |
326 | ||
327 | if (try_autoderefed (deref_r)) | |
328 | return true; | |
329 | ||
330 | adjustments.pop_back (); | |
331 | } | |
332 | ||
333 | if (!deref_mut.is_error ()) | |
334 | { | |
335 | auto deref_r = deref_mut.get_expected (); | |
336 | adjustments.push_back (deref_mut); | |
337 | Adjustment raw_deref = Adjuster::try_raw_deref_type (deref_r); | |
338 | adjustments.push_back (raw_deref); | |
339 | deref_r = raw_deref.get_expected (); | |
340 | ||
341 | if (try_autoderefed (deref_r)) | |
342 | return true; | |
343 | ||
344 | adjustments.pop_back (); | |
345 | adjustments.pop_back (); | |
346 | } | |
347 | ||
348 | if (!deref.is_error ()) | |
349 | { | |
350 | r = deref.get_expected (); | |
351 | adjustments.push_back (deref); | |
352 | } | |
353 | Adjustment raw_deref = Adjuster::try_raw_deref_type (r); | |
354 | if (raw_deref.is_error ()) | |
355 | return false; | |
356 | ||
357 | r = raw_deref.get_expected (); | |
358 | adjustments.push_back (raw_deref); | |
359 | } | |
360 | return false; | |
361 | } | |
362 | ||
363 | bool | |
364 | AutoderefCycle::try_autoderefed (const TyTy::BaseType *r) | |
365 | { | |
366 | try_hook (*r); | |
367 | ||
368 | // 1. try raw | |
369 | if (select (*r)) | |
370 | return true; | |
371 | ||
372 | // 2. try ref | |
373 | TyTy::ReferenceType *r1 | |
374 | = new TyTy::ReferenceType (r->get_ref (), TyTy::TyVar (r->get_ref ()), | |
375 | Mutability::Imm); | |
376 | adjustments.push_back ( | |
377 | Adjustment (Adjustment::AdjustmentType::IMM_REF, r, r1)); | |
378 | if (select (*r1)) | |
379 | return true; | |
380 | ||
381 | adjustments.pop_back (); | |
382 | ||
383 | // 3. try mut ref | |
384 | TyTy::ReferenceType *r2 | |
385 | = new TyTy::ReferenceType (r->get_ref (), TyTy::TyVar (r->get_ref ()), | |
386 | Mutability::Mut); | |
387 | adjustments.push_back ( | |
388 | Adjustment (Adjustment::AdjustmentType::MUT_REF, r, r2)); | |
389 | if (select (*r2)) | |
390 | return true; | |
391 | ||
392 | adjustments.pop_back (); | |
393 | ||
394 | return false; | |
395 | } | |
396 | ||
397 | } // namespace Resolver | |
398 | } // namespace Rust |