Skip to content

Commit 4c87325

Browse files
committed
Add support for higher ranked trait bounds
This adds the type checking for the bounds which will add the relevant bounds to the associated types and perform the relevant type checking required. Fixes #442
1 parent 1b9ddc7 commit 4c87325

File tree

6 files changed

+195
-3
lines changed

6 files changed

+195
-3
lines changed

gcc/rust/hir/tree/rust-hir-item.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1387,6 +1387,8 @@ class Struct : public VisItem
13871387
return generic_params;
13881388
}
13891389

1390+
WhereClause &get_where_clause () { return where_clause; }
1391+
13901392
protected:
13911393
Struct (Analysis::NodeMapping mappings, Identifier struct_name,
13921394
std::vector<std::unique_ptr<GenericParam>> generic_params,
@@ -1994,6 +1996,8 @@ class Union : public VisItem
19941996
}
19951997
}
19961998

1999+
WhereClause &get_where_clause () { return where_clause; }
2000+
19972001
protected:
19982002
/* Use covariance to implement clone function as returning this object
19992003
* rather than base */
@@ -2704,6 +2708,8 @@ class ImplBlock : public VisItem
27042708
return trait_ref;
27052709
}
27062710

2711+
WhereClause &get_where_clause () { return where_clause; }
2712+
27072713
protected:
27082714
ImplBlock *clone_item_impl () const override { return new ImplBlock (*this); }
27092715
};

gcc/rust/typecheck/rust-hir-type-check-implitem.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,11 @@ class TypeCheckTopLevelImplItem : public TypeCheckBase
150150
= TypeCheckType::Resolve (alias.get_type_aliased ().get ());
151151

152152
context->insert_type (alias.get_mappings (), actual_type);
153+
154+
for (auto &where_clause_item : alias.get_where_clause ().get_items ())
155+
{
156+
ResolveWhereClauseItem::Resolve (*where_clause_item.get ());
157+
}
153158
}
154159

155160
void visit (HIR::ConstantItem &constant) override
@@ -191,6 +196,11 @@ class TypeCheckTopLevelImplItem : public TypeCheckBase
191196
}
192197
}
193198

199+
for (auto &where_clause_item : function.get_where_clause ().get_items ())
200+
{
201+
ResolveWhereClauseItem::Resolve (*where_clause_item.get ());
202+
}
203+
194204
TyTy::BaseType *ret_type = nullptr;
195205
if (!function.has_function_return_type ())
196206
ret_type = new TyTy::TupleType (function.get_mappings ().get_hirid ());

gcc/rust/typecheck/rust-hir-type-check-toplevel.h

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,11 @@ class TypeCheckTopLevel : public TypeCheckBase
4646
= TypeCheckType::Resolve (alias.get_type_aliased ().get ());
4747

4848
context->insert_type (alias.get_mappings (), actual_type);
49+
50+
for (auto &where_clause_item : alias.get_where_clause ().get_items ())
51+
{
52+
ResolveWhereClauseItem::Resolve (*where_clause_item.get ());
53+
}
4954
}
5055

5156
void visit (HIR::TupleStruct &struct_decl) override
@@ -76,6 +81,11 @@ class TypeCheckTopLevel : public TypeCheckBase
7681
}
7782
}
7883

84+
for (auto &where_clause_item : struct_decl.get_where_clause ().get_items ())
85+
{
86+
ResolveWhereClauseItem::Resolve (*where_clause_item.get ());
87+
}
88+
7989
std::vector<TyTy::StructFieldType *> fields;
8090

8191
size_t idx = 0;
@@ -136,6 +146,11 @@ class TypeCheckTopLevel : public TypeCheckBase
136146
}
137147
}
138148

149+
for (auto &where_clause_item : struct_decl.get_where_clause ().get_items ())
150+
{
151+
ResolveWhereClauseItem::Resolve (*where_clause_item.get ());
152+
}
153+
139154
std::vector<TyTy::StructFieldType *> fields;
140155

