Skip to content

Commit a497ed0

Browse files
committed
gccrs: Initial support for Return Position Impl Trait
This is the initial patch for RPIT, we can build on this to handle the more complex cases but there are enough distinct changes going on here that it should just get merged now. RPIT is really a sneaky generic so for example: fn foo() -> impl Bar { Baz } This is represented as: fn () -> OpaqueType Bar. But when we handle the coercion site for Baz on impl Bar when we type resolve the function we know that the underlying type is Baz. Note this function is _not_ generic so its using this special OpaqueType and keeping track of the underlying type in its ty_ref reference hir-id which will resolve to Baz. This also means if we have a case where maybe this was in an if statement: fn foo(a: i32) -> impl Bar { if a > 10 { Baz } else { Qux } } The rules of impl Bar is that Baz is handled but Baz and Qux are different underlying types so this is not allowed. The reason is impl traits are not generic and although from a programmer perspective the callers dont know what the underlying type is, the compiler _knows_ what it is. So really when you call a function and get its return position impl trait the compiler knows what to do and does all whats nessecary to handle calling functions using that type etc. gcc/rust/ChangeLog: * backend/rust-compile-type.cc (TyTyResolveCompile::visit): we need to resolve the underlying type * typecheck/rust-substitution-mapper.cc (SubstMapperInternal::visit): just clone * typecheck/rust-tyty-call.cc (TypeCheckCallExpr::visit): ensure we monomphize to get the underlying * typecheck/rust-tyty.cc (BaseType::destructure): handle opaque types (OpaqueType::resolve): this is much simpler now (OpaqueType::handle_substitions): no longer needed * typecheck/rust-tyty.h: update header * typecheck/rust-unify.cc (UnifyRules::expect_opaque): unify rules for opaque gcc/testsuite/ChangeLog: * rust/compile/bad-rpit1.rs: New test. * rust/execute/torture/impl_rpit1.rs: New test. * rust/execute/torture/impl_rpit2.rs: New test. * rust/execute/torture/impl_rpit3.rs: New test. Signed-off-by: Philip Herron <herron.philip@googlemail.com>
1 parent b401e72 commit a497ed0

10 files changed

Lines changed: 169 additions & 118 deletions

File tree

gcc/rust/backend/rust-compile-type.cc

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -755,7 +755,9 @@ TyTyResolveCompile::visit (const TyTy::DynamicObjectType &type)
755755
void
756756
TyTyResolveCompile::visit (const TyTy::OpaqueType &type)
757757
{
758-
translated = error_mark_node;
758+
rust_assert (type.can_resolve ());
759+
auto underlying = type.resolve ();
760+
translated = TyTyResolveCompile::compile (ctx, underlying, trait_object_mode);
759761
}
760762

761763
tree

gcc/rust/typecheck/rust-substitution-mapper.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -374,7 +374,7 @@ SubstMapperInternal::visit (TyTy::DynamicObjectType &type)
374374
void
375375
SubstMapperInternal::visit (TyTy::OpaqueType &type)
376376
{
377-
resolved = type.handle_substitions (mappings);
377+
resolved = type.clone ();
378378
}
379379

380380
// SubstMapperFromExisting

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ TypeCheckCallExpr::visit (FnType &type)
246246
}
247247

248248
type.monomorphize ();
249-
resolved = type.get_return_type ()->clone ();
249+
resolved = type.get_return_type ()->monomorphized_clone ();
250250
}
251251

252252
void

gcc/rust/typecheck/rust-tyty.cc

Lines changed: 8 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -546,17 +546,14 @@ BaseType::destructure () const
546546
{
547547
x = p->get ();
548548
}
549-
// else if (auto p = x->try_as<const OpaqueType> ())
550-
// {
551-
// auto pr = p->resolve ();
552-
553-
// rust_debug ("XXXXXX")
554-
555-
// if (pr == x)
556-
// return pr;
549+
else if (auto p = x->try_as<const OpaqueType> ())
550+
{
551+
auto pr = p->resolve ();
552+
if (pr == x)
553+
return pr;
557554

558-
// x = pr;
559-
// }
555+
x = pr;
556+
}
560557
else
561558
{
562559
return x;
@@ -3624,28 +3621,7 @@ BaseType *
36243621
OpaqueType::resolve () const
36253622
{
36263623
TyVar var (get_ty_ref ());
3627-
BaseType *r = var.get_tyty ();
3628-
3629-
while (r->get_kind () == TypeKind::OPAQUE)
3630-
{
3631-
OpaqueType *rr = static_cast<OpaqueType *> (r);
3632-
if (!rr->can_resolve ())
3633-
break;
3634-
3635-
TyVar v (rr->get_ty_ref ());
3636-
BaseType *n = v.get_tyty ();
3637-
3638-
// fix infinite loop
3639-
if (r == n)
3640-
break;
3641-
3642-
r = n;
3643-
}
3644-
3645-
if (r->get_kind () == TypeKind::OPAQUE && (r->get_ref () == r->get_ty_ref ()))
3646-
return TyVar (r->get_ty_ref ()).get_tyty ();
3647-
3648-
return r;
3624+
return var.get_tyty ();
36493625
}
36503626

36513627
bool
@@ -3655,41 +3631,9 @@ OpaqueType::is_equal (const BaseType &other) const
36553631
if (can_resolve () != other2.can_resolve ())
36563632
return false;
36573633

3658-
if (can_resolve ())
3659-
return resolve ()->can_eq (other2.resolve (), false);
3660-
36613634
return bounds_compatible (other, UNDEF_LOCATION, false);
36623635
}
36633636

