]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/rust/typecheck/rust-hir-inherent-impl-overlap.h
Update copyright years.
[thirdparty/gcc.git] / gcc / rust / typecheck / rust-hir-inherent-impl-overlap.h
CommitLineData
a945c346 1// Copyright (C) 2020-2024 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#ifndef RUST_HIR_INHERENT_IMPL_ITEM_OVERLAP_H
20#define RUST_HIR_INHERENT_IMPL_ITEM_OVERLAP_H
21
22#include "rust-hir-type-check-base.h"
23#include "rust-hir-full.h"
24
25namespace Rust {
26namespace Resolver {
27
28class ImplItemToName : private TypeCheckBase, private HIR::HIRImplVisitor
29{
30public:
31 static bool resolve (HIR::ImplItem *item, std::string &name_result)
32 {
33 ImplItemToName resolver (name_result);
34 item->accept_vis (resolver);
35 return resolver.ok;
36 }
37
38 void visit (HIR::TypeAlias &alias) override
39 {
40 ok = true;
41 result.assign (alias.get_new_type_name ());
42 }
43
44 void visit (HIR::Function &function) override
45 {
46 ok = true;
47 result.assign (function.get_function_name ());
48 }
49
50 void visit (HIR::ConstantItem &constant) override
51 {
52 ok = true;
53 result.assign (constant.get_identifier ());
54 }
55
56private:
57 ImplItemToName (std::string &result)
58 : TypeCheckBase (), ok (false), result (result)
59 {}
60
61 bool ok;
62 std::string &result;
63};
64
65class OverlappingImplItemPass : public TypeCheckBase
66{
67public:
68 static void go ()
69 {
70 OverlappingImplItemPass pass;
71
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;
78
79 pass.process_impl_item (id, impl_item, impl);
80 return true;
81 });
82
83 pass.scan ();
84 }
85
86 void process_impl_item (HirId id, HIR::ImplItem *impl_item,
87 HIR::ImplBlock *impl)
88 {
89 // lets make a mapping of impl-item Self type to (impl-item,name):
90 // {
91 // impl-type -> [ (item, name), ... ]
92 // }
93
94 HirId impl_type_id = impl->get_type ()->get_mappings ().get_hirid ();
95 TyTy::BaseType *impl_type = nullptr;
59bee4d4
PH
96 bool ok = query_type (impl_type_id, &impl_type);
97 if (!ok)
98 return;
06688fe4
PH
99
100 std::string impl_item_name;
101 ok = ImplItemToName::resolve (impl_item, impl_item_name);
102 rust_assert (ok);
103
104 std::pair<HIR::ImplItem *, std::string> elem (impl_item, impl_item_name);
105 impl_mappings[impl_type].insert (std::move (elem));
106 }
107
108 void scan ()
109 {
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++)
113 {
114 TyTy::BaseType *query = it->first;
115
116 for (auto iy = impl_mappings.begin (); iy != impl_mappings.end (); iy++)
117 {
118 TyTy::BaseType *candidate = iy->first;
119 if (query == candidate)
120 continue;
121
122 if (query->can_eq (candidate, false))
123 {
124 // we might be in the case that we have:
125 //
126 // *const T vs *const [T]
127 //
128 // so lets use an equality check when the
129 // candidates are both generic to be sure we dont emit a false
130 // positive
131
132 bool a = query->is_concrete ();
133 bool b = candidate->is_concrete ();
134 bool both_generic = !a && !b;
135 if (both_generic)
136 {
137 if (!query->is_equal (*candidate))
138 continue;
139 }
140
141 possible_collision (it->second, iy->second);
142 }
143 }
144 }
145 }
146
147 void possible_collision (
148 std::set<std::pair<HIR::ImplItem *, std::string> > query,
149 std::set<std::pair<HIR::ImplItem *, std::string> > candidate)
150 {
151 for (auto &q : query)
152 {
153 HIR::ImplItem *query_impl_item = q.first;
154 std::string query_impl_item_name = q.second;
155
156 for (auto &c : candidate)
157 {
158 HIR::ImplItem *candidate_impl_item = c.first;
159 std::string candidate_impl_item_name = c.second;
160
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);
164 }
165 }
166 }
167
168 void collision_detected (HIR::ImplItem *query, HIR::ImplItem *dup,
169 const std::string &name)
170 {
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 ());
174 }
175
176private:
177 OverlappingImplItemPass () : TypeCheckBase () {}
178
179 std::map<TyTy::BaseType *,
180 std::set<std::pair<HIR::ImplItem *, std::string> > >
181 impl_mappings;
182};
183
184} // namespace Resolver
185} // namespace Rust
186
187#endif // RUST_HIR_INHERENT_IMPL_ITEM_OVERLAP_H