Skip to content

Commit 7699f7f

Browse files
committed
gccrs: Add support for binding const generic values to paths
Const generics bind values which can be accessed like a normal path but the difference is that they can be true expression values not just type paths. This patch adds support to resolving a method inference which passes a generic value into the method and fixes some missed bugs along the way. The tricky part was that there is a case where in the return position of a method returning a const param type vs the type of the method there is a special case in the unify rules so that we unify the specified type of the const param type not the const param itself. gcc/rust/ChangeLog: * backend/rust-compile-resolve-path.cc: handle const param values * typecheck/rust-hir-type-check-item.cc: generate const infer vars when required * typecheck/rust-type-util.cc (unify_site_and): handle a null param cleanup * typecheck/rust-tyty-util.cc (TyVar::get_implicit_const_infer_var): helper interface * typecheck/rust-tyty-util.h: update header prototypes * typecheck/rust-tyty.cc (BaseType::is_concrete): correctly handle const types (ConstParamType::get_name): emit the specified type (ConstParamType::is_equal): fix recursion loop * typecheck/rust-unify.cc (UnifyRules::go): const infer vars need cleanup too * typecheck/rust-unify.h: support base generics gcc/testsuite/ChangeLog: * rust/execute/torture/const-generics-2.rs: New test. Signed-off-by: Philip Herron <[email protected]>
1 parent e3ee956 commit 7699f7f

File tree

9 files changed

+141
-48
lines changed

9 files changed

+141
-48
lines changed

gcc/rust/backend/rust-compile-resolve-path.cc

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -132,10 +132,8 @@ ResolvePathRef::resolve_with_node_id (
132132
tl::optional<HirId> hid
133133
= ctx->get_mappings ().lookup_node_to_hir (resolved_node_id);
134134
if (!hid.has_value ())
135-
{
136-
rust_error_at (expr_locus, "reverse call path lookup failure");
137-
return error_mark_node;
138-
}
135+
return error_mark_node;
136+
139137
auto ref = hid.value ();
140138

141139
// might be a constant
@@ -189,6 +187,17 @@ ResolvePathRef::resolve_with_node_id (
189187
}
190188
}
191189

190+
// possibly a const expr value
191+
if (lookup->get_kind () == TyTy::TypeKind::CONST)
192+
{
193+
auto d = lookup->destructure ();
194+
rust_assert (d->get_kind () == TyTy::TypeKind::CONST);
195+
auto c = d->as_const_type ();
196+
rust_assert (c->const_kind () == TyTy::BaseConstType::ConstKind::Value);
197+
auto val = static_cast<TyTy::ConstValueType *> (c);
198+
return val->get_value ();
199+
}
200+
192201
// Handle unit struct
193202
tree resolved_item = error_mark_node;
194203
if (lookup->get_kind () == TyTy::TypeKind::ADT)
@@ -203,9 +212,7 @@ ResolvePathRef::resolve_with_node_id (
203212
resolved_item = query_compile (ref, lookup, final_segment, mappings,
204213
expr_locus, is_qualified_path);
205214
if (resolved_item != error_mark_node)
206-
{
207-
TREE_USED (resolved_item) = 1;
208-
}
215+
TREE_USED (resolved_item) = 1;
209216

210217
return resolved_item;
211218
}