3664-
OpaqueType *
3665-
OpaqueType::handle_substitions (SubstitutionArgumentMappings &subst_mappings)
3666-
{
3667-
// SubstitutionArg arg = SubstitutionArg::error ();
3668-
// bool ok = subst_mappings.get_argument_for_symbol (this, &arg);
3669-
// if (!ok || arg.is_error ())
3670-
// return this;
3671-
3672-
// OpaqueType *p = static_cast<OpaqueType *> (clone ());
3673-
// subst_mappings.on_param_subst (*p, arg);
3674-
3675-
// // there are two cases one where we substitute directly to a new PARAM and
3676-
// // otherwise
3677-
// if (arg.get_tyty ()->get_kind () == TyTy::TypeKind::PARAM)
3678-
// {
3679-
// p->set_ty_ref (arg.get_tyty ()->get_ref ());
3680-
// return p;
3681-
// }
3682-
3683-
// // this is the new subst that this needs to pass
3684-
// p->set_ref (mappings.get_next_hir_id ());
3685-
// p->set_ty_ref (arg.get_tyty ()->get_ref ());
3686-
3687-
// return p;
3688-
3689-
rust_unreachable ();
3690-
return nullptr;
3691-
}
3692-
36933637
// StrType
36943638

36953639
StrType::StrType (HirId ref, std::set<HirId> refs)

gcc/rust/typecheck/rust-tyty.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -441,8 +441,6 @@ class OpaqueType : public BaseType
441441
std::string get_name () const override final;
442442

443443
bool is_equal (const BaseType &other) const override;
444-
445-
OpaqueType *handle_substitions (SubstitutionArgumentMappings &mappings);
446444
};
447445

448446
class StructFieldType

gcc/rust/typecheck/rust-unify.cc

Lines changed: 41 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1788,59 +1788,51 @@ UnifyRules::expect_closure (TyTy::ClosureType *ltype, TyTy::BaseType *rtype)
17881788
TyTy::BaseType *
17891789
UnifyRules::expect_opaque (TyTy::OpaqueType *ltype, TyTy::BaseType *rtype)
17901790
{
1791-
switch (rtype->get_kind ())
1791+
if (rtype->is<TyTy::OpaqueType> ())
17921792
{
1793-
case TyTy::INFER: {
1794-
TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype);
1795-
bool is_valid
1796-
= r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL;
1797-
if (is_valid)
1798-
return ltype->clone ();
1799-
}
1800-
break;
1801-
1802-
case TyTy::OPAQUE: {
1803-
auto &type = *static_cast<TyTy::OpaqueType *> (rtype);
1804-
if (ltype->num_specified_bounds () != type.num_specified_bounds ())
1805-
{
1806-
return new TyTy::ErrorType (0);
1807-
}
1793+
TyTy::OpaqueType *ro = rtype->as<TyTy::OpaqueType> ();
1794+
if (!ltype->is_equal (*ro))
1795+
return new TyTy::ErrorType (0);
18081796

1809-
if (!ltype->bounds_compatible (type, locus, true))
1810-
{
1797+
if (ltype->can_resolve () && ro->can_resolve ())
1798+
{
1799+
auto lr = ltype->resolve ();
1800+
auto rr = ro->resolve ();
1801+
1802+
auto res = UnifyRules::Resolve (TyTy::TyWithLocation (lr),
1803+
TyTy::TyWithLocation (rr), locus,
1804+
commit_flag, false /* emit_error */,
1805+
infer_flag, commits, infers);
1806+
if (res->get_kind () == TyTy::TypeKind::ERROR)
18111807
return new TyTy::ErrorType (0);
1812-
}
1813-
1814-
return ltype->clone ();
1815-
}
1816-
break;
1817-
1818-
case TyTy::CLOSURE:
1819-
case TyTy::SLICE:
1820-
case TyTy::PARAM:
1821-
case TyTy::POINTER:
1822-
case TyTy::STR:
1823-
case TyTy::ADT:
1824-
case TyTy::REF:
1825-
case TyTy::ARRAY:
1826-
case TyTy::FNDEF:
1827-
case TyTy::FNPTR:
1828-
case TyTy::TUPLE:
1829-
case TyTy::BOOL:
1830-
case TyTy::CHAR:
1831-
case TyTy::INT:
1832-
case TyTy::UINT:
1833-
case TyTy::FLOAT:
1834-
case TyTy::USIZE:
1835-
case TyTy::ISIZE:
1836-
case TyTy::NEVER:
1837-
case TyTy::PLACEHOLDER:
1838-
case TyTy::PROJECTION:
1839-
case TyTy::DYNAMIC:
1840-
case TyTy::ERROR:
1841-
return new TyTy::ErrorType (0);
1808+
}
1809+
else if (ltype->can_resolve ())
1810+
{
1811+
auto lr = ltype->resolve ();
1812+
ro->set_ty_ref (lr->get_ref ());
1813+
}
1814+
else if (ro->can_resolve ())
1815+
{
1816+
auto rr = ro->resolve ();
1817+
ltype->set_ty_ref (rr->get_ref ());
1818+
}
18421819
}
1843-
return new TyTy::ErrorType (0);
1820+
else if (ltype->can_resolve ())
1821+
{
1822+
auto underly = ltype->resolve ();
1823+
auto res = UnifyRules::Resolve (TyTy::TyWithLocation (underly),
1824+
TyTy::TyWithLocation (rtype), locus,
1825+
commit_flag, false /* emit_error */,
1826+
infer_flag, commits, infers);
1827+
if (res->get_kind () == TyTy::TypeKind::ERROR)
1828+
return new TyTy::ErrorType (0);
1829+
}
1830+
else
1831+
{
1832+
ltype->set_ty_ref (rtype->get_ref ());
1833+
}
1834+
1835+
return ltype;
18441836
}
18451837

