aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2021-09-17 21:35:13 +0000
committerGitHub <noreply@github.com>2021-09-17 21:35:13 +0000
commitde43a0ac6d4d5816a5b59cde78aabce651d43cc8 (patch)
treed50a81ea97725eee5abe8d4b881e265c04fd80c0 /gcc
parent384cc64dab40edca1f59f369e162df89aa1e91f8 (diff)
parentfabaf7d6caf919ceaa05f2db4260fa897864d517 (diff)
downloadgcc-de43a0ac6d4d5816a5b59cde78aabce651d43cc8.zip
gcc-de43a0ac6d4d5816a5b59cde78aabce651d43cc8.tar.gz
gcc-de43a0ac6d4d5816a5b59cde78aabce651d43cc8.tar.bz2
Merge #684
684: Initial Dynamic dispatch support r=philberty a=philberty This rebases my branch for dynamic dispatch (dyn bound) support it supports the HIR::TraitObjectOneBound for now but can be easily extended. The computation of the addresses of the methods only supports impl items and does not support optional trait methods yet but the change set was already 10 commits and this seems like a good initial stab at support here. Please see the git commits for more detail information on each change. Fixes #197 Co-authored-by: Philip Herron <philip.herron@embecosm.com>
Diffstat (limited to 'gcc')
-rw-r--r--gcc/rust/backend/rust-compile-base.h13
-rw-r--r--gcc/rust/backend/rust-compile-context.h70
-rw-r--r--gcc/rust/backend/rust-compile-stmt.h12
-rw-r--r--gcc/rust/backend/rust-compile-tyty.h2
-rw-r--r--gcc/rust/backend/rust-compile.cc255
-rw-r--r--gcc/rust/hir/tree/rust-hir-item.h2
-rw-r--r--gcc/rust/typecheck/rust-hir-const-fold.h2
-rw-r--r--gcc/rust/typecheck/rust-hir-trait-ref.h50
-rw-r--r--gcc/rust/typecheck/rust-hir-trait-resolve.cc30
-rw-r--r--gcc/rust/typecheck/rust-hir-trait-resolve.h5
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-expr.h11
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-implitem.h3
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-type.cc19
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-type.h5
-rw-r--r--gcc/rust/typecheck/rust-substitution-mapper.h4
-rw-r--r--gcc/rust/typecheck/rust-tyty-bounds.cc19
-rw-r--r--gcc/rust/typecheck/rust-tyty-call.h56
-rw-r--r--gcc/rust/typecheck/rust-tyty-cast.h38
-rw-r--r--gcc/rust/typecheck/rust-tyty-cmp.h56
-rw-r--r--gcc/rust/typecheck/rust-tyty-coercion.h101
-rw-r--r--gcc/rust/typecheck/rust-tyty-rules.h66
-rw-r--r--gcc/rust/typecheck/rust-tyty-visitor.h2
-rw-r--r--gcc/rust/typecheck/rust-tyty.cc133
-rw-r--r--gcc/rust/typecheck/rust-tyty.h68
-rw-r--r--gcc/testsuite/rust/compile/traits10.rs16
-rw-r--r--gcc/testsuite/rust/compile/traits11.rs20
-rw-r--r--gcc/testsuite/rust/compile/traits9.rs13
-rw-r--r--gcc/testsuite/rust/compile/tuple_struct3.rs6
-rw-r--r--gcc/testsuite/rust/execute/torture/trait5.rs41
29 files changed, 1032 insertions, 86 deletions
diff --git a/gcc/rust/backend/rust-compile-base.h b/gcc/rust/backend/rust-compile-base.h
index 5a26862..4a81061 100644
--- a/gcc/rust/backend/rust-compile-base.h
+++ b/gcc/rust/backend/rust-compile-base.h
@@ -200,6 +200,19 @@ protected:
bool compile_locals_for_block (Resolver::Rib &rib, Bfunction *fndecl,
std::vector<Bvariable *> &locals);
+
+ Bexpression *coercion_site (Bexpression *compiled_ref, TyTy::BaseType *actual,
+ TyTy::BaseType *expected, Location locus);
+
+ Bexpression *coerce_to_dyn_object (Bexpression *compiled_ref,
+ TyTy::BaseType *actual,
+ TyTy::BaseType *expected,
+ TyTy::DynamicObjectType *ty,
+ Location locus);
+
+ Bexpression *
+ compute_address_for_trait_item (const Resolver::TraitItemReference *ref,
+ TyTy::BaseType *receiver);
};
} // namespace Compile
diff --git a/gcc/rust/backend/rust-compile-context.h b/gcc/rust/backend/rust-compile-context.h
index 3a92c32..7a4344e 100644
--- a/gcc/rust/backend/rust-compile-context.h
+++ b/gcc/rust/backend/rust-compile-context.h
@@ -343,9 +343,10 @@ private:
class TyTyResolveCompile : public TyTy::TyVisitor
{
public:
- static ::Btype *compile (Context *ctx, TyTy::BaseType *ty)
+ static ::Btype *compile (Context *ctx, TyTy::BaseType *ty,
+ bool trait_object_mode = false)
{
- TyTyResolveCompile compiler (ctx);
+ TyTyResolveCompile compiler (ctx, trait_object_mode);
ty->accept_vis (compiler);
return compiler.translated;
}
@@ -378,7 +379,8 @@ public:
if (!type.get_return_type ()->is_unit ())
{
auto hir_type = type.get_return_type ();
- auto ret = TyTyResolveCompile::compile (ctx, hir_type);
+ auto ret
+ = TyTyResolveCompile::compile (ctx, hir_type, trait_object_mode);
results.push_back (Backend::Btyped_identifier (
"_", ret,
ctx->get_mappings ()->lookup_location (hir_type->get_ref ())));
@@ -388,7 +390,7 @@ public:
{
auto param_tyty = param_pair.second;
auto compiled_param_type
- = TyTyResolveCompile::compile (ctx, param_tyty);
+ = TyTyResolveCompile::compile (ctx, param_tyty, trait_object_mode);
auto compiled_param = Backend::Btyped_identifier (
param_pair.first->as_string (), compiled_param_type,
@@ -429,7 +431,6 @@ public:
if (ctx->lookup_compiled_types (type.get_ty_ref (), &translated, &type))
return;
- // create implicit struct
std::vector<Backend::Btyped_identifier> fields;
for (size_t i = 0; i < type.num_fields (); i++)
{
@@ -570,7 +571,7 @@ public:
void visit (TyTy::ReferenceType &type) override
{
Btype *base_compiled_type
- = TyTyResolveCompile::compile (ctx, type.get_base ());
+ = TyTyResolveCompile::compile (ctx, type.get_base (), trait_object_mode);
if (type.is_mutable ())
{
translated = ctx->get_backend ()->reference_type (base_compiled_type);
@@ -585,7 +586,7 @@ public:
void visit (TyTy::PointerType &type) override
{
Btype *base_compiled_type
- = TyTyResolveCompile::compile (ctx, type.get_base ());
+ = TyTyResolveCompile::compile (ctx, type.get_base (), trait_object_mode);
if (type.is_mutable ())
{
translated = ctx->get_backend ()->pointer_type (base_compiled_type);
@@ -610,10 +611,63 @@ public:
translated = ctx->get_backend ()->unit_type ();
}
+ void visit (TyTy::DynamicObjectType &type) override
+ {
+ if (trait_object_mode)
+ {
+ translated = ctx->get_backend ()->integer_type (
+ true, ctx->get_backend ()->get_pointer_size ());
+ return;
+ }
+
+ if (ctx->lookup_compiled_types (type.get_ty_ref (), &translated, &type))
+ return;
+
+ // create implicit struct
+ auto items = type.get_object_items ();
+ std::vector<Backend::Btyped_identifier> fields;
+
+ Btype *uint = ctx->get_backend ()->integer_type (
+ true, ctx->get_backend ()->get_pointer_size ());
+ Btype *uintptr_ty = ctx->get_backend ()->pointer_type (uint);
+
+ Backend::Btyped_identifier f ("__receiver_trait_obj_ptr", uintptr_ty,
+ ctx->get_mappings ()->lookup_location (
+ type.get_ty_ref ()));
+ fields.push_back (std::move (f));
+
+ for (size_t i = 0; i < items.size (); i++)
+ {
+ // mrustc seems to make a vtable consisting of uintptr's
+ Btype *uint = ctx->get_backend ()->integer_type (
+ true, ctx->get_backend ()->get_pointer_size ());
+ Btype *uintptr_ty = ctx->get_backend ()->pointer_type (uint);
+
+ Backend::Btyped_identifier f ("__" + std::to_string (i), uintptr_ty,
+ ctx->get_mappings ()->lookup_location (
+ type.get_ty_ref ()));
+ fields.push_back (std::move (f));
+ }
+
+ Btype *type_record = ctx->get_backend ()->struct_type (fields);
+ Btype *named_struct
+ = ctx->get_backend ()->named_type (type.get_name (), type_record,
+ ctx->get_mappings ()->lookup_location (
+ type.get_ty_ref ()));
+
+ ctx->push_type (named_struct);
+ translated = named_struct;
+
+ ctx->insert_compiled_type (type.get_ty_ref (), named_struct, &type);
+ }
+
private:
- TyTyResolveCompile (Context *ctx) : ctx (ctx), translated (nullptr) {}
+ TyTyResolveCompile (Context *ctx, bool trait_object_mode)
+ : ctx (ctx), trait_object_mode (trait_object_mode), translated (nullptr)
+ {}
Context *ctx;
+ bool trait_object_mode;
::Btype *translated;
};
diff --git a/gcc/rust/backend/rust-compile-stmt.h b/gcc/rust/backend/rust-compile-stmt.h
index 73f6f22..e3fa697 100644
--- a/gcc/rust/backend/rust-compile-stmt.h
+++ b/gcc/rust/backend/rust-compile-stmt.h
@@ -58,6 +58,7 @@ public:
if (!ctx->get_tyctx ()->lookup_type (stmt.get_mappings ().get_hirid (),
&ty))
{
+ // FIXME this should be an assertion instead
rust_fatal_error (stmt.get_locus (),
"failed to lookup variable declaration type");
return;
@@ -66,15 +67,26 @@ public:
Bvariable *var = nullptr;
if (!ctx->lookup_var_decl (stmt.get_mappings ().get_hirid (), &var))
{
+ // FIXME this should be an assertion instead and use error mark node
rust_fatal_error (stmt.get_locus (),
"failed to lookup compiled variable declaration");
return;
}
Bexpression *init = CompileExpr::Compile (stmt.get_init_expr (), ctx);
+ // FIXME use error_mark_node, check that CompileExpr returns error_mark_node
+ // on failure and make this an assertion
if (init == nullptr)
return;
+ TyTy::BaseType *actual = nullptr;
+ bool ok = ctx->get_tyctx ()->lookup_type (
+ stmt.get_init_expr ()->get_mappings ().get_hirid (), &actual);
+ rust_assert (ok);
+
+ TyTy::BaseType *expected = ty;
+ init = coercion_site (init, actual, expected, stmt.get_locus ());
+
auto fnctx = ctx->peek_fn ();
if (ty->is_unit ())
{
diff --git a/gcc/rust/backend/rust-compile-tyty.h b/gcc/rust/backend/rust-compile-tyty.h
index 1a5747a..40b297c 100644
--- a/gcc/rust/backend/rust-compile-tyty.h
+++ b/gcc/rust/backend/rust-compile-tyty.h
@@ -237,6 +237,8 @@ public:
translated = backend->unit_type ();
}
+ void visit (TyTy::DynamicObjectType &) override { gcc_unreachable (); }
+
private:
TyTyCompile (::Backend *backend)
: backend (backend), translated (nullptr),
diff --git a/gcc/rust/backend/rust-compile.cc b/gcc/rust/backend/rust-compile.cc
index f0e26dc..58c679f 100644
--- a/gcc/rust/backend/rust-compile.cc
+++ b/gcc/rust/backend/rust-compile.cc
@@ -108,6 +108,9 @@ CompileExpr::visit (HIR::CallExpr &expr)
void
CompileExpr::visit (HIR::MethodCallExpr &expr)
{
+ // method receiver
+ Bexpression *self = CompileExpr::Compile (expr.get_receiver ().get (), ctx);
+
// lookup the resolved name
NodeId resolved_node_id = UNKNOWN_NODEID;
if (!ctx->get_resolver ()->lookup_resolved_name (
@@ -134,6 +137,110 @@ CompileExpr::visit (HIR::MethodCallExpr &expr)
rust_assert (lookup_fntype->get_kind () == TyTy::TypeKind::FNDEF);
TyTy::FnType *fntype = static_cast<TyTy::FnType *> (lookup_fntype);
+ TyTy::BaseType *receiver = nullptr;
+ ok = ctx->get_tyctx ()->lookup_receiver (expr.get_mappings ().get_hirid (),
+ &receiver);
+ rust_assert (ok);
+
+ bool is_dyn_dispatch
+ = receiver->get_root ()->get_kind () == TyTy::TypeKind::DYNAMIC;
+ bool is_generic_receiver = receiver->get_kind () == TyTy::TypeKind::PARAM;
+ if (is_generic_receiver)
+ {
+ TyTy::ParamType *p = static_cast<TyTy::ParamType *> (receiver);
+ receiver = p->resolve ();
+ }
+
+ if (is_dyn_dispatch)
+ {
+ TyTy::DynamicObjectType *dyn
+ = static_cast<TyTy::DynamicObjectType *> (receiver->get_root ());
+
+ size_t offs = 0;
+ const Resolver::TraitItemReference *ref = nullptr;
+ for (auto &item : dyn->get_object_items ())
+ {
+ auto t = item->get_tyty ();
+ rust_assert (t->get_kind () == TyTy::TypeKind::FNDEF);
+ auto ft = static_cast<TyTy::FnType *> (t);
+
+ if (ft->get_id () == fntype->get_id ())
+ {
+ ref = item;
+ break;
+ }
+ offs++;
+ }
+
+ if (ref == nullptr)
+ {
+ translated = ctx->get_backend ()->error_expression ();
+ return;
+ }
+
+ // get any indirection sorted out
+ auto receiver_ref = self;
+ if (receiver->get_kind () == TyTy::TypeKind::REF)
+ {
+ TyTy::ReferenceType *r
+ = static_cast<TyTy::ReferenceType *> (receiver);
+ auto indirect_ty = r->get_base ();
+ Btype *indrect_compiled_tyty
+ = TyTyResolveCompile::compile (ctx, indirect_ty);
+
+ Bexpression *indirect
+ = ctx->get_backend ()->indirect_expression (indrect_compiled_tyty,
+ receiver_ref, true,
+ expr.get_locus ());
+ receiver_ref = indirect;
+ }
+
+ // access the offs + 1 for the fnptr and offs=0 for the reciever obj
+ Bexpression *self_argument
+ = ctx->get_backend ()->struct_field_expression (receiver_ref, 0,
+ expr.get_locus ());
+
+ // access the vtable for the fn
+ Bexpression *fn_vtable_access
+ = ctx->get_backend ()->struct_field_expression (receiver_ref, offs + 1,
+ expr.get_locus ());
+
+ // cast it to the correct fntype
+ Btype *expected_fntype = TyTyResolveCompile::compile (ctx, fntype, true);
+ Bexpression *fn_convert_expr
+ = ctx->get_backend ()->convert_expression (expected_fntype,
+ fn_vtable_access,
+ expr.get_locus ());
+
+ fncontext fnctx = ctx->peek_fn ();
+ Bblock *enclosing_scope = ctx->peek_enclosing_scope ();
+ bool is_address_taken = false;
+ Bstatement *ret_var_stmt = nullptr;
+
+ Bvariable *fn_convert_expr_tmp = ctx->get_backend ()->temporary_variable (
+ fnctx.fndecl, enclosing_scope, expected_fntype, fn_convert_expr,
+ is_address_taken, expr.get_locus (), &ret_var_stmt);
+ ctx->add_statement (ret_var_stmt);
+
+ std::vector<Bexpression *> args;
+ args.push_back (self_argument);
+ expr.iterate_params ([&] (HIR::Expr *p) mutable -> bool {
+ Bexpression *compiled_expr = CompileExpr::Compile (p, ctx);
+ rust_assert (compiled_expr != nullptr);
+ args.push_back (compiled_expr);
+ return true;
+ });
+
+ Bexpression *fn_expr
+ = ctx->get_backend ()->var_expression (fn_convert_expr_tmp,
+ expr.get_locus ());
+
+ translated
+ = ctx->get_backend ()->call_expression (fnctx.fndecl, fn_expr, args,
+ nullptr, expr.get_locus ());
+ return;
+ }
+
// lookup compiled functions
Bfunction *fn = nullptr;
if (!ctx->lookup_function_decl (fntype->get_ty_ref (), &fn))
@@ -157,17 +264,6 @@ CompileExpr::visit (HIR::MethodCallExpr &expr)
trait->get_mappings ().get_defid (), &trait_ref);
rust_assert (ok);
- TyTy::BaseType *receiver = nullptr;
- ok = ctx->get_tyctx ()->lookup_receiver (
- expr.get_mappings ().get_hirid (), &receiver);
- rust_assert (ok);
-
- if (receiver->get_kind () == TyTy::TypeKind::PARAM)
- {
- TyTy::ParamType *p = static_cast<TyTy::ParamType *> (receiver);
- receiver = p->resolve ();
- }
-
// the type resolver can only resolve type bounds to their trait
// item so its up to us to figure out if this path should resolve
// to an trait-impl-block-item or if it can be defaulted to the
@@ -290,10 +386,6 @@ CompileExpr::visit (HIR::MethodCallExpr &expr)
std::vector<Bexpression *> args;
- // method receiver
- Bexpression *self = CompileExpr::Compile (expr.get_receiver ().get (), ctx);
- rust_assert (self != nullptr);
-
// lookup the autoderef mappings
std::vector<Resolver::Adjustment> *adjustments = nullptr;
ok = ctx->get_tyctx ()->lookup_autoderef_mappings (
@@ -579,5 +671,138 @@ HIRCompileBase::compile_locals_for_block (Resolver::Rib &rib, Bfunction *fndecl,
return true;
}
+
+Bexpression *
+HIRCompileBase::coercion_site (Bexpression *compiled_ref,
+ TyTy::BaseType *actual, TyTy::BaseType *expected,
+ Location locus)
+{
+ auto root_actual_kind = actual->get_root ()->get_kind ();
+ auto root_expected_kind = expected->get_root ()->get_kind ();
+
+ if (root_expected_kind == TyTy::TypeKind::DYNAMIC
+ && root_actual_kind != TyTy::TypeKind::DYNAMIC)
+ {
+ TyTy::DynamicObjectType *dyn
+ = static_cast<TyTy::DynamicObjectType *> (expected->get_root ());
+ return coerce_to_dyn_object (compiled_ref, actual, expected, dyn, locus);
+ }
+
+ return compiled_ref;
+}
+
+Bexpression *
+HIRCompileBase::coerce_to_dyn_object (Bexpression *compiled_ref,
+ TyTy::BaseType *actual,
+ TyTy::BaseType *expected,
+ TyTy::DynamicObjectType *ty,
+ Location locus)
+{
+ Btype *dynamic_object = TyTyResolveCompile::compile (ctx, ty);
+
+ //' this assumes ordering and current the structure is
+ // __trait_object_ptr
+ // [list of function ptrs]
+
+ std::vector<Bexpression *> vals;
+ vals.push_back (compiled_ref);
+ for (auto &item : ty->get_object_items ())
+ {
+ // compute the address of each method item
+ auto address = compute_address_for_trait_item (item, actual->get_root ());
+ vals.push_back (address);
+ }
+
+ Bexpression *constructed_trait_object
+ = ctx->get_backend ()->constructor_expression (dynamic_object, vals, -1,
+
+ locus);
+
+ fncontext fnctx = ctx->peek_fn ();
+ Bblock *enclosing_scope = ctx->peek_enclosing_scope ();
+ bool is_address_taken = false;
+ Bstatement *ret_var_stmt = nullptr;
+
+ Bvariable *dyn_tmp = ctx->get_backend ()->temporary_variable (
+ fnctx.fndecl, enclosing_scope, dynamic_object, constructed_trait_object,
+ is_address_taken, locus, &ret_var_stmt);
+ ctx->add_statement (ret_var_stmt);
+
+ // FIXME this needs to be more generic to apply any covariance
+
+ auto e = expected;
+ std::vector<Resolver::Adjustment> adjustments;
+ while (e->get_kind () == TyTy::TypeKind::REF)
+ {
+ auto r = static_cast<TyTy::ReferenceType *> (e);
+ e = r->get_base ();
+
+ if (r->is_mutable ())
+ adjustments.push_back (
+ Resolver::Adjustment (Resolver::Adjustment::AdjustmentType::MUT_REF,
+ e));
+ else
+ adjustments.push_back (
+ Resolver::Adjustment (Resolver::Adjustment::AdjustmentType::IMM_REF,
+ e));
+ }
+
+ auto resulting_dyn_object_ref
+ = ctx->get_backend ()->var_expression (dyn_tmp, locus);
+ for (auto it = adjustments.rbegin (); it != adjustments.rend (); it++)
+ {
+ bool ok
+ = it->get_type () == Resolver::Adjustment::AdjustmentType::IMM_REF
+ || it->get_type () == Resolver::Adjustment::AdjustmentType::MUT_REF;
+ rust_assert (ok);
+
+ resulting_dyn_object_ref
+ = ctx->get_backend ()->address_expression (resulting_dyn_object_ref,
+ locus);
+ }
+ return resulting_dyn_object_ref;
+}
+
+Bexpression *
+HIRCompileBase::compute_address_for_trait_item (
+ const Resolver::TraitItemReference *trait_item_ref, TyTy::BaseType *receiver)
+{
+ TyTy::BaseType *item_type = trait_item_ref->get_tyty ();
+ rust_assert (item_type->get_kind () == TyTy::TypeKind::FNDEF);
+ TyTy::FnType *fntype = static_cast<TyTy::FnType *> (item_type);
+
+ auto root = receiver->get_root ();
+ HIR::PathIdentSegment segment_name (trait_item_ref->get_identifier ());
+ std::vector<Resolver::PathProbeCandidate> candidates
+ = Resolver::PathProbeType::Probe (root, segment_name, true, false, true);
+
+ // FIXME for default trait item resolution
+ //
+ // if (candidates.size () == 0)
+ // {
+ // rust_assert (trait_item_ref->is_optional ()); // has definition
+ //
+ // CompileTraitItem::Compile (self_type,
+ // trait_item_ref->get_hir_trait_item (), ctx,
+ // fntype);
+ // if (!ctx->lookup_function_decl (fntype->get_ty_ref (), &fn))
+ // {
+ // return ctx->get_backend ()->error_expression ();
+ // }
+ // }
+
+ rust_assert (!candidates.empty ());
+ rust_assert (candidates.size () == 1);
+
+ Resolver::PathProbeCandidate *candidate = &candidates.at (0);
+ rust_assert (candidate->is_impl_candidate ());
+
+ HIR::ImplItem *impl_item = candidate->item.impl.impl_item;
+
+ return CompileInherentImplItem::Compile (receiver->get_root (), impl_item,
+ ctx, true, fntype, true,
+ Location () /* FIXME */);
+}
+
} // namespace Compile
} // namespace Rust
diff --git a/gcc/rust/hir/tree/rust-hir-item.h b/gcc/rust/hir/tree/rust-hir-item.h
index 0b2cf10..8cd7a01 100644
--- a/gcc/rust/hir/tree/rust-hir-item.h
+++ b/gcc/rust/hir/tree/rust-hir-item.h
@@ -2264,6 +2264,8 @@ public:
TraitFunctionDecl &get_decl () { return decl; }
+ const TraitFunctionDecl &get_decl () const { return decl; }
+
bool has_block_defined () const { return block_expr != nullptr; }
std::unique_ptr<BlockExpr> &get_block_expr ()
diff --git a/gcc/rust/typecheck/rust-hir-const-fold.h b/gcc/rust/typecheck/rust-hir-const-fold.h
index 1bff7ef..1466434 100644
--- a/gcc/rust/typecheck/rust-hir-const-fold.h
+++ b/gcc/rust/typecheck/rust-hir-const-fold.h
@@ -191,6 +191,8 @@ public:
void visit (TyTy::NeverType &) override { gcc_unreachable (); }
+ void visit (TyTy::DynamicObjectType &) override { gcc_unreachable (); }
+
private:
ConstFoldType (::Backend *backend)
: backend (backend), translated (backend->error_type ())
diff --git a/gcc/rust/typecheck/rust-hir-trait-ref.h b/gcc/rust/typecheck/rust-hir-trait-ref.h
index f05ff0c..0b64a36 100644
--- a/gcc/rust/typecheck/rust-hir-trait-ref.h
+++ b/gcc/rust/typecheck/rust-hir-trait-ref.h
@@ -143,6 +143,8 @@ public:
void associated_type_reset ();
+ bool is_object_safe () const;
+
private:
TyTy::ErrorType *get_error () const
{
@@ -175,12 +177,15 @@ private:
};
// this wraps up the HIR::Trait so we can do analysis on it
+
class TraitReference
{
public:
TraitReference (const HIR::Trait *hir_trait_ref,
- std::vector<TraitItemReference> item_refs)
- : hir_trait_ref (hir_trait_ref), item_refs (item_refs)
+ std::vector<TraitItemReference> item_refs,
+ std::vector<const TraitReference *> super_traits)
+ : hir_trait_ref (hir_trait_ref), item_refs (item_refs),
+ super_traits (super_traits)
{}
TraitReference (TraitReference const &other)
@@ -198,7 +203,7 @@ public:
TraitReference (TraitReference &&other) = default;
TraitReference &operator= (TraitReference &&other) = default;
- static TraitReference error () { return TraitReference (nullptr, {}); }
+ static TraitReference error () { return TraitReference (nullptr, {}, {}); }
bool is_error () const { return hir_trait_ref == nullptr; }
@@ -323,9 +328,48 @@ public:
return this_id == other_id;
}
+ const std::vector<const TraitReference *> get_super_traits () const
+ {
+ return super_traits;
+ }
+
+ bool is_object_safe (bool emit_error, Location locus) const
+ {
+ // https: // doc.rust-lang.org/reference/items/traits.html#object-safety
+ std::vector<const TraitReference *> non_object_super_traits;
+ for (auto &item : super_traits)
+ {
+ if (!item->is_object_safe (false, Location ()))
+ non_object_super_traits.push_back (item);
+ }
+
+ std::vector<const Resolver::TraitItemReference *> non_object_safe_items;
+ for (auto &item : get_trait_items ())
+ {
+ if (!item.is_object_safe ())
+ non_object_safe_items.push_back (&item);
+ }
+
+ bool is_safe
+ = non_object_super_traits.empty () && non_object_safe_items.empty ();
+ if (emit_error && !is_safe)
+ {
+ RichLocation r (locus);
+ for (auto &item : non_object_super_traits)
+ r.add_range (item->get_locus ());
+ for (auto &item : non_object_safe_items)
+ r.add_range (item->get_locus ());
+
+ rust_error_at (r, "trait bound is not object safe");
+ }
+
+ return is_safe;
+ }
+
private:
const HIR::Trait *hir_trait_ref;
std::vector<TraitItemReference> item_refs;
+ std::vector<const TraitReference *> super_traits;
};
class AssociatedImplTrait
diff --git a/gcc/rust/typecheck/rust-hir-trait-resolve.cc b/gcc/rust/typecheck/rust-hir-trait-resolve.cc
index be58840..cee6999 100644
--- a/gcc/rust/typecheck/rust-hir-trait-resolve.cc
+++ b/gcc/rust/typecheck/rust-hir-trait-resolve.cc
@@ -193,6 +193,36 @@ TraitItemReference::get_parent_trait_mappings () const
return trait->get_mappings ();
}
+bool
+TraitItemReference::is_object_safe () const
+{
+ // https://doc.rust-lang.org/reference/items/traits.html#object-safety
+ switch (get_trait_item_type ())
+ {
+ case TraitItemReference::TraitItemType::FN: {
+ // lets be boring and just check that this is indeed a method will do
+ // for now
+ const HIR::TraitItem *item = get_hir_trait_item ();
+ const HIR::TraitItemFunc *fn
+ = static_cast<const HIR::TraitItemFunc *> (item);
+ return fn->get_decl ().is_method ();
+ }
+
+ // constants are not available via dyn dispatch and so is not object safe
+ case TraitItemReference::TraitItemType::CONST:
+ return false;
+
+ // types are object safe since they are not available via dyn dispatch
+ case TraitItemReference::TraitItemType::TYPE:
+ return true;
+
+ // this is just an error so lets just fail it
+ case TraitItemReference::TraitItemType::ERROR:
+ return false;
+ }
+ return false;
+}
+
TyTy::BaseType *
AssociatedImplTrait::get_projected_type (
const TraitItemReference *trait_item_ref, TyTy::BaseType *receiver, HirId ref,
diff --git a/gcc/rust/typecheck/rust-hir-trait-resolve.h b/gcc/rust/typecheck/rust-hir-trait-resolve.h
index b0e2c0d..a32b4da 100644
--- a/gcc/rust/typecheck/rust-hir-trait-resolve.h
+++ b/gcc/rust/typecheck/rust-hir-trait-resolve.h
@@ -153,6 +153,7 @@ private:
TyTy::TypeBoundPredicate (trait_reference->get_mappings ().get_defid (),
trait_reference->get_locus ()));
+ std::vector<const TraitReference *> super_traits;
if (trait_reference->has_type_param_bounds ())
{
for (auto &bound : trait_reference->get_type_param_bounds ())
@@ -170,6 +171,7 @@ private:
trait->get_mappings ().get_defid (), bound->get_locus ());
specified_bounds.push_back (std::move (predicate));
+ super_traits.push_back (predicate.get ());
}
}
}
@@ -189,7 +191,8 @@ private:
item_refs.push_back (std::move (trait_item_ref));
}
- TraitReference trait_object (trait_reference, item_refs);
+ TraitReference trait_object (trait_reference, item_refs,
+ std::move (super_traits));
context->insert_trait_reference (
trait_reference->get_mappings ().get_defid (), std::move (trait_object));
diff --git a/gcc/rust/typecheck/rust-hir-type-check-expr.h b/gcc/rust/typecheck/rust-hir-type-check-expr.h
index 07d4f90..fe8973a 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-expr.h
+++ b/gcc/rust/typecheck/rust-hir-type-check-expr.h
@@ -227,10 +227,13 @@ public:
// which is simple. There will need to be adjustments to ensure we can turn
// the receiver into borrowed references etc
- bool reciever_is_generic = root->get_kind () == TyTy::TypeKind::PARAM;
+ bool receiver_is_type_param = root->get_kind () == TyTy::TypeKind::PARAM;
+ bool receiver_is_dyn = root->get_kind () == TyTy::TypeKind::DYNAMIC;
+
+ bool receiver_is_generic = receiver_is_type_param || receiver_is_dyn;
bool probe_bounds = true;
- bool probe_impls = !reciever_is_generic;
- bool ignore_mandatory_trait_items = !reciever_is_generic;
+ bool probe_impls = !receiver_is_generic;
+ bool ignore_mandatory_trait_items = !receiver_is_generic;
auto candidates
= PathProbeType::Probe (root, expr.get_method_name ().get_segment (),
@@ -345,7 +348,7 @@ public:
}
}
- if (!reciever_is_generic)
+ if (!receiver_is_type_param)
{
// apply any remaining generic arguments
if (expr.get_method_name ().has_generic_args ())
diff --git a/gcc/rust/typecheck/rust-hir-type-check-implitem.h b/gcc/rust/typecheck/rust-hir-type-check-implitem.h
index 94674ad..daf515a 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-implitem.h
+++ b/gcc/rust/typecheck/rust-hir-type-check-implitem.h
@@ -424,9 +424,6 @@ public:
trait_reference.get_name ().c_str ());
}
- rust_debug_loc (type.get_locus (), "type-alias within impl block");
- lookup->debug ();
-
// its actually a projection, since we need a way to actually bind the
// generic substitutions to the type itself
TyTy::ProjectionType *projection = new TyTy::ProjectionType (
diff --git a/gcc/rust/typecheck/rust-hir-type-check-type.cc b/gcc/rust/typecheck/rust-hir-type-check-type.cc
index b54a403..7ad6d03 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-type.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check-type.cc
@@ -221,5 +221,24 @@ TypeCheckType::resolve_segments (
gcc_unreachable ();
}
+void
+TypeCheckType::visit (HIR::TraitObjectTypeOneBound &type)
+{
+ std::vector<TyTy::TypeBoundPredicate> specified_bounds;
+
+ HIR::TraitBound &trait_bound = type.get_trait_bound ();
+ TraitReference *trait = resolve_trait_path (trait_bound.get_path ());
+ TyTy::TypeBoundPredicate predicate (trait->get_mappings ().get_defid (),
+ trait_bound.get_locus ());
+
+ if (predicate.is_object_safe (true, type.get_locus ()))
+ {
+ specified_bounds.push_back (std::move (predicate));
+ translated
+ = new TyTy::DynamicObjectType (type.get_mappings ().get_hirid (),
+ std::move (specified_bounds));
+ }
+}
+
} // namespace Resolver
} // namespace Rust
diff --git a/gcc/rust/typecheck/rust-hir-type-check-type.h b/gcc/rust/typecheck/rust-hir-type-check-type.h
index c02a369..eb1c861 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-type.h
+++ b/gcc/rust/typecheck/rust-hir-type-check-type.h
@@ -66,7 +66,8 @@ public:
type->accept_vis (resolver);
if (resolver.translated == nullptr)
- return new TyTy::ErrorType (type->get_mappings ().get_hirid ());
+ resolver.translated
+ = new TyTy::ErrorType (type->get_mappings ().get_hirid ());
resolver.context->insert_type (type->get_mappings (), resolver.translated);
return resolver.translated;
@@ -146,6 +147,8 @@ public:
TyTy::InferType::InferTypeKind::GENERAL);
}
+ void visit (HIR::TraitObjectTypeOneBound &type) override;
+
private:
TypeCheckType (std::vector<TyTy::SubstitutionParamMapping> *subst_mappings)
: TypeCheckBase (), subst_mappings (subst_mappings), translated (nullptr)
diff --git a/gcc/rust/typecheck/rust-substitution-mapper.h b/gcc/rust/typecheck/rust-substitution-mapper.h
index 28cbeb8..13496ff 100644
--- a/gcc/rust/typecheck/rust-substitution-mapper.h
+++ b/gcc/rust/typecheck/rust-substitution-mapper.h
@@ -137,6 +137,7 @@ public:
void visit (TyTy::ParamType &) override { gcc_unreachable (); }
void visit (TyTy::StrType &) override { gcc_unreachable (); }
void visit (TyTy::NeverType &) override { gcc_unreachable (); }
+ void visit (TyTy::DynamicObjectType &) override { gcc_unreachable (); }
private:
SubstMapper (HirId ref, HIR::GenericArgs *generics, Location locus)
@@ -230,6 +231,7 @@ public:
void visit (TyTy::CharType &) override { gcc_unreachable (); }
void visit (TyTy::StrType &) override { gcc_unreachable (); }
void visit (TyTy::NeverType &) override { gcc_unreachable (); }
+ void visit (TyTy::DynamicObjectType &) override { gcc_unreachable (); }
private:
SubstMapperInternal (HirId ref, TyTy::SubstitutionArgumentMappings &mappings)
@@ -288,6 +290,7 @@ public:
void visit (TyTy::NeverType &) override { gcc_unreachable (); }
void visit (TyTy::PlaceholderType &) override { gcc_unreachable (); }
void visit (TyTy::ProjectionType &) override { gcc_unreachable (); }
+ void visit (TyTy::DynamicObjectType &) override { gcc_unreachable (); }
private:
SubstMapperFromExisting (TyTy::BaseType *concrete, TyTy::BaseType *receiver)
@@ -339,6 +342,7 @@ public:
void visit (TyTy::NeverType &) override {}
void visit (TyTy::PlaceholderType &) override {}
void visit (TyTy::ProjectionType &) override {}
+ void visit (TyTy::DynamicObjectType &) override {}
private:
GetUsedSubstArgs () : args (TyTy::SubstitutionArgumentMappings::error ()) {}
diff --git a/gcc/rust/typecheck/rust-tyty-bounds.cc b/gcc/rust/typecheck/rust-tyty-bounds.cc
index 1bd7865..5f69deb 100644
--- a/gcc/rust/typecheck/rust-tyty-bounds.cc
+++ b/gcc/rust/typecheck/rust-tyty-bounds.cc
@@ -88,7 +88,24 @@ TypeBoundPredicate::get () const
std::string
TypeBoundPredicate::get_name () const
{
- return get ()->get_name ();
+ auto mappings = Analysis::Mappings::get ();
+ auto trait = get ();
+ auto nodeid = trait->get_mappings ().get_nodeid ();
+
+ const Resolver::CanonicalPath *p = nullptr;
+ if (mappings->lookup_canonical_path (mappings->get_current_crate (), nodeid,
+ &p))
+ return p->get ();
+
+ return trait->get_name ();
+}
+
+bool
+TypeBoundPredicate::is_object_safe (bool emit_error, Location locus) const
+{
+ const Resolver::TraitReference *trait = get ();
+ rust_assert (trait != nullptr);
+ return trait->is_object_safe (emit_error, locus);
}
} // namespace TyTy
diff --git a/gcc/rust/typecheck/rust-tyty-call.h b/gcc/rust/typecheck/rust-tyty-call.h
index 4e74e59..906110a 100644
--- a/gcc/rust/typecheck/rust-tyty-call.h
+++ b/gcc/rust/typecheck/rust-tyty-call.h
@@ -39,24 +39,25 @@ public:
return checker.resolved;
}
- void visit (InferType &type) override { gcc_unreachable (); }
- void visit (TupleType &type) override { gcc_unreachable (); }
- void visit (ArrayType &type) override { gcc_unreachable (); }
- void visit (BoolType &type) override { gcc_unreachable (); }
- void visit (IntType &type) override { gcc_unreachable (); }
- void visit (UintType &type) override { gcc_unreachable (); }
- void visit (FloatType &type) override { gcc_unreachable (); }
- void visit (USizeType &type) override { gcc_unreachable (); }
- void visit (ISizeType &type) override { gcc_unreachable (); }
- void visit (ErrorType &type) override { gcc_unreachable (); }
- void visit (CharType &type) override { gcc_unreachable (); }
- void visit (ReferenceType &type) override { gcc_unreachable (); }
- void visit (PointerType &type) override { gcc_unreachable (); }
+ void visit (InferType &) override { gcc_unreachable (); }
+ void visit (TupleType &) override { gcc_unreachable (); }
+ void visit (ArrayType &) override { gcc_unreachable (); }
+ void visit (BoolType &) override { gcc_unreachable (); }
+ void visit (IntType &) override { gcc_unreachable (); }
+ void visit (UintType &) override { gcc_unreachable (); }
+ void visit (FloatType &) override { gcc_unreachable (); }
+ void visit (USizeType &) override { gcc_unreachable (); }
+ void visit (ISizeType &) override { gcc_unreachable (); }
+ void visit (ErrorType &) override { gcc_unreachable (); }
+ void visit (CharType &) override { gcc_unreachable (); }
+ void visit (ReferenceType &) override { gcc_unreachable (); }
+ void visit (PointerType &) override { gcc_unreachable (); }
void visit (ParamType &) override { gcc_unreachable (); }
void visit (StrType &) override { gcc_unreachable (); }
void visit (NeverType &) override { gcc_unreachable (); }
void visit (PlaceholderType &) override { gcc_unreachable (); }
void visit (ProjectionType &) override { gcc_unreachable (); }
+ void visit (DynamicObjectType &) override { gcc_unreachable (); }
// tuple-structs
void visit (ADTType &type) override;
@@ -89,25 +90,26 @@ public:
return checker.resolved;
}
- void visit (InferType &type) override { gcc_unreachable (); }
- void visit (TupleType &type) override { gcc_unreachable (); }
- void visit (ArrayType &type) override { gcc_unreachable (); }
- void visit (BoolType &type) override { gcc_unreachable (); }
- void visit (IntType &type) override { gcc_unreachable (); }
- void visit (UintType &type) override { gcc_unreachable (); }
- void visit (FloatType &type) override { gcc_unreachable (); }
- void visit (USizeType &type) override { gcc_unreachable (); }
- void visit (ISizeType &type) override { gcc_unreachable (); }
- void visit (ErrorType &type) override { gcc_unreachable (); }
- void visit (ADTType &type) override { gcc_unreachable (); };
- void visit (CharType &type) override { gcc_unreachable (); }
- void visit (ReferenceType &type) override { gcc_unreachable (); }
- void visit (PointerType &type) override { gcc_unreachable (); }
+ void visit (InferType &) override { gcc_unreachable (); }
+ void visit (TupleType &) override { gcc_unreachable (); }
+ void visit (ArrayType &) override { gcc_unreachable (); }
+ void visit (BoolType &) override { gcc_unreachable (); }
+ void visit (IntType &) override { gcc_unreachable (); }
+ void visit (UintType &) override { gcc_unreachable (); }
+ void visit (FloatType &) override { gcc_unreachable (); }
+ void visit (USizeType &) override { gcc_unreachable (); }
+ void visit (ISizeType &) override { gcc_unreachable (); }
+ void visit (ErrorType &) override { gcc_unreachable (); }
+ void visit (ADTType &) override { gcc_unreachable (); };
+ void visit (CharType &) override { gcc_unreachable (); }
+ void visit (ReferenceType &) override { gcc_unreachable (); }
+ void visit (PointerType &) override { gcc_unreachable (); }
void visit (ParamType &) override { gcc_unreachable (); }
void visit (StrType &) override { gcc_unreachable (); }
void visit (NeverType &) override { gcc_unreachable (); }
void visit (PlaceholderType &) override { gcc_unreachable (); }
void visit (ProjectionType &) override { gcc_unreachable (); }
+ void visit (DynamicObjectType &) override { gcc_unreachable (); }
// FIXME
void visit (FnPtr &type) override { gcc_unreachable (); }
diff --git a/gcc/rust/typecheck/rust-tyty-cast.h b/gcc/rust/typecheck/rust-tyty-cast.h
index 51c9791..fa50992 100644
--- a/gcc/rust/typecheck/rust-tyty-cast.h
+++ b/gcc/rust/typecheck/rust-tyty-cast.h
@@ -318,6 +318,17 @@ public:
type.as_string ().c_str ());
}
+ virtual void visit (DynamicObjectType &type) override
+ {
+ Location ref_locus = mappings->lookup_location (type.get_ref ());
+ Location base_locus = mappings->lookup_location (get_base ()->get_ref ());
+ RichLocation r (ref_locus);
+ r.add_range (base_locus);
+ rust_error_at (r, "invalid cast [%s] to [%s]",
+ get_base ()->as_string ().c_str (),
+ type.as_string ().c_str ());
+ }
+
protected:
BaseCastRules (BaseType *base)
: mappings (Analysis::Mappings::get ()),
@@ -566,6 +577,19 @@ public:
BaseCastRules::visit (type);
}
+ void visit (DynamicObjectType &type) override
+ {
+ bool is_valid
+ = (base->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL);
+ if (is_valid)
+ {
+ resolved = type.clone ();
+ return;
+ }
+
+ BaseCastRules::visit (type);
+ }
+
private:
BaseType *get_base () override { return base; }
@@ -1273,6 +1297,20 @@ private:
PlaceholderType *base;
};
+class DynamicCastRules : public BaseCastRules
+{
+ using Rust::TyTy::BaseCastRules::visit;
+
+public:
+ DynamicCastRules (DynamicObjectType *base) : BaseCastRules (base), base (base)
+ {}
+
+private:
+ BaseType *get_base () override { return base; }
+
+ DynamicObjectType *base;
+};
+
} // namespace TyTy
} // namespace Rust
diff --git a/gcc/rust/typecheck/rust-tyty-cmp.h b/gcc/rust/typecheck/rust-tyty-cmp.h
index 100e384..030f702 100644
--- a/gcc/rust/typecheck/rust-tyty-cmp.h
+++ b/gcc/rust/typecheck/rust-tyty-cmp.h
@@ -375,6 +375,22 @@ public:
ok = true;
}
+ virtual void visit (const DynamicObjectType &type) override
+ {
+ ok = false;
+ if (emit_error_flag)
+ {
+ Location ref_locus = mappings->lookup_location (type.get_ref ());
+ Location base_locus
+ = mappings->lookup_location (get_base ()->get_ref ());
+ RichLocation r (ref_locus);
+ r.add_range (base_locus);
+ rust_error_at (r, "expected [%s] got [%s]",
+ get_base ()->as_string ().c_str (),
+ type.as_string ().c_str ());
+ }
+ }
+
protected:
BaseCmp (const BaseType *base, bool emit_errors)
: mappings (Analysis::Mappings::get ()),
@@ -622,6 +638,19 @@ public:
BaseCmp::visit (type);
}
+ void visit (const DynamicObjectType &type) override
+ {
+ bool is_valid
+ = (base->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL);
+ if (is_valid)
+ {
+ ok = true;
+ return;
+ }
+
+ BaseCmp::visit (type);
+ }
+
private:
const BaseType *get_base () const override { return base; }
const InferType *base;
@@ -1231,6 +1260,33 @@ private:
const PlaceholderType *base;
};
+class DynamicCmp : public BaseCmp
+{
+ using Rust::TyTy::BaseCmp::visit;
+
+public:
+ DynamicCmp (const DynamicObjectType *base, bool emit_errors)
+ : BaseCmp (base, emit_errors), base (base)
+ {}
+
+ void visit (const DynamicObjectType &type) override
+ {
+ if (base->num_specified_bounds () != type.num_specified_bounds ())
+ {
+ BaseCmp::visit (type);
+ return;
+ }
+
+ Location ref_locus = mappings->lookup_location (type.get_ref ());
+ ok = base->bounds_compatible (type, ref_locus, false);
+ }
+
+private:
+ const BaseType *get_base () const override { return base; }
+
+ const DynamicObjectType *base;
+};
+
} // namespace TyTy
} // namespace Rust
diff --git a/gcc/rust/typecheck/rust-tyty-coercion.h b/gcc/rust/typecheck/rust-tyty-coercion.h
index f12ffb4..976997d 100644
--- a/gcc/rust/typecheck/rust-tyty-coercion.h
+++ b/gcc/rust/typecheck/rust-tyty-coercion.h
@@ -24,6 +24,7 @@
#include "rust-tyty-visitor.h"
#include "rust-hir-map.h"
#include "rust-hir-type-check.h"
+#include "rust-hir-type-bounds.h"
extern ::Backend *
rust_get_backend ();
@@ -331,6 +332,17 @@ public:
type.as_string ().c_str ());
}
+ virtual void visit (DynamicObjectType &type) override
+ {
+ Location ref_locus = mappings->lookup_location (type.get_ref ());
+ Location base_locus = mappings->lookup_location (get_base ()->get_ref ());
+ RichLocation r (ref_locus);
+ r.add_range (base_locus);
+ rust_error_at (r, "expected [%s] got [%s]",
+ get_base ()->as_string ().c_str (),
+ type.as_string ().c_str ());
+ }
+
protected:
BaseCoercionRules (BaseType *base)
: mappings (Analysis::Mappings::get ()),
@@ -580,6 +592,19 @@ public:
BaseCoercionRules::visit (type);
}
+ void visit (DynamicObjectType &type) override
+ {
+ bool is_valid
+ = (base->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL);
+ if (is_valid)
+ {
+ resolved = type.clone ();
+ return;
+ }
+
+ BaseCoercionRules::visit (type);
+ }
+
private:
BaseType *get_base () override { return base; }
@@ -1106,7 +1131,7 @@ public:
auto base_type = base->get_base ();
auto other_base_type = type.get_base ();
- TyTy::BaseType *base_resolved = base_type->unify (other_base_type);
+ TyTy::BaseType *base_resolved = base_type->coerce (other_base_type);
if (base_resolved == nullptr
|| base_resolved->get_kind () == TypeKind::ERROR)
{
@@ -1302,12 +1327,86 @@ public:
: BaseCoercionRules (base), base (base)
{}
+ BaseType *coerce (BaseType *other) override final
+ {
+ if (!base->can_resolve ())
+ return BaseCoercionRules::coerce (other);
+
+ BaseType *lookup = base->resolve ();
+ return lookup->unify (other);
+ }
+
+ void visit (PlaceholderType &type) override
+ {
+ if (base->get_symbol ().compare (type.get_symbol ()) != 0)
+ {
+ BaseCoercionRules::visit (type);
+ return;
+ }
+
+ resolved = type.clone ();
+ }
+
+ void visit (InferType &type) override
+ {
+ if (type.get_infer_kind () != InferType::InferTypeKind::GENERAL)
+ {
+ BaseCoercionRules::visit (type);
+ return;
+ }
+
+ resolved = base->clone ();
+ }
+
private:
BaseType *get_base () override { return base; }
PlaceholderType *base;
};
+class DynamicCoercionRules : public BaseCoercionRules
+{
+ using Rust::TyTy::BaseCoercionRules::visit;
+
+public:
+ DynamicCoercionRules (DynamicObjectType *base)
+ : BaseCoercionRules (base), base (base)
+ {}
+
+ void visit (DynamicObjectType &type) override
+ {
+ if (base->num_specified_bounds () != type.num_specified_bounds ())
+ {
+ BaseCoercionRules::visit (type);
+ return;
+ }
+
+ Location ref_locus = mappings->lookup_location (type.get_ref ());
+ if (!base->bounds_compatible (type, ref_locus, true))
+ {
+ BaseCoercionRules::visit (type);
+ return;
+ }
+
+ resolved = base->clone ();
+ }
+
+ void visit (ADTType &type) override
+ {
+ Location ref_locus = mappings->lookup_location (type.get_ref ());
+ bool ok = base->bounds_compatible (type, ref_locus, true);
+ if (!ok)
+ return;
+
+ resolved = base->clone ();
+ }
+
+private:
+ BaseType *get_base () override { return base; }
+
+ DynamicObjectType *base;
+};
+
} // namespace TyTy
} // namespace Rust
diff --git a/gcc/rust/typecheck/rust-tyty-rules.h b/gcc/rust/typecheck/rust-tyty-rules.h
index db7d8c0..62689cf 100644
--- a/gcc/rust/typecheck/rust-tyty-rules.h
+++ b/gcc/rust/typecheck/rust-tyty-rules.h
@@ -353,6 +353,17 @@ public:
type.as_string ().c_str ());
}
+ virtual void visit (DynamicObjectType &type) override
+ {
+ Location ref_locus = mappings->lookup_location (type.get_ref ());
+ Location base_locus = mappings->lookup_location (get_base ()->get_ref ());
+ RichLocation r (ref_locus);
+ r.add_range (base_locus);
+ rust_error_at (r, "expected [%s] got [%s]",
+ get_base ()->as_string ().c_str (),
+ type.as_string ().c_str ());
+ }
+
protected:
BaseRules (BaseType *base)
: mappings (Analysis::Mappings::get ()),
@@ -601,6 +612,19 @@ public:
BaseRules::visit (type);
}
+ void visit (DynamicObjectType &type) override
+ {
+ bool is_valid
+ = (base->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL);
+ if (is_valid)
+ {
+ resolved = type.clone ();
+ return;
+ }
+
+ BaseRules::visit (type);
+ }
+
private:
BaseType *get_base () override { return base; }
@@ -1314,6 +1338,48 @@ private:
PlaceholderType *base;
};
+class DynamicRules : public BaseRules
+{
+ using Rust::TyTy::BaseRules::visit;
+
+public:
+ DynamicRules (DynamicObjectType *base) : BaseRules (base), base (base) {}
+
+ void visit (InferType &type) override
+ {
+ if (type.get_infer_kind () != InferType::InferTypeKind::GENERAL)
+ {
+ BaseRules::visit (type);
+ return;
+ }
+
+ resolved = base->clone ();
+ }
+
+ void visit (DynamicObjectType &type) override
+ {
+ if (base->num_specified_bounds () != type.num_specified_bounds ())
+ {
+ BaseRules::visit (type);
+ return;
+ }
+
+ Location ref_locus = mappings->lookup_location (type.get_ref ());
+ if (!base->bounds_compatible (type, ref_locus, true))
+ {
+ BaseRules::visit (type);
+ return;
+ }
+
+ resolved = base->clone ();
+ }
+
+private:
+ BaseType *get_base () override { return base; }
+
+ DynamicObjectType *base;
+};
+
} // namespace TyTy
} // namespace Rust
diff --git a/gcc/rust/typecheck/rust-tyty-visitor.h b/gcc/rust/typecheck/rust-tyty-visitor.h
index 0e9a58b..a51edf4 100644
--- a/gcc/rust/typecheck/rust-tyty-visitor.h
+++ b/gcc/rust/typecheck/rust-tyty-visitor.h
@@ -48,6 +48,7 @@ public:
virtual void visit (NeverType &type) = 0;
virtual void visit (PlaceholderType &type) = 0;
virtual void visit (ProjectionType &type) = 0;
+ virtual void visit (DynamicObjectType &type) = 0;
};
class TyConstVisitor
@@ -74,6 +75,7 @@ public:
virtual void visit (const NeverType &type) = 0;
virtual void visit (const PlaceholderType &type) = 0;
virtual void visit (const ProjectionType &type) = 0;
+ virtual void visit (const DynamicObjectType &type) = 0;
};
} // namespace TyTy
diff --git a/gcc/rust/typecheck/rust-tyty.cc b/gcc/rust/typecheck/rust-tyty.cc
index ef981cc..f4ce501 100644
--- a/gcc/rust/typecheck/rust-tyty.cc
+++ b/gcc/rust/typecheck/rust-tyty.cc
@@ -63,7 +63,8 @@ BaseType::satisfies_bound (const TypeBoundPredicate &predicate) const
}
bool
-BaseType::bounds_compatible (const BaseType &other, Location locus) const
+BaseType::bounds_compatible (const BaseType &other, Location locus,
+ bool emit_error) const
{
std::vector<std::reference_wrapper<const TypeBoundPredicate>>
unsatisfied_bounds;
@@ -89,8 +90,9 @@ BaseType::bounds_compatible (const BaseType &other, Location locus) const
missing_preds += ", ";
}
- rust_error_at (r, "bounds not satisfied for %s %<%s%> is not satisfied",
- other.get_name ().c_str (), missing_preds.c_str ());
+ if (emit_error)
+ rust_error_at (r, "bounds not satisfied for %s %<%s%> is not satisfied",
+ other.get_name ().c_str (), missing_preds.c_str ());
}
return unsatisfied_bounds.size () == 0;
@@ -2257,6 +2259,107 @@ ProjectionType::handle_substitions (SubstitutionArgumentMappings subst_mappings)
return projection;
}
+void
+DynamicObjectType::accept_vis (TyVisitor &vis)
+{
+ vis.visit (*this);
+}
+
+void
+DynamicObjectType::accept_vis (TyConstVisitor &vis) const
+{
+ vis.visit (*this);
+}
+
+std::string
+DynamicObjectType::as_string () const
+{
+ return "dyn [" + raw_bounds_as_string () + "]";
+}
+
+BaseType *
+DynamicObjectType::unify (BaseType *other)
+{
+ DynamicRules r (this);
+ return r.unify (other);
+}
+
+bool
+DynamicObjectType::can_eq (const BaseType *other, bool emit_errors) const
+{
+ DynamicCmp r (this, emit_errors);
+ return r.can_eq (other);
+}
+
+BaseType *
+DynamicObjectType::coerce (BaseType *other)
+{
+ DynamicCoercionRules r (this);
+ return r.coerce (other);
+}
+
+BaseType *
+DynamicObjectType::cast (BaseType *other)
+{
+ DynamicCastRules r (this);
+ return r.cast (other);
+}
+
+BaseType *
+DynamicObjectType::clone () const
+{
+ return new DynamicObjectType (get_ref (), get_ty_ref (), specified_bounds,
+ get_combined_refs ());
+}
+
+std::string
+DynamicObjectType::get_name () const
+{
+ std::string bounds = "[" + raw_bounds_as_string () + "]";
+ return "dyn " + bounds;
+}
+
+bool
+DynamicObjectType::is_equal (const BaseType &other) const
+{
+ if (get_kind () != other.get_kind ())
+ return false;
+
+ if (num_specified_bounds () != other.num_specified_bounds ())
+ return false;
+
+ return bounds_compatible (other, Location (), false);
+}
+
+const std::vector<const Resolver::TraitItemReference *>
+DynamicObjectType::get_object_items () const
+{
+ std::vector<const Resolver::TraitItemReference *> items;
+ for (auto &bound : get_specified_bounds ())
+ {
+ const Resolver::TraitReference *trait = bound.get ();
+ for (auto &item : trait->get_trait_items ())
+ {
+ if (item.get_trait_item_type ()
+ == Resolver::TraitItemReference::TraitItemType::FN
+ && item.is_object_safe ())
+ items.push_back (&item);
+ }
+
+ for (auto &super_trait : trait->get_super_traits ())
+ {
+ for (auto &item : super_trait->get_trait_items ())
+ {
+ if (item.get_trait_item_type ()
+ == Resolver::TraitItemReference::TraitItemType::FN
+ && item.is_object_safe ())
+ items.push_back (&item);
+ }
+ }
+ }
+ return items;
+}
+
// rust-tyty-call.h
void
@@ -2285,14 +2388,14 @@ TypeCheckCallExpr::visit (ADTType &type)
BaseType *field_tyty = field->get_field_type ();
BaseType *arg = Resolver::TypeCheckExpr::Resolve (p, false);
- if (arg == nullptr)
+ if (arg->get_kind () == TyTy::TypeKind::ERROR)
{
rust_error_at (p->get_locus (), "failed to resolve argument type");
return false;
}
- auto res = field_tyty->unify (arg);
- if (res == nullptr)
+ auto res = field_tyty->coerce (arg);
+ if (res->get_kind () == TyTy::TypeKind::ERROR)
{
return false;
}
@@ -2340,7 +2443,7 @@ TypeCheckCallExpr::visit (FnType &type)
size_t i = 0;
call.iterate_params ([&] (HIR::Expr *param) mutable -> bool {
auto argument_expr_tyty = Resolver::TypeCheckExpr::Resolve (param, false);
- if (argument_expr_tyty == nullptr)
+ if (argument_expr_tyty->get_kind () == TyTy::TypeKind::ERROR)
{
rust_error_at (param->get_locus (),
"failed to resolve type for argument expr in CallExpr");
@@ -2353,8 +2456,8 @@ TypeCheckCallExpr::visit (FnType &type)
if (i < type.num_params ())
{
auto fnparam = type.param_at (i);
- resolved_argument_type = fnparam.second->unify (argument_expr_tyty);
- if (resolved_argument_type == nullptr)
+ resolved_argument_type = fnparam.second->coerce (argument_expr_tyty);
+ if (argument_expr_tyty->get_kind () == TyTy::TypeKind::ERROR)
{
rust_error_at (param->get_locus (),
"Type Resolution failure on parameter");
@@ -2405,15 +2508,15 @@ TypeCheckCallExpr::visit (FnPtr &type)
call.iterate_params ([&] (HIR::Expr *param) mutable -> bool {
auto fnparam = type.param_at (i);
auto argument_expr_tyty = Resolver::TypeCheckExpr::Resolve (param, false);
- if (argument_expr_tyty == nullptr)
+ if (argument_expr_tyty->get_kind () == TyTy::TypeKind::ERROR)
{
rust_error_at (param->get_locus (),
"failed to resolve type for argument expr in CallExpr");
return false;
}
- auto resolved_argument_type = fnparam->unify (argument_expr_tyty);
- if (resolved_argument_type == nullptr)
+ auto resolved_argument_type = fnparam->coerce (argument_expr_tyty);
+ if (argument_expr_tyty->get_kind () == TyTy::TypeKind::ERROR)
{
rust_error_at (param->get_locus (),
"Type Resolution failure on parameter");
@@ -2456,15 +2559,15 @@ TypeCheckMethodCallExpr::visit (FnType &type)
call.iterate_params ([&] (HIR::Expr *param) mutable -> bool {
auto fnparam = type.param_at (i);
auto argument_expr_tyty = Resolver::TypeCheckExpr::Resolve (param, false);
- if (argument_expr_tyty == nullptr)
+ if (argument_expr_tyty->get_kind () == TyTy::TypeKind::ERROR)
{
rust_error_at (param->get_locus (),
"failed to resolve type for argument expr in CallExpr");
return false;
}
- auto resolved_argument_type = fnparam.second->unify (argument_expr_tyty);
- if (resolved_argument_type == nullptr)
+ auto resolved_argument_type = fnparam.second->coerce (argument_expr_tyty);
+ if (argument_expr_tyty->get_kind () == TyTy::TypeKind::ERROR)
{
rust_error_at (param->get_locus (),
"Type Resolution failure on parameter");
diff --git a/gcc/rust/typecheck/rust-tyty.h b/gcc/rust/typecheck/rust-tyty.h
index a7eb132..7ab2b2c 100644
--- a/gcc/rust/typecheck/rust-tyty.h
+++ b/gcc/rust/typecheck/rust-tyty.h
@@ -26,8 +26,10 @@
#include "rust-abi.h"
namespace Rust {
+
namespace Resolver {
class TraitReference;
+class TraitItemReference;
class AssociatedImplTrait;
} // namespace Resolver
@@ -57,6 +59,7 @@ enum TypeKind
NEVER,
PLACEHOLDER,
PROJECTION,
+ DYNAMIC,
// there are more to add...
ERROR
};
@@ -128,6 +131,9 @@ public:
case TypeKind::PROJECTION:
return "Projection";
+ case TypeKind::DYNAMIC:
+ return "Dynamic";
+
case TypeKind::ERROR:
return "ERROR";
}
@@ -150,6 +156,10 @@ public:
std::string get_name () const;
+ // check that this predicate is object-safe see:
+ // https://doc.rust-lang.org/reference/items/traits.html#object-safety
+ bool is_object_safe (bool emit_error, Location locus) const;
+
private:
DefId reference;
Location locus;
@@ -173,13 +183,23 @@ public:
return specified_bounds;
}
- std::string bounds_as_string () const
+ size_t num_specified_bounds () const { return specified_bounds.size (); }
+
+ std::string raw_bounds_as_string () const
{
std::string buf;
- for (auto &b : specified_bounds)
- buf += b.as_string () + ", ";
+ for (size_t i = 0; i < specified_bounds.size (); i++)
+ {
+ const TypeBoundPredicate &b = specified_bounds.at (i);
+ bool has_next = (i + 1) < specified_bounds.size ();
+ buf += b.get_name () + (has_next ? " + " : "");
+ }
+ return buf;
+ }
- return "bounds:[" + buf + "]";
+ std::string bounds_as_string () const
+ {
+ return "bounds:[" + raw_bounds_as_string () + "]";
}
protected:
@@ -253,7 +273,8 @@ public:
bool satisfies_bound (const TypeBoundPredicate &predicate) const;
- bool bounds_compatible (const BaseType &other, Location locus) const;
+ bool bounds_compatible (const BaseType &other, Location locus,
+ bool emit_error) const;
void inherit_bounds (const BaseType &other);
@@ -608,7 +629,7 @@ public:
}
else
{
- if (!param->bounds_compatible (*type, locus))
+ if (!param->bounds_compatible (*type, locus, true))
return;
}
@@ -1813,6 +1834,41 @@ private:
DefId item;
};
+class DynamicObjectType : public BaseType
+{
+public:
+ DynamicObjectType (HirId ref,
+ std::vector<TypeBoundPredicate> specified_bounds,
+ std::set<HirId> refs = std::set<HirId> ())
+ : BaseType (ref, ref, TypeKind::DYNAMIC, specified_bounds, refs)
+ {}
+
+ DynamicObjectType (HirId ref, HirId ty_ref,
+ std::vector<TypeBoundPredicate> specified_bounds,
+ std::set<HirId> refs = std::set<HirId> ())
+ : BaseType (ref, ty_ref, TypeKind::DYNAMIC, specified_bounds, refs)
+ {}
+
+ void accept_vis (TyVisitor &vis) override;
+ void accept_vis (TyConstVisitor &vis) const override;
+
+ std::string as_string () const override;
+
+ BaseType *unify (BaseType *other) override;
+ bool can_eq (const BaseType *other, bool emit_errors) const override final;
+ BaseType *coerce (BaseType *other) override;
+ BaseType *cast (BaseType *other) override;
+ bool is_equal (const BaseType &other) const override;
+
+ BaseType *clone () const final override;
+
+ std::string get_name () const override final;
+
+ // this returns a flat list of items including super trait bounds
+ const std::vector<const Resolver::TraitItemReference *>
+ get_object_items () const;
+};
+
} // namespace TyTy
} // namespace Rust
diff --git a/gcc/testsuite/rust/compile/traits10.rs b/gcc/testsuite/rust/compile/traits10.rs
new file mode 100644
index 0000000..a4622b2
--- /dev/null
+++ b/gcc/testsuite/rust/compile/traits10.rs
@@ -0,0 +1,16 @@
+struct Foo(i32);
+
+trait Bar {
+ const A: i32 = 123;
+ fn B();
+ fn C(&self);
+}
+
+pub fn main() {
+ let a;
+ a = Foo(123);
+
+ let b: &dyn Bar = &a;
+ // { dg-error "trait bound is not object safe" "" { target *-*-* } .-1 }
+ // { dg-error "expected" "" { target *-*-* } .-2 }
+}
diff --git a/gcc/testsuite/rust/compile/traits11.rs b/gcc/testsuite/rust/compile/traits11.rs
new file mode 100644
index 0000000..bf69ff0
--- /dev/null
+++ b/gcc/testsuite/rust/compile/traits11.rs
@@ -0,0 +1,20 @@
+struct Foo(i32);
+
+trait A {
+ const A: i32 = 123;
+ fn B();
+ fn C(&self);
+}
+
+trait B: A {
+ fn test(&self);
+}
+
+pub fn main() {
+ let a;
+ a = Foo(123);
+
+ let b: &dyn B = &a;
+ // { dg-error "trait bound is not object safe" "" { target *-*-* } .-1 }
+ // { dg-error "expected" "" { target *-*-* } .-2 }
+}
diff --git a/gcc/testsuite/rust/compile/traits9.rs b/gcc/testsuite/rust/compile/traits9.rs
new file mode 100644
index 0000000..e1aef539
--- /dev/null
+++ b/gcc/testsuite/rust/compile/traits9.rs
@@ -0,0 +1,13 @@
+struct Foo(i32);
+trait Bar {
+ fn baz(&self);
+}
+
+fn main() {
+ let a;
+ a = Foo(123);
+
+ let b: &dyn Bar = &a;
+ // { dg-error "bounds not satisfied for Foo .Bar. is not satisfied" "" { target *-*-* } .-1 }
+ // { dg-error "expected" "" { target *-*-* } .-2 }
+}
diff --git a/gcc/testsuite/rust/compile/tuple_struct3.rs b/gcc/testsuite/rust/compile/tuple_struct3.rs
index c52a610..1af72a2 100644
--- a/gcc/testsuite/rust/compile/tuple_struct3.rs
+++ b/gcc/testsuite/rust/compile/tuple_struct3.rs
@@ -1,5 +1,9 @@
struct Foo(i32, i32, bool);
fn main() {
- let c = Foo(1, 2f32, true); // { dg-error "expected .i32. got .f32." }
+ let c = Foo(1, 2f32, true);
+ // { dg-error "expected .i32. got .f32." "" { target *-*-* } .-1 }
+ // { dg-error "unexpected number of arguments 1 expected 3" "" { target *-*-* } .-2 }
+ // { dg-error "failed to lookup type to CallExpr" "" { target *-*-* } .-3 }
+ // { dg-error "failed to type resolve expression" "" { target *-*-* } .-4 }
}
diff --git a/gcc/testsuite/rust/execute/torture/trait5.rs b/gcc/testsuite/rust/execute/torture/trait5.rs
new file mode 100644
index 0000000..f25784a
--- /dev/null
+++ b/gcc/testsuite/rust/execute/torture/trait5.rs
@@ -0,0 +1,41 @@
+/* { dg-output "123\n123\n" } */
+extern "C" {
+ fn printf(s: *const i8, ...);
+}
+
+struct Foo(i32);
+trait Bar {
+ fn baz(&self);
+ // { dg-warning "unused name" "" { target *-*-* } .-1 }
+}
+
+impl Bar for Foo {
+ fn baz(&self) {
+ // { dg-warning "unused name" "" { target *-*-* } .-1 }
+ unsafe {
+ let a = "%i\n\0";
+ let b = a as *const str;
+ let c = b as *const i8;
+
+ printf(c, self.0);
+ }
+ }
+}
+
+fn static_dispatch<T: Bar>(t: &T) {
+ t.baz();
+}
+
+fn dynamic_dispatch(t: &dyn Bar) {
+ t.baz();
+}
+
+fn main() -> i32 {
+ let a = &Foo(123);
+ static_dispatch(a);
+
+ let b: &dyn Bar = a;
+ dynamic_dispatch(b);
+
+ 0
+}