1 // Copyright (C) 2020-2024 Free Software Foundation, Inc.
3 // This file is part of GCC.
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
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
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/>.
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"
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
);
34 Adjuster::adjust_type (const std::vector
<Adjustment
> &adjustments
)
36 if (adjustments
.size () == 0)
37 return base
->clone ();
39 return adjustments
.back ().get_expected ()->clone ();
43 Adjuster::try_deref_type (const TyTy::BaseType
*ty
,
44 Analysis::RustLangItem::ItemType deref_lang_item
)
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
)
55 return Adjustment::get_error ();
58 auto resolved_base
= fn
->get_return_type ()->clone ();
59 bool is_valid_type
= resolved_base
->get_kind () == TyTy::TypeKind::REF
;
61 return Adjustment::get_error ();
63 TyTy::ReferenceType
*ref_base
64 = static_cast<TyTy::ReferenceType
*> (resolved_base
);
66 Adjustment::AdjustmentType adjustment_type
67 = Adjustment::AdjustmentType::ERROR
;
68 switch (deref_lang_item
)
70 case Analysis::RustLangItem::ItemType::DEREF
:
71 adjustment_type
= Adjustment::AdjustmentType::DEREF
;
74 case Analysis::RustLangItem::ItemType::DEREF_MUT
:
75 adjustment_type
= Adjustment::AdjustmentType::DEREF_MUT
;
82 return Adjustment::get_op_overload_deref_adjustment (adjustment_type
, ty
,
83 ref_base
, fn
, impl_item
,
84 requires_ref_adjustment
);
88 Adjuster::try_raw_deref_type (const TyTy::BaseType
*ty
)
90 bool is_valid_type
= ty
->get_kind () == TyTy::TypeKind::REF
;
92 return Adjustment::get_error ();
94 const TyTy::ReferenceType
*ref_base
95 = static_cast<const TyTy::ReferenceType
*> (ty
);
96 auto infered
= ref_base
->get_base ()->clone ();
98 return Adjustment (Adjustment::AdjustmentType::INDIRECTION
, ty
, infered
);
102 Adjuster::try_unsize_type (const TyTy::BaseType
*ty
)
104 bool is_valid_type
= ty
->get_kind () == TyTy::TypeKind::ARRAY
;
106 return Adjustment::get_error ();
108 auto mappings
= Analysis::Mappings::get ();
109 auto context
= TypeCheckContext::get ();
111 const auto ref_base
= static_cast<const TyTy::ArrayType
*> (ty
);
112 auto slice_elem
= ref_base
->get_element_type ();
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
);
119 return Adjustment (Adjustment::AdjustmentType::UNSIZE
, ty
, slice
);
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
)
128 auto context
= TypeCheckContext::get ();
129 auto mappings
= Analysis::Mappings::get ();
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
);
138 if (!lang_item_defined
)
141 auto segment
= HIR::PathIdentSegment (associated_item_name
);
143 = MethodResolver::Probe (ty
, HIR::PathIdentSegment (associated_item_name
),
146 bool have_implementation_for_lang_item
= !candidates
.empty ();
147 if (!have_implementation_for_lang_item
)
150 // multiple candidates?
151 if (candidates
.size () > 1)
153 // error out? probably not for this case
157 // Get the adjusted self
158 auto candidate
= *candidates
.begin ();
160 TyTy::BaseType
*adjusted_self
= adj
.adjust_type (candidate
.adjustments
);
162 // is this the case we are recursive
163 // handle the case where we are within the impl block for this
164 // lang_item otherwise we end up with a recursive operator overload
165 // such as the i32 operator overload trait
166 TypeCheckContextItem
&fn_context
= context
->peek_context ();
167 if (fn_context
.get_type () == TypeCheckContextItem::ItemType::IMPL_ITEM
)
169 auto &impl_item
= fn_context
.get_impl_item ();
170 HIR::ImplBlock
*parent
= impl_item
.first
;
171 HIR::Function
*fn
= impl_item
.second
;
173 if (parent
->has_trait_ref ()
174 && fn
->get_function_name ().compare (associated_item_name
) == 0)
176 TraitReference
*trait_reference
177 = TraitResolver::Lookup (*parent
->get_trait_ref ().get ());
178 if (!trait_reference
->is_error ())
180 TyTy::BaseType
*lookup
= nullptr;
181 bool ok
= context
->lookup_type (fn
->get_mappings ().get_hirid (),
184 rust_assert (lookup
->get_kind () == TyTy::TypeKind::FNDEF
);
186 TyTy::FnType
*fntype
= static_cast<TyTy::FnType
*> (lookup
);
187 rust_assert (fntype
->is_method ());
189 bool is_lang_item_impl
190 = trait_reference
->get_mappings ().get_defid ()
191 == respective_lang_item_id
;
192 bool self_is_lang_item_self
193 = fntype
->get_self_type ()->is_equal (*adjusted_self
);
194 bool recursive_operator_overload
195 = is_lang_item_impl
&& self_is_lang_item_self
;
197 if (recursive_operator_overload
)
203 TyTy::BaseType
*lookup_tyty
= candidate
.candidate
.ty
;
205 // rust only support impl item deref operator overloading ie you must have an
207 rust_assert (candidate
.candidate
.type
208 == PathProbeCandidate::CandidateType::IMPL_FUNC
);
209 *impl_item
= candidate
.candidate
.item
.impl
.impl_item
;
211 rust_assert (lookup_tyty
->get_kind () == TyTy::TypeKind::FNDEF
);
212 TyTy::BaseType
*lookup
= lookup_tyty
;
213 TyTy::FnType
*fn
= static_cast<TyTy::FnType
*> (lookup
);
214 rust_assert (fn
->is_method ());
216 if (fn
->needs_substitution ())
218 if (ty
->get_kind () == TyTy::TypeKind::ADT
)
220 const TyTy::ADTType
*adt
= static_cast<const TyTy::ADTType
*> (ty
);
222 auto s
= fn
->get_self_type ()->get_root ();
223 rust_assert (s
->can_eq (adt
, false));
224 rust_assert (s
->get_kind () == TyTy::TypeKind::ADT
);
225 const TyTy::ADTType
*self_adt
226 = static_cast<const TyTy::ADTType
*> (s
);
228 // we need to grab the Self substitutions as the inherit type
229 // parameters for this
230 if (self_adt
->needs_substitution ())
232 rust_assert (adt
->was_substituted ());
234 TyTy::SubstitutionArgumentMappings used_args_in_prev_segment
235 = GetUsedSubstArgs::From (adt
);
237 TyTy::SubstitutionArgumentMappings inherit_type_args
238 = self_adt
->solve_mappings_from_receiver_for_self (
239 used_args_in_prev_segment
);
241 // there may or may not be inherited type arguments
242 if (!inherit_type_args
.is_error ())
244 // need to apply the inherited type arguments to the
246 lookup
= fn
->handle_substitions (inherit_type_args
);
252 rust_assert (candidate
.adjustments
.size () < 2);
254 // lets infer the params for this we could probably fix this up by
255 // actually just performing a substitution of a single param but this
256 // seems more generic i think.
258 // this is the case where we had say Foo<&Bar>> and we have derefed to
259 // the &Bar and we are trying to match a method self of Bar which
260 // requires another deref which is matched to the deref trait impl of
261 // &&T so this requires another reference and deref call
263 lookup
= fn
->infer_substitions (Location ());
264 rust_assert (lookup
->get_kind () == TyTy::TypeKind::FNDEF
);
265 fn
= static_cast<TyTy::FnType
*> (lookup
);
267 Location unify_locus
= mappings
->lookup_location (ty
->get_ref ());
268 TypeCheckBase::unify_site (
269 ty
->get_ref (), TyTy::TyWithLocation (fn
->get_self_type ()),
270 TyTy::TyWithLocation (adjusted_self
), unify_locus
);
276 if (candidate
.adjustments
.size () > 0)
277 *requires_ref_adjustment
= candidate
.adjustments
.at (0).get_type ();
279 *resolved_fn
= static_cast<TyTy::FnType
*> (lookup
);
284 AutoderefCycle::AutoderefCycle (bool autoderef_flag
)
285 : autoderef_flag (autoderef_flag
)
288 AutoderefCycle::~AutoderefCycle () {}
291 AutoderefCycle::try_hook (const TyTy::BaseType
&)
295 AutoderefCycle::cycle (const TyTy::BaseType
*receiver
)
297 const TyTy::BaseType
*r
= receiver
;
300 rust_debug ("autoderef try 1: {%s}", r
->debug_str ().c_str ());
301 if (try_autoderefed (r
))
304 // 4. deref to to 1, if cannot deref then quit
310 Adjustment unsize
= Adjuster::try_unsize_type (r
);
311 if (!unsize
.is_error ())
313 adjustments
.push_back (unsize
);
314 auto unsize_r
= unsize
.get_expected ();
316 rust_debug ("autoderef try unsize: {%s}",
317 unsize_r
->debug_str ().c_str ());
318 if (try_autoderefed (unsize_r
))
321 adjustments
.pop_back ();
325 = Adjuster::try_deref_type (r
, Analysis::RustLangItem::ItemType::DEREF
);
326 if (!deref
.is_error ())
328 auto deref_r
= deref
.get_expected ();
329 adjustments
.push_back (deref
);
331 rust_debug ("autoderef try lang-item DEREF: {%s}",
332 deref_r
->debug_str ().c_str ());
333 if (try_autoderefed (deref_r
))
336 adjustments
.pop_back ();
339 Adjustment deref_mut
= Adjuster::try_deref_type (
340 r
, Analysis::RustLangItem::ItemType::DEREF_MUT
);
341 if (!deref_mut
.is_error ())
343 auto deref_r
= deref_mut
.get_expected ();
344 adjustments
.push_back (deref_mut
);
346 rust_debug ("autoderef try lang-item DEREF_MUT: {%s}",
347 deref_r
->debug_str ().c_str ());
348 if (try_autoderefed (deref_r
))
351 adjustments
.pop_back ();
354 if (!deref_mut
.is_error ())
356 auto deref_r
= deref_mut
.get_expected ();
357 adjustments
.push_back (deref_mut
);
358 Adjustment raw_deref
= Adjuster::try_raw_deref_type (deref_r
);
359 adjustments
.push_back (raw_deref
);
360 deref_r
= raw_deref
.get_expected ();
362 if (try_autoderefed (deref_r
))
365 adjustments
.pop_back ();
366 adjustments
.pop_back ();
369 if (!deref
.is_error ())
371 r
= deref
.get_expected ();
372 adjustments
.push_back (deref
);
374 Adjustment raw_deref
= Adjuster::try_raw_deref_type (r
);
375 if (raw_deref
.is_error ())
378 r
= raw_deref
.get_expected ();
379 adjustments
.push_back (raw_deref
);
385 AutoderefCycle::try_autoderefed (const TyTy::BaseType
*r
)
394 TyTy::ReferenceType
*r1
395 = new TyTy::ReferenceType (r
->get_ref (), TyTy::TyVar (r
->get_ref ()),
397 adjustments
.push_back (
398 Adjustment (Adjustment::AdjustmentType::IMM_REF
, r
, r1
));
402 adjustments
.pop_back ();
405 TyTy::ReferenceType
*r2
406 = new TyTy::ReferenceType (r
->get_ref (), TyTy::TyVar (r
->get_ref ()),
408 adjustments
.push_back (
409 Adjustment (Adjustment::AdjustmentType::MUT_REF
, r
, r2
));
413 adjustments
.pop_back ();
418 } // namespace Resolver