]>
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 | #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 | ||
25 | namespace Rust { | |
26 | namespace Resolver { | |
27 | ||
28 | class ImplItemToName : private TypeCheckBase, private HIR::HIRImplVisitor | |
29 | { | |
30 | public: | |
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 | ||
56 | private: | |
57 | ImplItemToName (std::string &result) | |
58 | : TypeCheckBase (), ok (false), result (result) | |
59 | {} | |
60 | ||
61 | bool ok; | |
62 | std::string &result; | |
63 | }; | |
64 | ||
65 | class OverlappingImplItemPass : public TypeCheckBase | |
66 | { | |
67 | public: | |
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 | ||
176 | private: | |
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 |