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 : 7924 : class OverlappingImplItemPass : public TypeCheckBase
29 : : {
30 : : public:
31 : 3962 : static void go ()
32 : : {
33 : 7924 : OverlappingImplItemPass pass;
34 : :
35 : : // generate mappings
36 : 3962 : pass.mappings.iterate_impl_items (
37 : 3962 : [&] (HirId id, HIR::ImplItem *impl_item, HIR::ImplBlock *impl) -> bool {
38 : : // ignoring trait-impls might need thought later on
39 : 7981 : if (impl->has_trait_ref ())
40 : : return true;
41 : :
42 : 2686 : pass.process_impl_item (id, impl_item, impl);
43 : 2686 : return true;
44 : : });
45 : :
46 : 3962 : pass.scan ();
47 : 3962 : }
48 : :
49 : 2686 : 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 : 2686 : HirId impl_type_id = impl->get_type ().get_mappings ().get_hirid ();
58 : 2686 : TyTy::BaseType *impl_type = nullptr;
59 : 2686 : bool ok = query_type (impl_type_id, &impl_type);
60 : 2686 : if (!ok)
61 : 0 : return;
62 : :
63 : 2686 : std::string impl_item_name = impl_item->get_impl_item_name ();
64 : 2686 : std::pair<HIR::ImplItem *, std::string> elem (impl_item, impl_item_name);
65 : 2686 : impl_mappings[impl_type].insert (std::move (elem));
66 : 2686 : }
67 : :
68 : 3962 : 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 : 4863 : for (auto it = impl_mappings.begin (); it != impl_mappings.end (); it++)
73 : : {
74 : 901 : TyTy::BaseType *query = it->first;
75 : :
76 : 4146 : for (auto iy = impl_mappings.begin (); iy != impl_mappings.end (); iy++)
77 : : {
78 : 3245 : TyTy::BaseType *candidate = iy->first;
79 : 901 : if (query == candidate)
80 : 901 : continue;
81 : :
82 : 2344 : if (!types_compatable (TyTy::TyWithLocation (query),
83 : 2344 : TyTy::TyWithLocation (candidate),
84 : : UNKNOWN_LOCATION, false))
85 : 2300 : continue;
86 : :
87 : : // we might be in the case that we have:
88 : : //
89 : : // *const T vs *const [T]
90 : : //
91 : : // so lets use an equality check when the
92 : : // candidates are both generic to be sure we dont emit a false
93 : : // positive
94 : :
95 : 44 : bool a = query->is_concrete ();
96 : 44 : bool b = candidate->is_concrete ();
97 : 44 : bool both_generic = !a && !b;
98 : 44 : if (both_generic)
99 : : {
100 : 28 : if (!query->is_equal (*candidate))
101 : 28 : continue;
102 : : }
103 : :
104 : 16 : possible_collision (it->second, iy->second);
105 : : }
106 : : }
107 : 3962 : }
108 : :
109 : 16 : void possible_collision (
110 : : std::set<std::pair<HIR::ImplItem *, std::string> > query,
111 : : std::set<std::pair<HIR::ImplItem *, std::string> > candidate)
112 : : {
113 : 32 : for (auto &q : query)
114 : : {
115 : 16 : HIR::ImplItem *query_impl_item = q.first;
116 : 16 : std::string query_impl_item_name = q.second;
117 : :
118 : 32 : for (auto &c : candidate)
119 : : {
120 : 16 : HIR::ImplItem *candidate_impl_item = c.first;
121 : 16 : std::string candidate_impl_item_name = c.second;
122 : :
123 : 16 : if (query_impl_item_name.compare (candidate_impl_item_name) == 0)
124 : 2 : collision_detected (query_impl_item, candidate_impl_item,
125 : : candidate_impl_item_name);
126 : 16 : }
127 : 16 : }
128 : 16 : }
129 : :
130 : 2 : void collision_detected (HIR::ImplItem *query, HIR::ImplItem *dup,
131 : : const std::string &name)
132 : : {
133 : 2 : rich_location r (line_table, dup->get_locus ());
134 : 2 : std::string msg = "duplicate definitions for " + name;
135 : 2 : r.add_fixit_replace (query->get_locus (), msg.c_str ());
136 : 2 : r.add_range (query->get_locus ());
137 : 2 : rust_error_at (r, ErrorCode::E0592, "duplicate definitions with name %qs",
138 : : name.c_str ());
139 : 2 : }
140 : :
141 : : private:
142 : 3962 : OverlappingImplItemPass () : TypeCheckBase () {}
143 : :
144 : : std::map<TyTy::BaseType *,
145 : : std::set<std::pair<HIR::ImplItem *, std::string> > >
146 : : impl_mappings;
147 : : };
148 : :
149 : : } // namespace Resolver
150 : : } // namespace Rust
151 : :
152 : : #endif // RUST_HIR_INHERENT_IMPL_ITEM_OVERLAP_H
|