141156
for (auto &field : struct_decl.get_fields ())
@@ -188,6 +203,11 @@ class TypeCheckTopLevel : public TypeCheckBase
188203
}
189204
}
190205

206+
for (auto &where_clause_item : union_decl.get_where_clause ().get_items ())
207+
{
208+
ResolveWhereClauseItem::Resolve (*where_clause_item.get ());
209+
}
210+
191211
std::vector<TyTy::StructFieldType *> variants;
192212
union_decl.iterate ([&] (HIR::StructField &variant) mutable -> bool {
193213
TyTy::BaseType *variant_type
@@ -259,6 +279,11 @@ class TypeCheckTopLevel : public TypeCheckBase
259279
}
260280
}
261281

282+
for (auto &where_clause_item : function.get_where_clause ().get_items ())
283+
{
284+
ResolveWhereClauseItem::Resolve (*where_clause_item.get ());
285+
}
286+
262287
TyTy::BaseType *ret_type = nullptr;
263288
if (!function.has_function_return_type ())
264289
ret_type = new TyTy::TupleType (function.get_mappings ().get_hirid ());
@@ -296,6 +321,7 @@ class TypeCheckTopLevel : public TypeCheckBase
296321
TyTy::FnType::FNTYPE_DEFAULT_FLAGS,
297322
ABI::RUST, std::move (params), ret_type,
298323
std::move (substitutions));
324+
299325
context->insert_type (function.get_mappings (), fnType);
300326
}
301327

@@ -327,6 +353,11 @@ class TypeCheckTopLevel : public TypeCheckBase
327353
}
328354
}
329355

356+
for (auto &where_clause_item : impl_block.get_where_clause ().get_items ())
357+
{
358+
ResolveWhereClauseItem::Resolve (*where_clause_item.get ());
359+
}
360+
330361
auto self
331362
= TypeCheckType::Resolve (impl_block.get_type ().get (), &substitutions);
332363
if (self == nullptr || self->get_kind () == TyTy::TypeKind::ERROR)

gcc/rust/typecheck/rust-hir-type-check-type.h

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,111 @@ class TypeResolveGenericParam : public TypeCheckBase
277277
TyTy::ParamType *resolved;
278278
};
279279