gcc/rust/typecheck/rust-hir-type-check-item.cc

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -112,17 +112,27 @@ TypeCheckItem::ResolveImplBlockSelfWithInference (
112112
std::vector<TyTy::SubstitutionArg> args;
113113
for (auto &p : substitutions)
114114
{
115-
if (p.needs_substitution ())
115+
auto param = p.get_param_ty ();
116+
if (!p.needs_substitution ())
116117
{
117-
TyTy::TyVar infer_var = TyTy::TyVar::get_implicit_infer_var (locus);
118-
args.emplace_back (&p, infer_var.get_tyty ());
118+
auto resolved = param->destructure ();
119+
args.emplace_back (&p, resolved);
120+
121+
continue;
122+
}
123+
124+
TyTy::BaseType *argument = nullptr;
125+
if (param->get_kind () == TyTy::TypeKind::CONST)
126+
{
127+
auto i = TyTy::TyVar::get_implicit_const_infer_var (locus);
128+
argument = i.get_tyty ();
119129
}
120130
else
121131
{
122-
auto param = p.get_param_ty ();
123-
auto resolved = param->destructure ();
124-
args.emplace_back (&p, resolved);
132+
auto i = TyTy::TyVar::get_implicit_infer_var (locus);
133+
argument = i.get_tyty ();
125134
}
135+
args.emplace_back (&p, argument);
126136
}
127137

128138
// create argument mappings

gcc/rust/typecheck/rust-type-util.cc

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -221,13 +221,13 @@ unify_site_and (HirId id, TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs,
221221
}
222222
else if (cleanup)
223223
{
224-
// FIXME
225-
// reset the get_next_hir_id
226-
227224
for (auto &i : infers)
228225
{
229-
i.param->set_ref (i.pref);
230-
i.param->set_ty_ref (i.ptyref);
226+
if (i.param != nullptr)
227+
{
228+
i.param->set_ref (i.pref);
229+
i.param->set_ty_ref (i.ptyref);
230+
}
231231

232232
// remove the inference variable
233233
context.clear_type (i.infer);

gcc/rust/typecheck/rust-tyty-util.cc

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,14 +62,15 @@ TyVar::get_implicit_infer_var (location_t locus)
6262
}
6363

6464
TyVar
65-
TyVar::get_implicit_const_infer_var (location_t locus)
65+
TyVar::get_implicit_const_infer_var (location_t locus, TyVar *implicit_type)
6666
{
6767
auto &mappings = Analysis::Mappings::get ();
6868
auto context = Resolver::TypeCheckContext::get ();
6969

70-
TyVar ty_infer = get_implicit_infer_var (locus);
70+
TyVar it = (implicit_type != nullptr) ? *implicit_type
71+
: get_implicit_infer_var (locus);
7172
HirId next = mappings.get_next_hir_id ();
72-
auto infer = new ConstInferType (ty_infer.get_tyty (), next, next, {});
73+
auto infer = new ConstInferType (it.get_tyty (), next, next, {});
7374

7475
context->insert_implicit_type (infer->get_ref (), infer);
7576
mappings.insert_location (infer->get_ref (), locus);

gcc/rust/typecheck/rust-tyty-util.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,8 @@ class TyVar
4343

4444
static TyVar get_implicit_infer_var (location_t locus);
4545

46-
static TyVar get_implicit_const_infer_var (location_t locus);
46+
static TyVar get_implicit_const_infer_var (location_t locus,
47+
TyVar *implicit_type = nullptr);
4748

4849
static TyVar subst_covariant_var (TyTy::BaseType *orig,
4950
TyTy::BaseType *subst);

gcc/rust/typecheck/rust-tyty.cc

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -785,11 +785,18 @@ BaseType::is_concrete () const
785785
{
786786
const TyTy::BaseType *x = destructure ();
787787

788-
if (x->is<ParamType> () || x->is<ProjectionType> ()
789-
|| x->is<ConstParamType> ())
788+
if (x->is<ParamType> () || x->is<ProjectionType> ())
790789
{
791790
return false;
792791
}
792+
else if (x->get_kind () == TyTy::TypeKind::CONST)
793+
{
794+
auto p = x->as_const_type ();
795+
if (p->const_kind () == BaseConstType::ConstKind::Decl)
796+
return false;
797+
798+
return true;
799+
}
793800
// placeholder is a special case for this case when it is not resolvable
794801
// it means we its just an empty placeholder associated type which is
795802
// concrete
@@ -3633,9 +3640,8 @@ ConstParamType::get_name () const
36333640
return get_symbol ();
36343641

36353642
BaseType *lookup = resolve ();
3636-
// Avoid infinite recursion if resolve() returns this same type
36373643
if (lookup == this->as_base_type ())
3638-
return get_symbol ();
3644+
return get_symbol () + ":" + get_specified_type ()->get_name ();
36393645

36403646
return lookup->get_name ();
36413647
}
@@ -3660,9 +3666,25 @@ ConstParamType::is_equal (const BaseType &other) const
36603666
return false;
36613667

36623668
if (can_resolve ())
3663-
return Resolver::types_compatable (TyTy::TyWithLocation (resolve ()),
3664-
TyTy::TyWithLocation (other2.resolve ()),
3665-
ident.locus, false);
3669+
{
3670+
// Compare the resolved ty_ref values to avoid infinite recursion
3671+
// through types_compatable/unification
3672+
BaseType *lhs = resolve ();
3673+
BaseType *rhs = other2.resolve ();
3674+
3675+
// If they resolve to the same type (same ty_ref), they're equal
3676+
if (lhs->get_ty_ref () == rhs->get_ty_ref ())
3677+
return true;
3678+
3679+
// Otherwise check if the resolved types are equal
3680+
// Avoid recursion by checking if we'd be comparing ConstParamTypes again
3681+
if (lhs->get_kind () == TypeKind::CONST
3682+
&& lhs->as_const_type ()->const_kind ()
3683+
== BaseConstType::ConstKind::Decl)
3684+
return false; // Would cause recursion, so not equal
3685+
3686+
return lhs->is_equal (*rhs);
3687+
}
36663688

36673689
return get_symbol ().compare (other2.get_symbol ()) == 0;
36683690
}

gcc/rust/typecheck/rust-unify.cc

Lines changed: 47 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@
1818

1919
#include "rust-unify.h"
2020
#include "fold-const.h"
21+
#include "rust-tyty-util.h"
2122
#include "rust-tyty.h"
22-
#include "tree.h"
2323

2424
namespace Rust {
2525
namespace Resolver {
@@ -302,35 +302,67 @@ UnifyRules::go ()
302302
else if (ltype->get_kind () == TyTy::TypeKind::CONST
303303
&& rtype->get_kind () == TyTy::TypeKind::CONST)
304304
{
305-
const auto &lhs = *ltype->as_const_type ();
306-
const auto &rhs = *rtype->as_const_type ();
305+
auto lhs = ltype->as_const_type ();
306+
auto rhs = rtype->as_const_type ();
307307

308308
bool both_are_decls
309-
= lhs.const_kind () == TyTy::BaseConstType::ConstKind::Decl
310-
&& rhs.const_kind () == TyTy::BaseConstType::ConstKind::Decl;
309+
= lhs->const_kind () == TyTy::BaseConstType::ConstKind::Decl
310+
&& rhs->const_kind () == TyTy::BaseConstType::ConstKind::Decl;
311311
bool have_decls
312-
= lhs.const_kind () == TyTy::BaseConstType::ConstKind::Decl
313-
|| rhs.const_kind () == TyTy::BaseConstType::ConstKind::Decl;
312+
= lhs->const_kind () == TyTy::BaseConstType::ConstKind::Decl
313+
|| rhs->const_kind () == TyTy::BaseConstType::ConstKind::Decl;
314314

315315
if (have_decls && !both_are_decls)
316316
{
317-
if (lhs.const_kind () == TyTy::BaseConstType::ConstKind::Decl)
317+
if (lhs->const_kind () == TyTy::BaseConstType::ConstKind::Decl)
318318
{
319-
TyTy::TyVar iv = TyTy::TyVar::get_implicit_const_infer_var (
320-
lhs.as_base_type ()->get_locus ());
321-
ltype = iv.get_tyty ();
319+
auto l = lhs->as_base_type ()->get_locus ();
320+
auto p = static_cast<TyTy::ConstParamType *> (lhs);
321+
auto it = TyTy::TyVar::get_implicit_infer_var (l);
322+
auto iv = TyTy::TyVar::get_implicit_const_infer_var (l, &it);
323+
auto ivt = iv.get_tyty ();
324+
325+
infers.emplace_back (0, 0, nullptr, it.get_tyty ());
326+
infers.emplace_back (ltype->get_ref (), ltype->get_ty_ref (),
327+
p, ivt);
328+
329+
ltype = ivt;
330+
p->set_ty_ref (ltype->get_ref ());
322331
}
323-
else if (rhs.const_kind ()
332+
else if (rhs->const_kind ()
324333
== TyTy::BaseConstType::ConstKind::Decl)
325334
{
326-
TyTy::TyVar iv = TyTy::TyVar::get_implicit_const_infer_var (
327-
rhs.as_base_type ()->get_locus ());
328-
rtype = iv.get_tyty ();
335+
auto l = rhs->as_base_type ()->get_locus ();
336+
auto p = static_cast<TyTy::ConstParamType *> (rhs);
337+
auto it = TyTy::TyVar::get_implicit_infer_var (l);
338+
auto iv = TyTy::TyVar::get_implicit_const_infer_var (l, &it);
339+
auto ivt = iv.get_tyty ();
340+
341+
infers.emplace_back (0, 0, nullptr, it.get_tyty ());
342+
infers.emplace_back (rtype->get_ref (), rtype->get_ty_ref (),
343+
p, ivt);
344+
345+
rtype = ivt;
346+
p->set_ty_ref (rtype->get_ref ());
329347
}
330348
}
331349
}
332350
}
333351

352+
if (ltype->get_kind () != TyTy::TypeKind::CONST
353+
&& rtype->get_kind () == TyTy::TypeKind::CONST)
354+
{
355+
auto *rc = rtype->as_const_type ();
356+
rtype = rc->get_specified_type ();
357+
}
358+
359+
if (ltype->get_kind () == TyTy::TypeKind::CONST
360+
&& rtype->get_kind () != TyTy::TypeKind::CONST)
361+
{
362+
auto *lc = ltype->as_const_type ();
363+
ltype = lc->get_specified_type ();
364+
}
365+
334366
switch (ltype->get_kind ())
335367
{
336368
case TyTy::INFER:

gcc/rust/typecheck/rust-unify.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,15 @@ class UnifyRules
3030
public:
3131
struct InferenceSite
3232
{
33-
InferenceSite (HirId pref, HirId ptyref, TyTy::ParamType *param,
34-
TyTy::InferType *infer)
33+
InferenceSite (HirId pref, HirId ptyref, TyTy::BaseGeneric *param,
34+
TyTy::BaseType *infer)
3535
: pref (pref), ptyref (ptyref), param (param), infer (infer)
3636
{}
3737

3838
HirId pref;
3939
HirId ptyref;
40-
TyTy::ParamType *param;
41-
TyTy::InferType *infer;
40+
TyTy::BaseGeneric *param;
41+
TyTy::BaseType *infer;
4242
};
4343
struct CommitSite
4444
{
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#[lang = "sized"]
2+
trait Sized {}
3+
4+
trait Magic {
5+
fn magic(&self) -> usize;
6+
}
7+
8+
struct Foo<const N: usize>;
9+
10+
impl<const N: usize> Magic for Foo<N> {
11+
fn magic(&self) -> usize {
12+
N
13+
}
14+
}
15+
16+
fn main() -> i32 {
17+
let f = Foo::<7> {};
18+
let n = f.magic();
19+
n as i32 - 7
20+
}

0 commit comments

Comments
 (0)