18461838
} // namespace Resolver
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#[lang = "sized"]
2+
trait Sized {}
3+
4+
trait Foo {
5+
fn id(&self) -> i32;
6+
}
7+
8+
struct A;
9+
struct B;
10+
11+
impl Foo for A {
12+
fn id(&self) -> i32 {
13+
1
14+
}
15+
}
16+
17+
impl Foo for B {
18+
fn id(&self) -> i32 {
19+
2
20+
}
21+
}
22+
23+
fn make_foo(cond: bool) -> impl Foo {
24+
if cond { A } else { B }
25+
// { dg-error "mismatched types, expected .A. but got .B. .E0308." "" { target *-*-* } .-1 }
26+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#[lang = "sized"]
2+
trait Sized {}
3+
4+
trait Foo {
5+
fn id(&self) -> i32;
6+
}
7+
8+
struct Thing(i32);
9+
10+
impl Foo for Thing {
11+
fn id(&self) -> i32 {
12+
self.0
13+
}
14+
}
15+
16+
fn make_thing(a: i32) -> impl Foo {
17+
Thing(a)
18+
}
19+
20+
fn use_foo(f: impl Foo) -> i32 {
21+
f.id()
22+
}
23+
24+
fn main() -> i32 {
25+
let value = make_thing(42);
26+
let val = use_foo(value);
27+
val - 42
28+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#[lang = "sized"]
2+
trait Sized {}
3+
4+
trait Foo {
5+
fn id(&self) -> i32;
6+
}
7+
8+
struct Thing(i32);
9+
10+
impl Thing {
11+
fn double(&self) -> i32 {
12+
// { dg-warning "associated function is never used: .double." "" { target *-*-* } .-1 }
13+
self.0 * 2
14+
}
15+
}
16+
17+
impl Foo for Thing {
18+
fn id(&self) -> i32 {
19+
self.0
20+
}
21+
}
22+
23+
fn make_thing(a: i32) -> impl Foo {
24+
Thing(a)
25+
}
26+
27+
fn use_foo(f: impl Foo) -> i32 {
28+
f.id()
29+
}
30+
31+
fn main() -> i32 {
32+
let value = make_thing(21);
33+
let id = use_foo(value);
34+
35+
id - 21
36+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#[lang = "sized"]
2+
trait Sized {}
3+
4+
trait Foo {
5+
fn id(&self) -> i32;
6+
}
7+
8+
struct Thing(i32);
9+
10+
impl Foo for Thing {
11+
fn id(&self) -> i32 {
12+
self.0
13+
}
14+
}
15+
16+
fn make_thing() -> impl Foo {
17+
Thing(99)
18+
}
19+
20+
fn main() -> i32 {
21+
let v = make_thing();
22+
let r = &v;
23+
let val = r.id();
24+
val - 99
25+
}

0 commit comments

Comments
 (0)