280+
class ResolveWhereClauseItem : public TypeCheckBase
281+
{
282+
using Rust::Resolver::TypeCheckBase::visit;
283+
284+
public:
285+
static void Resolve (HIR::WhereClauseItem &item)
286+
{
287+
ResolveWhereClauseItem resolver;
288+
item.accept_vis (resolver);
289+
}
290+
291+
void visit (HIR::LifetimeWhereClauseItem &) override {}
292+
293+
void visit (HIR::TypeBoundWhereClauseItem &item) override
294+
{
295+
auto &binding_type_path = item.get_bound_type ();
296+
TyTy::BaseType *binding = TypeCheckType::Resolve (binding_type_path.get ());
297+
298+
std::vector<TyTy::TypeBoundPredicate> specified_bounds;
299+
for (auto &bound : item.get_type_param_bounds ())
300+
{
301+
switch (bound->get_bound_type ())
302+
{
303+
case HIR::TypeParamBound::BoundType::TRAITBOUND: {
304+
HIR::TraitBound *b
305+
= static_cast<HIR::TraitBound *> (bound.get ());
306+
307+
auto &type_path = b->get_path ();
308+
TraitReference *trait = resolve_trait_path (type_path);
309+
TyTy::TypeBoundPredicate predicate (
310+
trait->get_mappings ().get_defid (), b->get_locus ());
311+
312+
auto &final_seg = type_path.get_final_segment ();
313+
if (final_seg->is_generic_segment ())
314+
{
315+
auto final_generic_seg
316+
= static_cast<HIR::TypePathSegmentGeneric *> (
317+
final_seg.get ());
318+
if (final_generic_seg->has_generic_args ())
319+
{
320+
HIR::GenericArgs &generic_args
321+
= final_generic_seg->get_generic_args ();
322+
323+
// this is applying generic arguments to a trait
324+
// reference
325+
predicate.apply_generic_arguments (&generic_args);
326+
}
327+
}
328+
329+
specified_bounds.push_back (std::move (predicate));
330+
}
331+
break;
332+
333+
default:
334+
break;
335+
}
336+
}
337+
binding->inherit_bounds (specified_bounds);
338+
339+
// When we apply these bounds we must lookup which type this binding
340+
// resolves to, as this is the type which will be used during resolution of
341+
// the block.
342+
NodeId ast_node_id = binding_type_path->get_mappings ().get_nodeid ();
343+
344+
// then lookup the reference_node_id
345+
NodeId ref_node_id = UNKNOWN_NODEID;
346+
if (!resolver->lookup_resolved_type (ast_node_id, &ref_node_id))
347+
{
348+
// FIXME
349+
rust_error_at (Location (),
350+
"Failed to lookup type reference for node: %s",
351+
binding_type_path->as_string ().c_str ());
352+
return;
353+
}
354+
355+
// node back to HIR
356+
HirId ref;
357+
if (!mappings->lookup_node_to_hir (
358+
binding_type_path->get_mappings ().get_crate_num (), ref_node_id,
359+
&ref))
360+
{
361+
// FIXME
362+
rust_error_at (Location (), "where-clause reverse lookup failure");
363+
return;
364+
}
365+
366+
// the base reference for this name _must_ have a type set
367+
TyTy::BaseType *lookup;
368+
if (!context->lookup_type (ref, &lookup))
369+
{
370+
rust_error_at (mappings->lookup_location (ref),
371+
"Failed to resolve where-clause binding type: %s",
372+
binding_type_path->as_string ().c_str ());
373+
return;
374+
}
375+
376+
// FIXME
377+
// rust_assert (binding->is_equal (*lookup));
378+
lookup->inherit_bounds (specified_bounds);
379+
}
380+
381+
private:
382+
ResolveWhereClauseItem () : TypeCheckBase () {}
383+
};
384+
280385
} // namespace Resolver
281386
} // namespace Rust
282387

gcc/testsuite/rust/compile/torture/traits10.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
trait Foo
2-
where
3-
Self: Sized,
1+
trait Foo // where
2+
// Self: Sized,
43
{
54
fn get(self) -> i32;
65
// { dg-warning "unused name" "" { target *-*-* } .-1 }
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/* { dg-output "3\n" } */
2+
extern "C" {
3+
fn printf(s: *const i8, ...);
4+
}
5+
6+
trait FnLike<A, R> {
7+
fn call(&self, arg: A) -> R;
8+
// { dg-warning "unused name .self." "" { target *-*-* } .-1 }
9+
// { dg-warning "unused name .arg." "" { target *-*-* } .-2 }
10+
}
11+
12+
struct S;
13+
impl<'a, T> FnLike<&'a T, &'a T> for S {
14+
fn call(&self, arg: &'a T) -> &'a T {
15+
// { dg-warning "unused name .self." "" { target *-*-* } .-1 }
16+
// { dg-warning "unused name" "" { target *-*-* } .-2 }
17+
arg
18+
}
19+
}
20+
21+
fn indirect<F>(f: F)
22+
where
23+
F: for<'a> FnLike<&'a isize, &'a isize>,
24+
{
25+
let x = 3;
26+
let y = f.call(&x);
27+
28+
unsafe {
29+
let a = "%i\n\0";
30+
let b = a as *const str;
31+
let c = b as *const i8;
32+
33+
printf(c, *y);
34+
}
35+
}
36+
37+
fn main() -> i32 {
38+
indirect(S);
39+
40+
0
41+
}

0 commit comments

Comments
 (0)