1 // Copyright (C) 2020-2023 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_CANONICAL_PATH
20 #define RUST_CANONICAL_PATH
21
22 #include "rust-system.h"
23 #include "rust-mapping-common.h"
24
25 namespace Rust {
26 namespace Resolver {
27
28 // https://doc.rust-lang.org/reference/paths.html#canonical-paths
29 //
30 // struct X - path X
31 // impl X { fn test - path X::test }
32 //
33 // struct X<T> - path X
34 //
35 // impl X<T> { fn test - path X::test}
36 // impl X<i32> { fn test - path X<i32>::test }
37 // impl X<f32> { fn test - path X<f32>::test }
38 //
39 // pub trait Trait { // ::a::Trait
40 // fn f(&self); // ::a::Trait::f
41 // }
42 //
43 // impl Trait for Struct {
44 // fn f(&self) {} // <::a::Struct as ::a::Trait>::f
45 // }
46 class CanonicalPath
47 {
48 public:
49 CanonicalPath (const CanonicalPath &other) : segs (other.segs) {}
50
51 CanonicalPath &operator= (const CanonicalPath &other)
52 {
53 segs = other.segs;
54 return *this;
55 }
56
57 static CanonicalPath new_seg (NodeId id, const std::string &path)
58 {
59 rust_assert (!path.empty ());
60 return CanonicalPath ({std::pair<NodeId, std::string> (id, path)},
61 UNKNOWN_CREATENUM);
62 }
63
64 static CanonicalPath
65 trait_impl_projection_seg (NodeId id, const CanonicalPath &trait_seg,
66 const CanonicalPath &impl_type_seg)
67 {
68 return CanonicalPath::new_seg (id, "<" + impl_type_seg.get () + " as "
69 + trait_seg.get () + ">");
70 }
71
72 std::string get () const
73 {
74 std::string buf;
75 for (size_t i = 0; i < segs.size (); i++)
76 {
77 bool have_more = (i + 1) < segs.size ();
78 const std::string &seg = segs.at (i).second;
79 buf += seg + (have_more ? "::" : "");
80 }
81 return buf;
82 }
83
84 static CanonicalPath get_big_self (NodeId id)
85 {
86 return CanonicalPath::new_seg (id, "Self");
87 }
88
89 static CanonicalPath create_empty ()
90 {
91 return CanonicalPath ({}, UNKNOWN_CREATENUM);
92 }
93
94 bool is_empty () const { return segs.size () == 0; }
95
96 CanonicalPath append (const CanonicalPath &other) const
97 {
98 rust_assert (!other.is_empty ());
99 if (is_empty ())
100 return CanonicalPath (other.segs, crate_num);
101
102 std::vector<std::pair<NodeId, std::string>> copy (segs);
103 for (auto &s : other.segs)
104 copy.push_back (s);
105
106 return CanonicalPath (copy, crate_num);
107 }
108
109 // if we have the path A::B::C this will give a callback for each segment
110 // including the prefix, example:
111 //
112 // path:
113 // A::B::C
114 //
115 // iterate:
116 // A
117 // A::B
118 // A::B::C
119 void iterate (std::function<bool (const CanonicalPath &)> cb) const
120 {
121 std::vector<std::pair<NodeId, std::string>> buf;
122 for (auto &seg : segs)
123 {
124 buf.push_back (seg);
125 if (!cb (CanonicalPath (buf, crate_num)))
126 return;
127 }
128 }
129
130 // if we have the path A::B::C this will give a callback for each segment
131 // example:
132 //
133 // path:
134 // A::B::C
135 //
136 // iterate:
137 // A
138 // B
139 // C
140 void iterate_segs (std::function<bool (const CanonicalPath &)> cb) const
141 {
142 for (auto &seg : segs)
143 {
144 std::vector<std::pair<NodeId, std::string>> buf;
145 buf.push_back ({seg.first, seg.second});
146 if (!cb (CanonicalPath (buf, crate_num)))
147 return;
148 }
149 }
150
151 size_t size () const { return segs.size (); }
152
153 NodeId get_node_id () const
154 {
155 rust_assert (!segs.empty ());
156 return segs.back ().first;
157 }
158
159 const std::pair<NodeId, std::string> &get_seg_at (size_t index) const
160 {
161 rust_assert (index < size ());
162 return segs.at (index);
163 }
164
165 bool is_equal (const CanonicalPath &b) const
166 {
167 return get ().compare (b.get ()) == 0;
168 }
169
170 void set_crate_num (CrateNum n) { crate_num = n; }
171
172 CrateNum get_crate_num () const
173 {
174 rust_assert (crate_num != UNKNOWN_CREATENUM);
175 return crate_num;
176 }
177
178 bool operator== (const CanonicalPath &b) const { return is_equal (b); }
179
180 bool operator< (const CanonicalPath &b) const { return get () < b.get (); }
181
182 private:
183 explicit CanonicalPath (std::vector<std::pair<NodeId, std::string>> path,
184 CrateNum crate_num)
185 : segs (path), crate_num (crate_num)
186 {}
187
188 std::vector<std::pair<NodeId, std::string>> segs;
189 CrateNum crate_num;
190 };
191
192 } // namespace Resolver
193 } // namespace Rust
194
195 #endif // RUST_CANONICAL_PATH