From: Enes Cevik <[email protected]>
This patch implements the 'unsize' lang item to the compiler.
gcc/rust/ChangeLog:
* typecheck/rust-tyty.cc (BaseType::unsize_to): New function.
(BaseType::satisfies_bound): Use it.
* typecheck/rust-tyty.h (class BaseType): New declaration.
* util/rust-lang-item.cc (Rust::LangItem::lang_items): Add
unsize to the BiMap.
* util/rust-lang-item.h (class LangItem): Add UNSIZE to the Kind
enum.
gcc/testsuite/ChangeLog:
* rust/compile/unsize2.rs: New test.
Signed-off-by: Enes Cevik <[email protected]>
---
This change was merged into the gccrs repository and is posted here for
upstream visibility and potential drive-by review, as requested by GCC
release managers.
Each commit email contains a link to its details on github from where you can
find the Pull-Request and associated discussions.
Commit on github: https://github.com/Rust-GCC/gccrs/commit/942b257486195eaafdff33dad3839b8605ef48f6
The commit has NOT been mentioned in any issue.
The commit has been mentioned in the following pull-request(s):
- https://github.com/Rust-GCC/gccrs/pull/4722
gcc/rust/typecheck/rust-tyty.cc | 91 +++++++++++++++++++++++++++
gcc/rust/typecheck/rust-tyty.h | 2 +
gcc/rust/util/rust-lang-item.cc | 1 +
gcc/rust/util/rust-lang-item.h | 1 +
gcc/testsuite/rust/compile/unsize2.rs | 40 ++++++++++++
5 files changed, 135 insertions(+)
create mode 100644 gcc/testsuite/rust/compile/unsize2.rs
diff --git a/gcc/rust/typecheck/rust-tyty.cc b/gcc/rust/typecheck/rust-tyty.cc
index 65130ea25..72b2f9d7a 100644
--- a/gcc/rust/typecheck/rust-tyty.cc
+++ b/gcc/rust/typecheck/rust-tyty.cc
@@ -288,10 +288,101 @@ BaseType::get_locus () const
return ident.locus;
}
+bool
+BaseType::unsize_to (const BaseType *target) const
+{
+ if (this->get_kind () == TyTy::TypeKind::DYNAMIC
+ && target->get_kind () == TyTy::TypeKind::DYNAMIC)
+ {
+ const auto *source_dyn = this->as<const TyTy::DynamicObjectType> ();
+ const auto *target_dyn = target->as<const TyTy::DynamicObjectType> ();
+
+ const auto &source_bounds = source_dyn->get_specified_bounds ();
+ const auto &target_bounds = target_dyn->get_specified_bounds ();
+
+ if (source_bounds.empty () || target_bounds.empty ())
+ return false;
+
+ if (source_bounds.at (0).get_id () != target_bounds.at (0).get_id ())
+ return false;
+
+ for (const auto &t_bound : target_dyn->get_specified_bounds ())
+ {
+ bool found = false;
+ for (const auto &s_bound : source_dyn->get_specified_bounds ())
+ {
+ if (s_bound.get_id () == t_bound.get_id ())
+ {
+ found = true;
+ break;
+ }
+ }
+ if (!found)
+ return false;
+ }
+ return true;
+ }
+
+ // `T` -> `Trait`
+ else if (target->get_kind () == TyTy::TypeKind::DYNAMIC)
+ return true;
+
+ // Ambiguous handling is below `T` -> `Trait`, because inference
+ // variables can still implement `Unsize<Trait>` and nested
+ // obligations will have the final say (likely deferred).
+ else if (this->destructure ()->is<InferType> ()
+ || target->destructure ()->is<InferType> ())
+ return true;
+
+ // `[T; n]` -> `[T]`
+ else if (this->get_kind () == TyTy::TypeKind::ARRAY
+ && target->get_kind () == TyTy::TypeKind::SLICE)
+ return true;
+
+ // `Struct<T>` -> `Struct<U>`
+ else if (this->get_kind () == TyTy::TypeKind::ADT
+ && target->get_kind () == TyTy::TypeKind::ADT)
+ {
+ const auto *source_adt = this->as<const TyTy::ADTType> ();
+ const auto *target_adt = target->as<const TyTy::ADTType> ();
+ return (source_adt->is_struct_struct () || source_adt->is_tuple_struct ())
+ && source_adt->get_id () == target_adt->get_id ();
+ }
+
+ // `(.., T)` -> `(.., U)`
+ else if (this->get_kind () == TyTy::TypeKind::TUPLE
+ && target->get_kind () == TyTy::TypeKind::TUPLE)
+ {
+ const auto *source_tuple = this->as<const TyTy::TupleType> ();
+ const auto *target_tuple = target->as<const TyTy::TupleType> ();
+ return source_tuple->get_subst_argument_mappings ().size ()
+ == target_tuple->get_subst_argument_mappings ().size ();
+ }
+ return false;
+}
+
// FIXME this is missing locus
bool
BaseType::satisfies_bound (const TypeBoundPredicate &predicate, bool emit_error)
{
+ // see:
+ // https://github.com/rust-lang/rust/blob/e1884a8e3c3e813aada8254edfa120e85bf5ffca/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs#L673
+ if (auto unsize_id = mappings.lookup_lang_item (Rust::LangItem::Kind::UNSIZE))
+ {
+ if (predicate.get_id () == unsize_id)
+ {
+ const auto &args = predicate.get_substitution_arguments ();
+ rust_assert (args.size () == 2 && "Unsize<U>");
+
+ // When this target is defined as `U`, it does not give us the
+ // realized argument type. Instead, it returns `PARAM`.
+ TyTy::BaseType *target
+ = args.get_mappings ().at (1).get_param_ty ()->resolve ();
+
+ return this->unsize_to (target);
+ }
+ }
+
const Resolver::TraitReference *query = predicate.get ();
for (const auto &bound : specified_bounds)
{
diff --git a/gcc/rust/typecheck/rust-tyty.h b/gcc/rust/typecheck/rust-tyty.h
index d607c6b49..ecb2b3e24 100644
--- a/gcc/rust/typecheck/rust-tyty.h
+++ b/gcc/rust/typecheck/rust-tyty.h
@@ -237,6 +237,8 @@ public:
// 2. (For functions) have the same signature
virtual bool is_equal (const BaseType &other) const;
+ bool unsize_to (const BaseType *target) const;
+
bool satisfies_bound (const TypeBoundPredicate &predicate, bool emit_error);
bool bounds_compatible (BaseType &other, location_t locus, bool emit_error);
diff --git a/gcc/rust/util/rust-lang-item.cc b/gcc/rust/util/rust-lang-item.cc
index 5a3e939f9..a54b2e594 100644
--- a/gcc/rust/util/rust-lang-item.cc
+++ b/gcc/rust/util/rust-lang-item.cc
@@ -66,6 +66,7 @@ const BiMap<std::string, LangItem::Kind> Rust::LangItem::lang_items = {{
{"drop", Kind::DROP},
{"sized", Kind::SIZED},
{"freeze", Kind::FREEZE},
+ {"unsize", Kind::UNSIZE},
{"sync", Kind::SYNC},
{"slice_alloc", Kind::SLICE_ALLOC},
{"slice_u8_alloc", Kind::SLICE_U8_ALLOC},
diff --git a/gcc/rust/util/rust-lang-item.h b/gcc/rust/util/rust-lang-item.h
index 766b47c79..476752367 100644
--- a/gcc/rust/util/rust-lang-item.h
+++ b/gcc/rust/util/rust-lang-item.h
@@ -94,6 +94,7 @@ public:
DROP,
SIZED,
FREEZE,
+ UNSIZE,
SYNC,
// https://github.com/Rust-GCC/gccrs/issues/1896
diff --git a/gcc/testsuite/rust/compile/unsize2.rs b/gcc/testsuite/rust/compile/unsize2.rs
new file mode 100644
index 000000000..609380268
--- /dev/null
+++ b/gcc/testsuite/rust/compile/unsize2.rs
@@ -0,0 +1,40 @@
+#![feature(no_core, lang_items, optin_builtin_traits)]
+#![no_core]
+
+#[lang = "sized"]
+pub trait Sized {}
+
+#[lang = "unsize"]
+pub trait Unsize<T: ?Sized> {}
+
+fn unsize_array<T: ?Sized>() where T: Unsize<[i32]> {}
+fn unsize_trait<T: ?Sized>() where T: Unsize<dyn Animal> {}
+fn unsize_dyn<T: ?Sized>() where T: Unsize<dyn Animal> {}
+fn unsize_struct<T: ?Sized>() where T: Unsize<_MyWrapper<[i32]>> {}
+fn unsize_tuple<T: ?Sized>() where T: Unsize<(i32, [i32])> {}
+
+trait Animal {}
+struct _Dog;
+impl Animal for _Dog {}
+auto trait Send {}
+
+struct _MyWrapper<T: ?Sized> {
+ pub data: T,
+}
+
+fn main() {
+ // 1. ARRAY -> SLICE
+ unsize_array::<[i32; 3]>();
+
+ // 2. T -> dyn Trait
+ unsize_trait::<_Dog>();
+
+ // 3. Dynamic -> Dynamic
+ unsize_dyn::<dyn Animal + Send>();
+
+ // 4. Struct -> Struct
+ unsize_struct::<_MyWrapper<[i32; 3]>>();
+
+ // 5. Tuple -> Tuple
+ unsize_tuple::<(i32, [i32; 3])>();
+}
base-commit: 7a3c1de74ae6e3cf18b3ccf81f1a9f356f3e5c74
--
2.54.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not
affiliated with the servers or forums shown here and is not responsible for
the content of articles, which is written by their respective authors.