gccrs: Method resolution must support multiple candidates
[official-gcc.git] / gcc / rust / typecheck / rust-hir-inherent-impl-overlap.h
blob6e2fe1b2286eb4d77c7066df9cc4f0fd857672f2
1 // Copyright (C) 2020-2023 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
8 // version.
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.
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 #ifndef RUST_HIR_INHERENT_IMPL_ITEM_OVERLAP_H
20 #define RUST_HIR_INHERENT_IMPL_ITEM_OVERLAP_H
22 #include "rust-hir-type-check-base.h"
23 #include "rust-hir-full.h"
25 namespace Rust {
26 namespace Resolver {
28 class ImplItemToName : private TypeCheckBase, private HIR::HIRImplVisitor
30 public:
31 static bool resolve (HIR::ImplItem *item, std::string &name_result)
33 ImplItemToName resolver (name_result);
34 item->accept_vis (resolver);
35 return resolver.ok;
38 void visit (HIR::TypeAlias &alias) override
40 ok = true;
41 result.assign (alias.get_new_type_name ());
44 void visit (HIR::Function &function) override
46 ok = true;
47 result.assign (function.get_function_name ());
50 void visit (HIR::ConstantItem &constant) override
52 ok = true;
53 result.assign (constant.get_identifier ());
56 private:
57 ImplItemToName (std::string &result)
58 : TypeCheckBase (), ok (false), result (result)
61 bool ok;
62 std::string &result;
65 class OverlappingImplItemPass : public TypeCheckBase
67 public:
68 static void go ()
70 OverlappingImplItemPass pass;
72 // generate mappings
73 pass.mappings->iterate_impl_items (
74 [&] (HirId id, HIR::ImplItem *impl_item, HIR::ImplBlock *impl) -> bool {
75 // ignoring trait-impls might need thought later on
76 if (impl->has_trait_ref ())
77 return true;
79 pass.process_impl_item (id, impl_item, impl);
80 return true;
81 });
83 pass.scan ();
86 void process_impl_item (HirId id, HIR::ImplItem *impl_item,
87 HIR::ImplBlock *impl)
89 // lets make a mapping of impl-item Self type to (impl-item,name):
90 // {
91 // impl-type -> [ (item, name), ... ]
92 // }
94 HirId impl_type_id = impl->get_type ()->get_mappings ().get_hirid ();
95 TyTy::BaseType *impl_type = nullptr;
96 bool ok = query_type (impl_type_id, &impl_type);
97 if (!ok)
98 return;
100 std::string impl_item_name;
101 ok = ImplItemToName::resolve (impl_item, impl_item_name);
102 rust_assert (ok);
104 std::pair<HIR::ImplItem *, std::string> elem (impl_item, impl_item_name);
105 impl_mappings[impl_type].insert (std::move (elem));
108 void scan ()
110 // we can now brute force the map looking for can_eq on each of the
111 // impl_items_types to look for possible colliding impl blocks;
112 for (auto it = impl_mappings.begin (); it != impl_mappings.end (); it++)
114 TyTy::BaseType *query = it->first;
116 for (auto iy = impl_mappings.begin (); iy != impl_mappings.end (); iy++)
118 TyTy::BaseType *candidate = iy->first;
119 if (query == candidate)
120 continue;
122 if (query->can_eq (candidate, false))
124 // we might be in the case that we have:
126 // *const T vs *const [T]
128 // so lets use an equality check when the
129 // candidates are both generic to be sure we dont emit a false
130 // positive
132 bool a = query->is_concrete ();
133 bool b = candidate->is_concrete ();
134 bool both_generic = !a && !b;
135 if (both_generic)
137 if (!query->is_equal (*candidate))
138 continue;
141 possible_collision (it->second, iy->second);
147 void possible_collision (
148 std::set<std::pair<HIR::ImplItem *, std::string> > query,
149 std::set<std::pair<HIR::ImplItem *, std::string> > candidate)
151 for (auto &q : query)
153 HIR::ImplItem *query_impl_item = q.first;
154 std::string query_impl_item_name = q.second;
156 for (auto &c : candidate)
158 HIR::ImplItem *candidate_impl_item = c.first;
159 std::string candidate_impl_item_name = c.second;
161 if (query_impl_item_name.compare (candidate_impl_item_name) == 0)
162 collision_detected (query_impl_item, candidate_impl_item,
163 candidate_impl_item_name);
168 void collision_detected (HIR::ImplItem *query, HIR::ImplItem *dup,
169 const std::string &name)
171 RichLocation r (dup->get_locus ());
172 r.add_range (query->get_locus ());
173 rust_error_at (r, "duplicate definitions with name %s", name.c_str ());
176 private:
177 OverlappingImplItemPass () : TypeCheckBase () {}
179 std::map<TyTy::BaseType *,
180 std::set<std::pair<HIR::ImplItem *, std::string> > >
181 impl_mappings;
184 } // namespace Resolver
185 } // namespace Rust
187 #endif // RUST_HIR_INHERENT_IMPL_ITEM_OVERLAP_H