Skip to content

Commit af48e2a

Browse files
Merge #1186
1186: Refactor `ResolvePath` in its own file r=CohenArthur a=CohenArthur Co-authored-by: Arthur Cohen <[email protected]>
2 parents 9a9bb44 + 10b01c3 commit af48e2a

7 files changed

+328
-266
lines changed

gcc/rust/Make-lang.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ GRS_OBJS = \
9191
rust/rust-ast-resolve-pattern.o \
9292
rust/rust-ast-resolve-expr.o \
9393
rust/rust-ast-resolve-type.o \
94+
rust/rust-ast-resolve-path.o \
9495
rust/rust-hir-type-check.o \
9596
rust/rust-privacy-check.o \
9697
rust/rust-privacy-ctx.o \

gcc/rust/resolve/rust-ast-resolve-expr.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "rust-ast-verify-assignee.h"
2323
#include "rust-ast-resolve-type.h"
2424
#include "rust-ast-resolve-pattern.h"
25+
#include "rust-ast-resolve-path.h"
2526

2627
namespace Rust {
2728
namespace Resolver {

gcc/rust/resolve/rust-ast-resolve-expr.h

Lines changed: 0 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -25,35 +25,6 @@
2525
namespace Rust {
2626
namespace Resolver {
2727

28-
class ResolvePath : public ResolverBase
29-
{
30-
using Rust::Resolver::ResolverBase::visit;
31-
32-
public:
33-
static void go (AST::PathInExpression *expr, NodeId parent)
34-
{
35-
ResolvePath resolver (parent);
36-
resolver.resolve_path (expr);
37-
}
38-
39-
static void go (AST::QualifiedPathInExpression *expr, NodeId parent)
40-
{
41-
ResolvePath resolver (parent);
42-
resolver.resolve_path (expr);
43-
}
44-
45-
private:
46-
ResolvePath (NodeId parent) : ResolverBase (parent) {}
47-
48-
void resolve_path (AST::PathInExpression *expr);
49-
50-
void resolve_path (AST::QualifiedPathInExpression *expr);
51-
52-
void resolve_segments (CanonicalPath prefix, size_t offs,
53-
std::vector<AST::PathExprSegment> &segs,
54-
NodeId expr_node_id, Location expr_locus);
55-
};
56-
5728
class ResolveExpr : public ResolverBase
5829
{
5930
using Rust::Resolver::ResolverBase::visit;
Lines changed: 276 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,276 @@
1+
// Copyright (C) 2020-2022 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+
#include "rust-ast-resolve-path.h"
20+
#include "rust-ast-resolve-type.h"
21+
#include "rust-path.h"
22+
23+
namespace Rust {
24+
namespace Resolver {
25+
26+
void
27+
ResolvePath::go (AST::PathInExpression *expr, NodeId parent)
28+
{
29+
ResolvePath resolver (parent);
30+
resolver.resolve_path (expr);
31+
}
32+
33+
void
34+
ResolvePath::go (AST::QualifiedPathInExpression *expr, NodeId parent)
35+
{
36+
ResolvePath resolver (parent);
37+
resolver.resolve_path (expr);
38+
}
39+
40+
void
41+
ResolvePath::resolve_path (AST::PathInExpression *expr)
42+
{
43+
// resolve root segment first then apply segments in turn
44+
std::vector<AST::PathExprSegment> &segs = expr->get_segments ();
45+
AST::PathExprSegment &root_segment = segs.at (0);
46+
AST::PathIdentSegment &root_ident_seg = root_segment.get_ident_segment ();
47+
48+
bool segment_is_type = false;
49+
CanonicalPath root_seg_path
50+
= CanonicalPath::new_seg (root_segment.get_node_id (),
51+
root_ident_seg.as_string ());
52+
53+
// name scope first
54+
if (resolver->get_name_scope ().lookup (root_seg_path, &resolved_node))
55+
{
56+
segment_is_type = false;
57+
resolver->insert_resolved_name (root_segment.get_node_id (),
58+
resolved_node);
59+
resolver->insert_new_definition (root_segment.get_node_id (),
60+
Definition{expr->get_node_id (),
61+
parent});
62+
}
63+
// check the type scope
64+
else if (resolver->get_type_scope ().lookup (root_seg_path, &resolved_node))
65+
{
66+
segment_is_type = true;
67+
resolver->insert_resolved_type (root_segment.get_node_id (),
68+
resolved_node);
69+
resolver->insert_new_definition (root_segment.get_node_id (),
70+
Definition{expr->get_node_id (),
71+
parent});
72+
}
73+
else
74+
{
75+
rust_error_at (expr->get_locus (),
76+
"Cannot find path %<%s%> in this scope",
77+
root_segment.as_string ().c_str ());
78+
return;
79+
}
80+
81+
if (root_segment.has_generic_args ())
82+
{
83+
bool ok = ResolveTypeToCanonicalPath::type_resolve_generic_args (
84+
root_segment.get_generic_args ());
85+
if (!ok)
86+
{
87+
rust_error_at (root_segment.get_locus (),
88+
"failed to resolve generic arguments");
89+
return;
90+
}
91+
}
92+
93+
bool is_single_segment = segs.size () == 1;
94+
if (is_single_segment)
95+
{
96+
if (segment_is_type)
97+
resolver->insert_resolved_type (expr->get_node_id (), resolved_node);
98+
else
99+
resolver->insert_resolved_name (expr->get_node_id (), resolved_node);
100+
101+
resolver->insert_new_definition (expr->get_node_id (),
102+
Definition{expr->get_node_id (),
103+
parent});
104+
return;
105+
}
106+
107+
resolve_segments (root_seg_path, 1, expr->get_segments (),
108+
expr->get_node_id (), expr->get_locus ());
109+
}
110+
111+
void
112+
ResolvePath::resolve_path (AST::QualifiedPathInExpression *expr)
113+
{
114+
AST::QualifiedPathType &root_segment = expr->get_qualified_path_type ();
115+
116+
bool canonicalize_type_with_generics = false;
117+
ResolveType::go (&root_segment.get_as_type_path (),
118+
root_segment.get_node_id (),
119+
canonicalize_type_with_generics);
120+
121+
ResolveType::go (root_segment.get_type ().get (), root_segment.get_node_id (),
122+
canonicalize_type_with_generics);
123+
124+
bool type_resolve_generic_args = true;
125+
CanonicalPath impl_type_seg
126+
= ResolveTypeToCanonicalPath::resolve (*root_segment.get_type ().get (),
127+
canonicalize_type_with_generics,
128+
type_resolve_generic_args);
129+
130+
CanonicalPath trait_type_seg
131+
= ResolveTypeToCanonicalPath::resolve (root_segment.get_as_type_path (),
132+
canonicalize_type_with_generics,
133+
type_resolve_generic_args);
134+
CanonicalPath root_seg_path
135+
= TraitImplProjection::resolve (root_segment.get_node_id (), trait_type_seg,
136+
impl_type_seg);
137+
bool segment_is_type = false;
138+
139+
// name scope first
140+
if (resolver->get_name_scope ().lookup (root_seg_path, &resolved_node))
141+
{
142+
segment_is_type = false;
143+
resolver->insert_resolved_name (root_segment.get_node_id (),
144+
resolved_node);
145+
resolver->insert_new_definition (root_segment.get_node_id (),
146+
Definition{expr->get_node_id (),
147+
parent});
148+
}
149+
// check the type scope
150+
else if (resolver->get_type_scope ().lookup (root_seg_path, &resolved_node))
151+
{
152+
segment_is_type = true;
153+
resolver->insert_resolved_type (root_segment.get_node_id (),
154+
resolved_node);
155+
resolver->insert_new_definition (root_segment.get_node_id (),
156+
Definition{expr->get_node_id (),
157+
parent});
158+
}
159+
else
160+
{
161+
rust_error_at (expr->get_locus (),
162+
"Cannot find path %<%s%> in this scope",
163+
root_segment.as_string ().c_str ());
164+
return;
165+
}
166+
167+
bool is_single_segment = expr->get_segments ().empty ();
168+
if (is_single_segment)
169+
{
170+
if (segment_is_type)
171+
resolver->insert_resolved_type (expr->get_node_id (), resolved_node);
172+
else
173+
resolver->insert_resolved_name (expr->get_node_id (), resolved_node);
174+
175+
resolver->insert_new_definition (expr->get_node_id (),
176+
Definition{expr->get_node_id (),
177+
parent});
178+
return;
179+
}
180+
181+
resolve_segments (root_seg_path, 0, expr->get_segments (),
182+
expr->get_node_id (), expr->get_locus ());
183+
}
184+
185+
void
186+
ResolvePath::resolve_segments (CanonicalPath prefix, size_t offs,
187+
std::vector<AST::PathExprSegment> &segs,
188+
NodeId expr_node_id, Location expr_locus)
189+
{
190+
// we can attempt to resolve this path fully
191+
CanonicalPath path = prefix;
192+
bool segment_is_type = false;
193+
for (size_t i = offs; i < segs.size (); i++)
194+
{
195+
AST::PathExprSegment &seg = segs.at (i);
196+
auto s = ResolvePathSegmentToCanonicalPath::resolve (seg);
197+
path = path.append (s);
198+
199+
// reset state
200+
segment_is_type = false;
201+
resolved_node = UNKNOWN_NODEID;
202+
203+
if (resolver->get_name_scope ().lookup (path, &resolved_node))
204+
{
205+
resolver->insert_resolved_name (seg.get_node_id (), resolved_node);
206+
resolver->insert_new_definition (seg.get_node_id (),
207+
Definition{expr_node_id, parent});
208+
}
209+
// check the type scope
210+
else if (resolver->get_type_scope ().lookup (path, &resolved_node))
211+
{
212+
segment_is_type = true;
213+
resolver->insert_resolved_type (seg.get_node_id (), resolved_node);
214+
resolver->insert_new_definition (seg.get_node_id (),
215+
Definition{expr_node_id, parent});
216+
}
217+
else
218+
{
219+
// attempt to fully resolve the path which is allowed to fail given
220+
// the following scenario
221+
//
222+
// https://github.com/Rust-GCC/gccrs/issues/355 Paths are
223+
// resolved fully here, there are limitations though imagine:
224+
//
225+
// struct Foo<A> (A);
226+
//
227+
// impl Foo<isize> {
228+
// fn test() -> ...
229+
//
230+
// impl Foo<f32> {
231+
// fn test() -> ...
232+
//
233+
// fn main() {
234+
// let a:i32 = Foo::test();
235+
//
236+
// there are multiple paths that test can resolve to Foo::<?>::test
237+
// here so we cannot resolve this case
238+
//
239+
// canonical names:
240+
//
241+
// struct Foo<A> -> Foo
242+
// impl Foo<isize>::fn test -> Foo::isize::test
243+
// impl Foo<f32>::fn test -> Foo::f32::test
244+
//
245+
// Since there is the case we have the following paths for test:
246+
//
247+
// Foo::isize::test
248+
// Foo::f32::test
249+
// vs
250+
// Foo::test
251+
//
252+
// but the lookup was simply Foo::test we must rely on type resolution
253+
// to figure this type out in a similar fashion to method resolution
254+
// with a probe phase
255+
256+
// nothing more we can do we need the type resolver to try and resolve
257+
// this
258+
return;
259+
}
260+
}
261+
262+
// its fully resolved lets mark it as such
263+
if (resolved_node != UNKNOWN_NODEID)
264+
{
265+
if (segment_is_type)
266+
resolver->insert_resolved_type (expr_node_id, resolved_node);
267+
else
268+
resolver->insert_resolved_name (expr_node_id, resolved_node);
269+
270+
resolver->insert_new_definition (expr_node_id,
271+
Definition{expr_node_id, parent});
272+
}
273+
}
274+
275+
} // namespace Resolver
276+
} // namespace Rust
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// Copyright (C) 2020-2022 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_AST_RESOLVE_PATH_H
20+
#define RUST_AST_RESOLVE_PATH_H
21+
22+
#include "rust-ast-resolve-base.h"
23+
24+
namespace Rust {
25+
namespace Resolver {
26+
27+
class ResolvePath : public ResolverBase
28+
{
29+
using Rust::Resolver::ResolverBase::visit;
30+
31+
public:
32+
static void go (AST::PathInExpression *expr, NodeId parent);
33+
static void go (AST::QualifiedPathInExpression *expr, NodeId parent);
34+
35+
private:
36+
ResolvePath (NodeId parent) : ResolverBase (parent) {}
37+
38+
void resolve_path (AST::PathInExpression *expr);
39+
void resolve_path (AST::QualifiedPathInExpression *expr);
40+
41+
void resolve_segments (CanonicalPath prefix, size_t offs,
42+
std::vector<AST::PathExprSegment> &segs,
43+
NodeId expr_node_id, Location expr_locus);
44+
};
45+
46+
} // namespace Resolver
47+
} // namespace Rust
48+
49+
#endif // !RUST_AST_RESOLVE_PATH_H

gcc/rust/resolve/rust-ast-resolve-pattern.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
// <http://www.gnu.org/licenses/>.
1818

1919
#include "rust-ast-resolve-pattern.h"
20+
#include "rust-ast-resolve-path.h"
2021
#include "rust-ast-resolve-expr.h"
2122

2223
namespace Rust {

0 commit comments

Comments
 (0)