Branch data Line data Source code
1 : : // Copyright (C) 2020-2025 Free Software Foundation, Inc.
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-type-util.h"
24 : :
25 : : namespace Rust {
26 : : namespace Resolver {
27 : :
28 : 6746 : class OverlappingImplItemPass : public TypeCheckBase
29 : : {
30 : : public:
31 : 3373 : static void go ()
32 : : {
33 : 6746 : OverlappingImplItemPass pass;
34 : :
35 : : // generate mappings
36 : 3373 : pass.mappings->iterate_impl_items (
37 : 3373 : [&] (HirId id, HIR::ImplItem *impl_item, HIR::ImplBlock *impl) -> bool {
38 : : // ignoring trait-impls might need thought later on
39 : 4075 : if (impl->has_trait_ref ())
40 : : return true;
41 : :
42 : 1625 : pass.process_impl_item (id, impl_item, impl);
43 : 1625 : return true;
44 : : });
45 : :
46 : 3373 : pass.scan ();
47 : 3373 : }
48 : :
49 : 1625 : void process_impl_item (HirId id, HIR::ImplItem *impl_item,
50 : : HIR::ImplBlock *impl)
51 : : {
52 : : // lets make a mapping of impl-item Self type to (impl-item,name):
53 : : // {
54 : : // impl-type -> [ (item, name), ... ]
55 : : // }
56 : :
57 : 1625 : HirId impl_type_id = impl->get_type ()->get_mappings ().get_hirid ();
58 : 1625 : TyTy::BaseType *impl_type = nullptr;
59 : 1625 : bool ok = query_type (impl_type_id, &impl_type);
60 : 1625 : if (!ok)
61 : 0 : return;
62 : :
63 : 1625 : std::string impl_item_name = impl_item->get_impl_item_name ();
64 : 1625 : std::pair<HIR::ImplItem *, std::string> elem (impl_item, impl_item_name);
65 : 1625 : impl_mappings[impl_type].insert (std::move (elem));
66 : 1625 : }
67 : :
68 : 3373 : void scan ()
69 : : {
70 : : // we can now brute force the map looking for can_eq on each of the
71 : : // impl_items_types to look for possible colliding impl blocks;
72 : 4048 : for (auto it = impl_mappings.begin (); it != impl_mappings.end (); it++)
73 : : {
74 : 675 : TyTy::BaseType *query = it->first;
75 : :
76 : 2230 : for (auto iy = impl_mappings.begin (); iy != impl_mappings.end (); iy++)
77 : : {
78 : 1555 : TyTy::BaseType *candidate = iy->first;
79 : 1555 : if (query == candidate)
80 : 675 : continue;
81 : :
82 : 880 : if (query->can_eq (candidate, false))
83 : : {
84 : : // we might be in the case that we have:
85 : : //
86 : : // *const T vs *const [T]
87 : : //
88 : : // so lets use an equality check when the
89 : : // candidates are both generic to be sure we dont emit a false
90 : : // positive
91 : :
92 : 76 : bool a = query->is_concrete ();
93 : 76 : bool b = candidate->is_concrete ();
94 : 76 : bool both_generic = !a && !b;
95 : 76 : if (both_generic)
96 : : {
97 : 61 : if (!query->is_equal (*candidate))
98 : 61 : continue;
99 : : }
100 : :
101 : 15 : possible_collision (it->second, iy->second);
102 : : }
103 : : }
104 : : }
105 : 3373 : }
106 : :
107 : 15 : void possible_collision (
108 : : std::set<std::pair<HIR::ImplItem *, std::string> > query,
109 : : std::set<std::pair<HIR::ImplItem *, std::string> > candidate)
110 : : {
111 : 30 : for (auto &q : query)
112 : : {
113 : 15 : HIR::ImplItem *query_impl_item = q.first;
114 : 15 : std::string query_impl_item_name = q.second;
115 : :
116 : 30 : for (auto &c : candidate)
117 : : {
118 : 15 : HIR::ImplItem *candidate_impl_item = c.first;
119 : 15 : std::string candidate_impl_item_name = c.second;
120 : :
121 : 15 : if (query_impl_item_name.compare (candidate_impl_item_name) == 0)
122 : 1 : collision_detected (query_impl_item, candidate_impl_item,
123 : : candidate_impl_item_name);
124 : 15 : }
125 : 15 : }
126 : 15 : }
127 : :
128 : 1 : void collision_detected (HIR::ImplItem *query, HIR::ImplItem *dup,
129 : : const std::string &name)
130 : : {
131 : 1 : rich_location r (line_table, dup->get_locus ());
132 : 1 : std::string msg = "duplicate definitions for " + name;
133 : 1 : r.add_fixit_replace (query->get_locus (), msg.c_str ());
134 : 1 : r.add_range (query->get_locus ());
135 : 1 : rust_error_at (r, ErrorCode::E0592, "duplicate definitions with name %qs",
136 : : name.c_str ());
137 : 1 : }
138 : :
139 : : private:
140 : 3373 : OverlappingImplItemPass () : TypeCheckBase () {}
141 : :
142 : : std::map<TyTy::BaseType *,
143 : : std::set<std::pair<HIR::ImplItem *, std::string> > >
144 : : impl_mappings;
145 : : };
146 : :
147 : : } // namespace Resolver
148 : : } // namespace Rust
149 : :
150 : : #endif // RUST_HIR_INHERENT_IMPL_ITEM_OVERLAP_H
|