aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2021-11-02 13:54:14 +0000
committerGitHub <noreply@github.com>2021-11-02 13:54:14 +0000
commit5f0df4812c37fc428b5508e019e9fb7f8a7b77b1 (patch)
tree2a2bef1a866b93287a48990c09a4243d0ab41c0f /gcc
parent09af9b16b436606fa8ced0aa6cc111555bdc3da7 (diff)
parentfc5f8d746362a42adc52e538dec248bd2992a794 (diff)
downloadgcc-5f0df4812c37fc428b5508e019e9fb7f8a7b77b1.zip
gcc-5f0df4812c37fc428b5508e019e9fb7f8a7b77b1.tar.gz
gcc-5f0df4812c37fc428b5508e019e9fb7f8a7b77b1.tar.bz2
Merge #781
781: Add missing typechecking for enums r=philberty a=philberty This PR splits up the Algebraic data type into one which can support many variants which is what an enum is. It then changes the type checking for construction of ADT's to use the VariantDef structures as required. This does not fully implement but does allow us to have most of the type checking in place to start code-generation work. This combines work from Mark Wielaard (https://code.wildebeest.org/git/user/mjw/gccrs/commit/?h=enum-type) and Philip Addresses #79 Co-authored-by: Mark Wielaard <mark@klomp.org> Co-authored-by: Philip Herron <philip.herron@embecosm.com>
Diffstat (limited to 'gcc')
-rw-r--r--gcc/rust/Make-lang.in1
-rw-r--r--gcc/rust/backend/rust-compile-context.h9
-rw-r--r--gcc/rust/backend/rust-compile-expr.h18
-rw-r--r--gcc/rust/backend/rust-compile.cc6
-rw-r--r--gcc/rust/hir/tree/rust-hir-item.h31
-rw-r--r--gcc/rust/hir/tree/rust-hir.h2
-rw-r--r--gcc/rust/lint/rust-lint-marklive.cc14
-rw-r--r--gcc/rust/typecheck/rust-hir-path-probe.h71
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-enumitem.h153
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-expr.h49
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-path.cc19
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-stmt.h100
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-struct-field.h4
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-struct.cc298
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-toplevel.h99
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check.cc256
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check.h21
-rw-r--r--gcc/rust/typecheck/rust-tyty-call.h12
-rw-r--r--gcc/rust/typecheck/rust-tyty-cast.h36
-rw-r--r--gcc/rust/typecheck/rust-tyty-cmp.h36
-rw-r--r--gcc/rust/typecheck/rust-tyty-coercion.h36
-rw-r--r--gcc/rust/typecheck/rust-tyty-rules.h36
-rw-r--r--gcc/rust/typecheck/rust-tyty.cc170
-rw-r--r--gcc/rust/typecheck/rust-tyty.h238
-rw-r--r--gcc/testsuite/rust/compile/func2.rs2
-rw-r--r--gcc/testsuite/rust/compile/func3.rs2
-rw-r--r--gcc/testsuite/rust/compile/tuple_struct1.rs2
-rw-r--r--gcc/testsuite/rust/compile/tuple_struct2.rs2
-rw-r--r--gcc/testsuite/rust/compile/tuple_struct3.rs2
29 files changed, 1204 insertions, 521 deletions
diff --git a/gcc/rust/Make-lang.in b/gcc/rust/Make-lang.in
index d2029bbd..15c0a8f 100644
--- a/gcc/rust/Make-lang.in
+++ b/gcc/rust/Make-lang.in
@@ -85,6 +85,7 @@ GRS_OBJS = \
rust/rust-hir-trait-resolve.o \
rust/rust-hir-const-fold.o \
rust/rust-hir-type-check-type.o \
+ rust/rust-hir-type-check-struct.o \
rust/rust-lint-marklive.o \
rust/rust-hir-type-check-path.o \
rust/rust-compile-intrinsic.o \
diff --git a/gcc/rust/backend/rust-compile-context.h b/gcc/rust/backend/rust-compile-context.h
index 2b2018f..551e041 100644
--- a/gcc/rust/backend/rust-compile-context.h
+++ b/gcc/rust/backend/rust-compile-context.h
@@ -431,10 +431,15 @@ public:
if (ctx->lookup_compiled_types (type.get_ty_ref (), &translated, &type))
return;
+ // we dont support enums yet
+ rust_assert (!type.is_enum ());
+ rust_assert (type.number_of_variants () == 1);
+
+ TyTy::VariantDef &variant = *type.get_variants ().at (0);
std::vector<Backend::Btyped_identifier> fields;
- for (size_t i = 0; i < type.num_fields (); i++)
+ for (size_t i = 0; i < variant.num_fields (); i++)
{
- const TyTy::StructFieldType *field = type.get_field (i);
+ const TyTy::StructFieldType *field = variant.get_field_at_index (i);
Btype *compiled_field_ty
= TyTyResolveCompile::compile (ctx, field->get_field_type ());
diff --git a/gcc/rust/backend/rust-compile-expr.h b/gcc/rust/backend/rust-compile-expr.h
index 0512373..f43db50 100644
--- a/gcc/rust/backend/rust-compile-expr.h
+++ b/gcc/rust/backend/rust-compile-expr.h
@@ -698,7 +698,13 @@ public:
if (receiver->get_kind () == TyTy::TypeKind::ADT)
{
TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (receiver);
- adt->get_field (expr.get_field_name (), &field_index);
+ rust_assert (!adt->is_enum ());
+ rust_assert (adt->number_of_variants () == 1);
+
+ TyTy::VariantDef *variant = adt->get_variants ().at (0);
+ bool ok = variant->lookup_field (expr.get_field_name (), nullptr,
+ &field_index);
+ rust_assert (ok);
}
else if (receiver->get_kind () == TyTy::TypeKind::REF)
{
@@ -707,9 +713,15 @@ public:
rust_assert (b->get_kind () == TyTy::TypeKind::ADT);
TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (b);
- adt->get_field (expr.get_field_name (), &field_index);
- Btype *adt_tyty = TyTyResolveCompile::compile (ctx, adt);
+ rust_assert (!adt->is_enum ());
+ rust_assert (adt->number_of_variants () == 1);
+ TyTy::VariantDef *variant = adt->get_variants ().at (0);
+ bool ok = variant->lookup_field (expr.get_field_name (), nullptr,
+ &field_index);
+ rust_assert (ok);
+
+ Btype *adt_tyty = TyTyResolveCompile::compile (ctx, adt);
Bexpression *indirect
= ctx->get_backend ()->indirect_expression (adt_tyty, receiver_ref,
true, expr.get_locus ());
diff --git a/gcc/rust/backend/rust-compile.cc b/gcc/rust/backend/rust-compile.cc
index c8254c1..a5d32b1 100644
--- a/gcc/rust/backend/rust-compile.cc
+++ b/gcc/rust/backend/rust-compile.cc
@@ -73,6 +73,10 @@ CompileExpr::visit (HIR::CallExpr &expr)
TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (tyty);
Btype *compiled_adt_type = TyTyResolveCompile::compile (ctx, tyty);
+ rust_assert (!adt->is_enum ());
+ rust_assert (adt->number_of_variants () == 1);
+ auto variant = adt->get_variants ().at (0);
+
// this assumes all fields are in order from type resolution and if a
// base struct was specified those fields are filed via accesors
std::vector<Bexpression *> vals;
@@ -83,7 +87,7 @@ CompileExpr::visit (HIR::CallExpr &expr)
// assignments are coercion sites so lets convert the rvalue if
// necessary
- auto respective_field = adt->get_field (i);
+ auto respective_field = variant->get_field_at_index (i);
auto expected = respective_field->get_field_type ();
TyTy::BaseType *actual = nullptr;
diff --git a/gcc/rust/hir/tree/rust-hir-item.h b/gcc/rust/hir/tree/rust-hir-item.h
index 9b8793f..c5a8d06 100644
--- a/gcc/rust/hir/tree/rust-hir-item.h
+++ b/gcc/rust/hir/tree/rust-hir-item.h
@@ -1694,12 +1694,12 @@ public:
return std::unique_ptr<EnumItem> (clone_item_impl ());
}
- virtual std::string as_string () const;
+ virtual std::string as_string () const override;
// not pure virtual as not abstract
- virtual void accept_vis (HIRVisitor &vis);
+ virtual void accept_vis (HIRVisitor &vis) override;
- Location get_locus () const { return locus; }
+ Location get_locus () const override { return locus; }
Identifier get_identifier () const { return variant_name; }
@@ -1729,6 +1729,8 @@ public:
void accept_vis (HIRVisitor &vis) override;
+ std::vector<TupleField> &get_tuple_fields () { return tuple_fields; }
+
protected:
// Clone function implementation as (not pure) virtual method
EnumItemTuple *clone_item_impl () const override
@@ -1759,6 +1761,8 @@ public:
void accept_vis (HIRVisitor &vis) override;
+ std::vector<StructField> &get_struct_fields () { return struct_fields; }
+
protected:
// Clone function implementation as (not pure) virtual method
EnumItemStruct *clone_item_impl () const override
@@ -1805,6 +1809,8 @@ public:
void accept_vis (HIRVisitor &vis) override;
+ std::unique_ptr<Expr> &get_discriminant_expression () { return expression; }
+
protected:
// Clone function implementation as (not pure) virtual method
EnumItemDiscriminant *clone_item_impl () const override
@@ -1899,6 +1905,16 @@ public:
Identifier get_identifier () const { return enum_name; }
+ std::vector<std::unique_ptr<GenericParam>> &get_generic_params ()
+ {
+ return generic_params;
+ }
+
+ const std::vector<std::unique_ptr<EnumItem>> &get_variants () const
+ {
+ return items;
+ }
+
protected:
/* Use covariance to implement clone function as returning this object
* rather than base */
@@ -1989,14 +2005,7 @@ public:
void accept_vis (HIRVisitor &vis) override;
- void iterate (std::function<bool (StructField &)> cb)
- {
- for (auto &variant : variants)
- {
- if (!cb (variant))
- return;
- }
- }
+ std::vector<StructField> &get_variants () { return variants; }
WhereClause &get_where_clause () { return where_clause; }
diff --git a/gcc/rust/hir/tree/rust-hir.h b/gcc/rust/hir/tree/rust-hir.h
index 667f4d08..d7977b4 100644
--- a/gcc/rust/hir/tree/rust-hir.h
+++ b/gcc/rust/hir/tree/rust-hir.h
@@ -127,7 +127,7 @@ public:
return std::unique_ptr<Item> (clone_item_impl ());
}
- std::string as_string () const;
+ std::string as_string () const override;
/* Adds crate names to the vector passed by reference, if it can
* (polymorphism). */
diff --git a/gcc/rust/lint/rust-lint-marklive.cc b/gcc/rust/lint/rust-lint-marklive.cc
index 4b095ab4..ef207bc 100644
--- a/gcc/rust/lint/rust-lint-marklive.cc
+++ b/gcc/rust/lint/rust-lint-marklive.cc
@@ -228,11 +228,17 @@ MarkLive::visit (HIR::FieldAccessExpr &expr)
}
rust_assert (adt != nullptr);
+ rust_assert (!adt->is_enum ());
+ rust_assert (adt->number_of_variants () == 1);
+
+ TyTy::VariantDef *variant = adt->get_variants ().at (0);
// get the field index
- size_t index = 0;
- adt->get_field (expr.get_field_name (), &index);
- if (index >= adt->num_fields ())
+ size_t index;
+ TyTy::StructFieldType *field;
+ bool ok = variant->lookup_field (expr.get_field_name (), &field, &index);
+ rust_assert (ok);
+ if (index >= variant->num_fields ())
{
rust_error_at (expr.get_receiver_expr ()->get_locus (),
"cannot access struct %s by index: %ld",
@@ -241,7 +247,7 @@ MarkLive::visit (HIR::FieldAccessExpr &expr)
}
// get the field hir id
- HirId field_id = adt->get_field (index)->get_ref ();
+ HirId field_id = field->get_ref ();
mark_hir_id (field_id);
}
diff --git a/gcc/rust/typecheck/rust-hir-path-probe.h b/gcc/rust/typecheck/rust-hir-path-probe.h
index b989990..d318b9c 100644
--- a/gcc/rust/typecheck/rust-hir-path-probe.h
+++ b/gcc/rust/typecheck/rust-hir-path-probe.h
@@ -32,6 +32,8 @@ struct PathProbeCandidate
{
enum CandidateType
{
+ ENUM_VARIANT,
+
IMPL_CONST,
IMPL_TYPE_ALIAS,
IMPL_FUNC,
@@ -41,6 +43,12 @@ struct PathProbeCandidate
TRAIT_FUNC,
};
+ struct EnumItemCandidate
+ {
+ const TyTy::ADTType *parent;
+ const TyTy::VariantDef *variant;
+ };
+
struct ImplItemCandidate
{
HIR::ImplItem *impl_item;
@@ -59,14 +67,21 @@ struct PathProbeCandidate
Location locus;
union Candidate
{
+ EnumItemCandidate enum_field;
ImplItemCandidate impl;
TraitItemCandidate trait;
+ Candidate (EnumItemCandidate enum_field) : enum_field (enum_field) {}
Candidate (ImplItemCandidate impl) : impl (impl) {}
Candidate (TraitItemCandidate trait) : trait (trait) {}
} item;
PathProbeCandidate (CandidateType type, TyTy::BaseType *ty, Location locus,
+ EnumItemCandidate enum_field)
+ : type (type), ty (ty), item (enum_field)
+ {}
+
+ PathProbeCandidate (CandidateType type, TyTy::BaseType *ty, Location locus,
ImplItemCandidate impl)
: type (type), ty (ty), item (impl)
{}
@@ -81,34 +96,17 @@ struct PathProbeCandidate
return "PathProbe candidate TODO - as_string";
}
+ bool is_enum_candidate () const { return type == ENUM_VARIANT; }
+
bool is_impl_candidate () const
{
- switch (type)
- {
- case IMPL_CONST:
- case IMPL_TYPE_ALIAS:
- case IMPL_FUNC:
- return true;
-
- default:
- return false;
- }
- gcc_unreachable ();
+ return type == IMPL_CONST || type == IMPL_TYPE_ALIAS || type == IMPL_FUNC;
}
bool is_trait_candidate () const
{
- switch (type)
- {
- case TRAIT_ITEM_CONST:
- case TRAIT_TYPE_ALIAS:
- case TRAIT_FUNC:
- return true;
-
- default:
- return false;
- }
- gcc_unreachable ();
+ return type == TRAIT_ITEM_CONST || type == TRAIT_TYPE_ALIAS
+ || type == TRAIT_FUNC;
}
};
@@ -125,7 +123,17 @@ public:
{
PathProbeType probe (receiver, segment_name);
if (probe_impls)
- probe.process_impl_items_for_candidates ();
+ {
+ if (receiver->get_kind () == TyTy::TypeKind::ADT)
+ {
+ const TyTy::ADTType *adt
+ = static_cast<const TyTy::ADTType *> (receiver);
+ if (adt->is_enum ())
+ probe.process_enum_item_for_candiates (adt);
+ }
+
+ probe.process_impl_items_for_candidates ();
+ }
if (!probe_bounds)
return probe.candidates;
@@ -211,6 +219,19 @@ public:
}
protected:
+ void process_enum_item_for_candiates (const TyTy::ADTType *adt)
+ {
+ TyTy::VariantDef *v;
+ if (!adt->lookup_variant (search.as_string (), &v))
+ return;
+
+ PathProbeCandidate::EnumItemCandidate enum_item_candidate{adt, v};
+ PathProbeCandidate candidate{
+ PathProbeCandidate::CandidateType::ENUM_VARIANT, receiver->clone (),
+ mappings->lookup_location (adt->get_ty_ref ()), enum_item_candidate};
+ candidates.push_back (std::move (candidate));
+ }
+
void process_impl_items_for_candidates ()
{
mappings->iterate_impl_items ([&] (HirId id, HIR::ImplItem *item,
@@ -422,6 +443,10 @@ public:
{
switch (c.type)
{
+ case PathProbeCandidate::CandidateType::ENUM_VARIANT:
+ gcc_unreachable ();
+ break;
+
case PathProbeCandidate::CandidateType::IMPL_CONST:
case PathProbeCandidate::CandidateType::IMPL_TYPE_ALIAS:
case PathProbeCandidate::CandidateType::IMPL_FUNC:
diff --git a/gcc/rust/typecheck/rust-hir-type-check-enumitem.h b/gcc/rust/typecheck/rust-hir-type-check-enumitem.h
new file mode 100644
index 0000000..e4dcaeb23
--- /dev/null
+++ b/gcc/rust/typecheck/rust-hir-type-check-enumitem.h
@@ -0,0 +1,153 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+#ifndef RUST_HIR_TYPE_CHECK_ENUMITEM
+#define RUST_HIR_TYPE_CHECK_ENUMITEM
+
+#include "rust-hir-type-check-base.h"
+#include "rust-hir-full.h"
+#include "rust-hir-type-check-type.h"
+#include "rust-hir-type-check-expr.h"
+
+extern ::Backend *
+rust_get_backend ();
+
+namespace Rust {
+namespace Resolver {
+
+class TypeCheckEnumItem : public TypeCheckBase
+{
+ using Rust::Resolver::TypeCheckBase::visit;
+
+public:
+ static TyTy::VariantDef *Resolve (HIR::EnumItem *item,
+ int64_t last_discriminant)
+ {
+ TypeCheckEnumItem resolver (last_discriminant);
+ item->accept_vis (resolver);
+ return resolver.variant;
+ }
+
+ void visit (HIR::EnumItem &item) override
+ {
+ if (last_discriminant == INT64_MAX)
+ rust_error_at (item.get_locus (), "discriminant too big");
+
+ variant
+ = new TyTy::VariantDef (item.get_mappings ().get_hirid (),
+ item.get_identifier (), last_discriminant + 1);
+ }
+
+ void visit (HIR::EnumItemDiscriminant &item) override
+ {
+ if (last_discriminant == INT64_MAX)
+ rust_error_at (item.get_locus (), "discriminant too big");
+
+ auto &discriminant = item.get_discriminant_expression ();
+ auto capacity_type = TypeCheckExpr::Resolve (discriminant.get (), false);
+ if (capacity_type->get_kind () == TyTy::TypeKind::ERROR)
+ return;
+
+ TyTy::USizeType *expected_ty
+ = new TyTy::USizeType (discriminant->get_mappings ().get_hirid ());
+ context->insert_type (discriminant->get_mappings (), expected_ty);
+
+ auto unified = expected_ty->unify (capacity_type);
+ if (unified->get_kind () == TyTy::TypeKind::ERROR)
+ return;
+
+ auto backend = rust_get_backend ();
+ auto folded_discriminant
+ = ConstFold::ConstFoldExpr::fold (discriminant.get ());
+ if (folded_discriminant == nullptr
+ || backend->is_error_expression (folded_discriminant))
+ return;
+
+ size_t specified_discriminant;
+ bool ok
+ = backend->const_size_cast (folded_discriminant, &specified_discriminant);
+ rust_assert (ok);
+
+ variant
+ = new TyTy::VariantDef (item.get_mappings ().get_hirid (),
+ item.get_identifier (), specified_discriminant);
+ }
+
+ void visit (HIR::EnumItemTuple &item) override
+ {
+ if (last_discriminant == INT64_MAX)
+ rust_error_at (item.get_locus (), "discriminant too big");
+
+ std::vector<TyTy::StructFieldType *> fields;
+ size_t idx = 0;
+ for (auto &field : item.get_tuple_fields ())
+ {
+ TyTy::BaseType *field_type
+ = TypeCheckType::Resolve (field.get_field_type ().get ());
+ TyTy::StructFieldType *ty_field
+ = new TyTy::StructFieldType (field.get_mappings ().get_hirid (),
+ std::to_string (idx), field_type);
+ fields.push_back (ty_field);
+ context->insert_type (field.get_mappings (),
+ ty_field->get_field_type ());
+ idx++;
+ }
+
+ variant
+ = new TyTy::VariantDef (item.get_mappings ().get_hirid (),
+ item.get_identifier (),
+ TyTy::VariantDef::VariantType::TUPLE, fields);
+ }
+
+ void visit (HIR::EnumItemStruct &item) override
+ {
+ if (last_discriminant == INT64_MAX)
+ rust_error_at (item.get_locus (), "discriminant too big");
+
+ std::vector<TyTy::StructFieldType *> fields;
+ for (auto &field : item.get_struct_fields ())
+ {
+ TyTy::BaseType *field_type
+ = TypeCheckType::Resolve (field.get_field_type ().get ());
+ TyTy::StructFieldType *ty_field
+ = new TyTy::StructFieldType (field.get_mappings ().get_hirid (),
+ field.get_field_name (), field_type);
+ fields.push_back (ty_field);
+ context->insert_type (field.get_mappings (),
+ ty_field->get_field_type ());
+ }
+
+ variant
+ = new TyTy::VariantDef (item.get_mappings ().get_hirid (),
+ item.get_identifier (),
+ TyTy::VariantDef::VariantType::STRUCT, fields);
+ }
+
+private:
+ TypeCheckEnumItem (int64_t last_discriminant)
+ : TypeCheckBase (), variant (nullptr), last_discriminant (last_discriminant)
+ {}
+
+ TyTy::VariantDef *variant;
+ int64_t last_discriminant;
+};
+
+} // namespace Resolver
+} // namespace Rust
+
+#endif // RUST_HIR_TYPE_CHECK_ENUMITEM
diff --git a/gcc/rust/typecheck/rust-hir-type-check-expr.h b/gcc/rust/typecheck/rust-hir-type-check-expr.h
index e71d1e9..2a6bae9 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-expr.h
+++ b/gcc/rust/typecheck/rust-hir-type-check-expr.h
@@ -113,14 +113,18 @@ public:
}
TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (resolved);
+ rust_assert (!adt->is_enum ());
+ rust_assert (adt->number_of_variants () == 1);
+
+ TyTy::VariantDef *variant = adt->get_variants ().at (0);
TupleIndex index = expr.get_tuple_index ();
- if ((size_t) index >= adt->num_fields ())
+ if ((size_t) index >= variant->num_fields ())
{
rust_error_at (expr.get_locus (), "unknown field at index %i", index);
return;
}
- auto field_tyty = adt->get_field ((size_t) index);
+ auto field_tyty = variant->get_field_at_index ((size_t) index);
if (field_tyty == nullptr)
{
rust_error_at (expr.get_locus (),
@@ -194,7 +198,33 @@ public:
return;
}
- infered = TyTy::TypeCheckCallExpr::go (function_tyty, expr, context);
+ TyTy::VariantDef &variant = TyTy::VariantDef::get_error_node ();
+ if (function_tyty->get_kind () == TyTy::TypeKind::ADT)
+ {
+ TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (function_tyty);
+ if (adt->is_enum ())
+ {
+ // lookup variant id
+ HirId variant_id;
+ bool ok = context->lookup_variant_definition (
+ expr.get_fnexpr ()->get_mappings ().get_hirid (), &variant_id);
+ rust_assert (ok);
+
+ TyTy::VariantDef *lookup_variant = nullptr;
+ ok = adt->lookup_variant_by_id (variant_id, &lookup_variant);
+ rust_assert (ok);
+
+ variant = *lookup_variant;
+ }
+ else
+ {
+ rust_assert (adt->number_of_variants () == 1);
+ variant = *adt->get_variants ().at (0);
+ }
+ }
+
+ infered
+ = TyTy::TypeCheckCallExpr::go (function_tyty, expr, variant, context);
if (infered == nullptr)
{
rust_error_at (expr.get_locus (), "failed to lookup type to CallExpr");
@@ -984,8 +1014,15 @@ public:
}
TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (struct_base);
- auto resolved = adt->get_field (expr.get_field_name ());
- if (resolved == nullptr)
+ rust_assert (!adt->is_enum ());
+ rust_assert (adt->number_of_variants () == 1);
+
+ TyTy::VariantDef *vaiant = adt->get_variants ().at (0);
+
+ TyTy::StructFieldType *lookup = nullptr;
+ bool found
+ = vaiant->lookup_field (expr.get_field_name (), &lookup, nullptr);
+ if (!found)
{
rust_error_at (expr.get_locus (), "unknown field [%s] for type [%s]",
expr.get_field_name ().c_str (),
@@ -993,7 +1030,7 @@ public:
return;
}
- infered = resolved->get_field_type ();
+ infered = lookup->get_field_type ();
}
void visit (HIR::QualifiedPathInExpression &expr) override;
diff --git a/gcc/rust/typecheck/rust-hir-type-check-path.cc b/gcc/rust/typecheck/rust-hir-type-check-path.cc
index 20f7156..8aa4484 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-path.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check-path.cc
@@ -359,7 +359,24 @@ TypeCheckExpr::resolve_segments (NodeId root_resolved_node_id,
prev_segment = tyseg;
tyseg = candidate.ty;
- if (candidate.is_impl_candidate ())
+ if (candidate.is_enum_candidate ())
+ {
+ const TyTy::VariantDef *variant = candidate.item.enum_field.variant;
+
+ CrateNum crate_num = mappings->get_current_crate ();
+ HirId variant_id = variant->get_id ();
+
+ HIR::Item *enum_item
+ = mappings->lookup_hir_item (crate_num, variant_id);
+ rust_assert (enum_item != nullptr);
+
+ resolved_node_id = enum_item->get_mappings ().get_nodeid ();
+
+ // insert the id of the variant we are resolved to
+ context->insert_variant_definition (expr_mappings.get_hirid (),
+ variant_id);
+ }
+ else if (candidate.is_impl_candidate ())
{
resolved_node_id
= candidate.item.impl.impl_item->get_impl_mappings ().get_nodeid ();
diff --git a/gcc/rust/typecheck/rust-hir-type-check-stmt.h b/gcc/rust/typecheck/rust-hir-type-check-stmt.h
index 74bc037..8df43d9 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-stmt.h
+++ b/gcc/rust/typecheck/rust-hir-type-check-stmt.h
@@ -23,6 +23,7 @@
#include "rust-hir-full.h"
#include "rust-hir-type-check-type.h"
#include "rust-hir-type-check-expr.h"
+#include "rust-hir-type-check-enumitem.h"
namespace Rust {
namespace Resolver {
@@ -155,7 +156,6 @@ public:
}
std::vector<TyTy::StructFieldType *> fields;
-
size_t idx = 0;
for (auto &field : struct_decl.get_fields ())
{
@@ -170,17 +170,75 @@ public:
idx++;
}
+ // there is only a single variant
+ std::vector<TyTy::VariantDef *> variants;
+ variants.push_back (new TyTy::VariantDef (
+ struct_decl.get_mappings ().get_hirid (), struct_decl.get_identifier (),
+ TyTy::VariantDef::VariantType::TUPLE, std::move (fields)));
+
TyTy::BaseType *type
= new TyTy::ADTType (struct_decl.get_mappings ().get_hirid (),
mappings->get_next_hir_id (),
struct_decl.get_identifier (),
TyTy::ADTType::ADTKind::TUPLE_STRUCT,
- std::move (fields), std::move (substitutions));
+ std::move (variants), std::move (substitutions));
context->insert_type (struct_decl.get_mappings (), type);
infered = type;
}
+ void visit (HIR::Enum &enum_decl) override
+ {
+ std::vector<TyTy::SubstitutionParamMapping> substitutions;
+ if (enum_decl.has_generics ())
+ {
+ for (auto &generic_param : enum_decl.get_generic_params ())
+ {
+ switch (generic_param.get ()->get_kind ())
+ {
+ case HIR::GenericParam::GenericKind::LIFETIME:
+ // Skipping Lifetime completely until better handling.
+ break;
+
+ case HIR::GenericParam::GenericKind::TYPE: {
+ auto param_type
+ = TypeResolveGenericParam::Resolve (generic_param.get ());
+ context->insert_type (generic_param->get_mappings (),
+ param_type);
+
+ substitutions.push_back (TyTy::SubstitutionParamMapping (
+ static_cast<HIR::TypeParam &> (*generic_param),
+ param_type));
+ }
+ break;
+ }
+ }
+ }
+
+ std::vector<TyTy::VariantDef *> variants;
+ int64_t discriminant_value = 0;
+ for (auto &variant : enum_decl.get_variants ())
+ {
+ TyTy::VariantDef *field_type
+ = TypeCheckEnumItem::Resolve (variant.get (), discriminant_value);
+
+ variants.push_back (field_type);
+ if (field_type->get_variant_type ()
+ == TyTy::VariantDef::VariantType::NUM)
+ discriminant_value = field_type->get_discriminant ();
+ }
+
+ TyTy::BaseType *type
+ = new TyTy::ADTType (enum_decl.get_mappings ().get_hirid (),
+ mappings->get_next_hir_id (),
+ enum_decl.get_identifier (),
+ TyTy::ADTType::ADTKind::ENUM, std::move (variants),
+ std::move (substitutions));
+
+ context->insert_type (enum_decl.get_mappings (), type);
+ infered = type;
+ }
+
void visit (HIR::StructStruct &struct_decl) override
{
std::vector<TyTy::SubstitutionParamMapping> substitutions;
@@ -222,12 +280,18 @@ public:
ty_field->get_field_type ());
}
+ // there is only a single variant
+ std::vector<TyTy::VariantDef *> variants;
+ variants.push_back (new TyTy::VariantDef (
+ struct_decl.get_mappings ().get_hirid (), struct_decl.get_identifier (),
+ TyTy::VariantDef::VariantType::STRUCT, std::move (fields)));
+
TyTy::BaseType *type
= new TyTy::ADTType (struct_decl.get_mappings ().get_hirid (),
mappings->get_next_hir_id (),
struct_decl.get_identifier (),
TyTy::ADTType::ADTKind::STRUCT_STRUCT,
- std::move (fields), std::move (substitutions));
+ std::move (variants), std::move (substitutions));
context->insert_type (struct_decl.get_mappings (), type);
infered = type;
@@ -261,18 +325,24 @@ public:
}
}
- std::vector<TyTy::StructFieldType *> variants;
- union_decl.iterate ([&] (HIR::StructField &variant) mutable -> bool {
- TyTy::BaseType *variant_type
- = TypeCheckType::Resolve (variant.get_field_type ().get ());
- TyTy::StructFieldType *ty_variant
- = new TyTy::StructFieldType (variant.get_mappings ().get_hirid (),
- variant.get_field_name (), variant_type);
- variants.push_back (ty_variant);
- context->insert_type (variant.get_mappings (),
- ty_variant->get_field_type ());
- return true;
- });
+ std::vector<TyTy::StructFieldType *> fields;
+ for (auto &variant : union_decl.get_variants ())
+ {
+ TyTy::BaseType *variant_type
+ = TypeCheckType::Resolve (variant.get_field_type ().get ());
+ TyTy::StructFieldType *ty_variant
+ = new TyTy::StructFieldType (variant.get_mappings ().get_hirid (),
+ variant.get_field_name (), variant_type);
+ fields.push_back (ty_variant);
+ context->insert_type (variant.get_mappings (),
+ ty_variant->get_field_type ());
+ }
+
+ // there is only a single variant
+ std::vector<TyTy::VariantDef *> variants;
+ variants.push_back (new TyTy::VariantDef (
+ union_decl.get_mappings ().get_hirid (), union_decl.get_identifier (),
+ TyTy::VariantDef::VariantType::STRUCT, std::move (fields)));
TyTy::BaseType *type
= new TyTy::ADTType (union_decl.get_mappings ().get_hirid (),
diff --git a/gcc/rust/typecheck/rust-hir-type-check-struct-field.h b/gcc/rust/typecheck/rust-hir-type-check-struct-field.h
index 6aa3134..4c4b128 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-struct-field.h
+++ b/gcc/rust/typecheck/rust-hir-type-check-struct-field.h
@@ -51,7 +51,8 @@ private:
TypeCheckStructExpr (HIR::Expr *e)
: TypeCheckBase (),
resolved (new TyTy::ErrorType (e->get_mappings ().get_hirid ())),
- struct_path_resolved (nullptr)
+ struct_path_resolved (nullptr),
+ variant (&TyTy::VariantDef::get_error_node ())
{}
// result
@@ -59,6 +60,7 @@ private:
// internal state:
TyTy::ADTType *struct_path_resolved;
+ TyTy::VariantDef *variant;
TyTy::BaseType *resolved_field_value_expr;
std::set<std::string> fields_assigned;
std::map<size_t, HIR::StructExprField *> adtFieldIndexToField;
diff --git a/gcc/rust/typecheck/rust-hir-type-check-struct.cc b/gcc/rust/typecheck/rust-hir-type-check-struct.cc
new file mode 100644
index 0000000..78340c3
--- /dev/null
+++ b/gcc/rust/typecheck/rust-hir-type-check-struct.cc
@@ -0,0 +1,298 @@
+// Copyright (C) 2020-2021 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "rust-hir-type-check.h"
+#include "rust-hir-full.h"
+#include "rust-hir-type-check-expr.h"
+#include "rust-hir-type-check-struct-field.h"
+
+namespace Rust {
+namespace Resolver {
+
+void
+TypeCheckStructExpr::visit (HIR::StructExprStructFields &struct_expr)
+{
+ TyTy::BaseType *struct_path_ty
+ = TypeCheckExpr::Resolve (&struct_expr.get_struct_name (), false);
+ if (struct_path_ty->get_kind () != TyTy::TypeKind::ADT)
+ {
+ rust_error_at (struct_expr.get_struct_name ().get_locus (),
+ "expected an ADT type for constructor");
+ return;
+ }
+
+ struct_path_resolved = static_cast<TyTy::ADTType *> (struct_path_ty);
+ TyTy::ADTType *struct_def = struct_path_resolved;
+ if (struct_expr.has_struct_base ())
+ {
+ TyTy::BaseType *base_resolved
+ = TypeCheckExpr::Resolve (struct_expr.struct_base->base_struct.get (),
+ false);
+ struct_def
+ = (TyTy::ADTType *) struct_path_resolved->unify (base_resolved);
+ if (struct_def == nullptr)
+ {
+ rust_fatal_error (struct_expr.struct_base->base_struct->get_locus (),
+ "incompatible types for base struct reference");
+ return;
+ }
+ }
+
+ // figure out the variant
+ if (struct_path_resolved->is_enum ())
+ {
+ // lookup variant id
+ HirId variant_id;
+ bool ok = context->lookup_variant_definition (
+ struct_expr.get_struct_name ().get_mappings ().get_hirid (),
+ &variant_id);
+ rust_assert (ok);
+
+ ok = struct_path_resolved->lookup_variant_by_id (variant_id, &variant);
+ rust_assert (ok);
+ }
+ else
+ {
+ rust_assert (struct_path_resolved->number_of_variants () == 1);
+ variant = struct_path_resolved->get_variants ().at (0);
+ }
+
+ std::vector<TyTy::StructFieldType *> infered_fields;
+ bool ok = true;
+
+ for (auto &field : struct_expr.get_fields ())
+ {
+ resolved_field_value_expr = nullptr;
+ field->accept_vis (*this);
+ if (resolved_field_value_expr == nullptr)
+ {
+ rust_fatal_error (field->get_locus (),
+ "failed to resolve type for field");
+ ok = false;
+ break;
+ }
+
+ context->insert_type (field->get_mappings (), resolved_field_value_expr);
+ }
+
+ // something failed setting up the fields
+ if (!ok)
+ {
+ rust_error_at (struct_expr.get_locus (),
+ "constructor type resolution failure");
+ return;
+ }
+
+ // check the arguments are all assigned and fix up the ordering
+ if (fields_assigned.size () != variant->num_fields ())
+ {
+ if (struct_def->is_union ())
+ {
+ if (fields_assigned.size () != 1 || struct_expr.has_struct_base ())
+ {
+ rust_error_at (
+ struct_expr.get_locus (),
+ "union must have exactly one field variant assigned");
+ return;
+ }
+ }
+ else if (!struct_expr.has_struct_base ())
+ {
+ rust_error_at (struct_expr.get_locus (),
+ "constructor is missing fields");
+ return;
+ }
+ else
+ {
+ // we have a struct base to assign the missing fields from.
+ // the missing fields can be implicit FieldAccessExprs for the value
+ std::set<std::string> missing_fields;
+ for (auto &field : variant->get_fields ())
+ {
+ auto it = fields_assigned.find (field->get_name ());
+ if (it == fields_assigned.end ())
+ missing_fields.insert (field->get_name ());
+ }
+
+ // we can generate FieldAccessExpr or TupleAccessExpr for the
+ // values of the missing fields.
+ for (auto &missing : missing_fields)
+ {
+ HIR::Expr *receiver
+ = struct_expr.struct_base->base_struct->clone_expr_impl ();
+
+ HIR::StructExprField *implicit_field = nullptr;
+
+ AST::AttrVec outer_attribs;
+ auto crate_num = mappings->get_current_crate ();
+ Analysis::NodeMapping mapping (
+ crate_num,
+ struct_expr.struct_base->base_struct->get_mappings ()
+ .get_nodeid (),
+ mappings->get_next_hir_id (crate_num), UNKNOWN_LOCAL_DEFID);
+
+ HIR::Expr *field_value = new HIR::FieldAccessExpr (
+ mapping, std::unique_ptr<HIR::Expr> (receiver), missing,
+ std::move (outer_attribs),
+ struct_expr.struct_base->base_struct->get_locus ());
+
+ implicit_field = new HIR::StructExprFieldIdentifierValue (
+ mapping, missing, std::unique_ptr<HIR::Expr> (field_value),
+ struct_expr.struct_base->base_struct->get_locus ());
+
+ size_t field_index;
+ bool ok = variant->lookup_field (missing, nullptr, &field_index);
+ rust_assert (ok);
+
+ adtFieldIndexToField[field_index] = implicit_field;
+ struct_expr.get_fields ().push_back (
+ std::unique_ptr<HIR::StructExprField> (implicit_field));
+ }
+ }
+ }
+
+ if (struct_def->is_union ())
+ {
+ // There is exactly one field in this constructor, we need to
+ // figure out the field index to make sure we initialize the
+ // right union field.
+ for (size_t i = 0; i < adtFieldIndexToField.size (); i++)
+ {
+ if (adtFieldIndexToField[i])
+ {
+ struct_expr.union_index = i;
+ break;
+ }
+ }
+ rust_assert (struct_expr.union_index != -1);
+ }
+ else
+ {
+ // everything is ok, now we need to ensure all field values are ordered
+ // correctly. The GIMPLE backend uses a simple algorithm that assumes each
+ // assigned field in the constructor is in the same order as the field in
+ // the type
+ for (auto &field : struct_expr.get_fields ())
+ field.release ();
+
+ std::vector<std::unique_ptr<HIR::StructExprField> > ordered_fields;
+ for (size_t i = 0; i < adtFieldIndexToField.size (); i++)
+ {
+ ordered_fields.push_back (
+ std::unique_ptr<HIR::StructExprField> (adtFieldIndexToField[i]));
+ }
+ struct_expr.set_fields_as_owner (std::move (ordered_fields));
+ }
+
+ resolved = struct_def;
+}
+
+void
+TypeCheckStructExpr::visit (HIR::StructExprFieldIdentifierValue &field)
+{
+ auto it = fields_assigned.find (field.field_name);
+ if (it != fields_assigned.end ())
+ {
+ rust_fatal_error (field.get_locus (), "used more than once");
+ return;
+ }
+
+ size_t field_index;
+ TyTy::StructFieldType *field_type;
+ bool ok = variant->lookup_field (field.field_name, &field_type, &field_index);
+ if (!ok)
+ {
+ rust_error_at (field.get_locus (), "unknown field");
+ return;
+ }
+
+ TyTy::BaseType *value = TypeCheckExpr::Resolve (field.get_value (), false);
+ resolved_field_value_expr = field_type->get_field_type ()->unify (value);
+ if (resolved_field_value_expr != nullptr)
+ {
+ fields_assigned.insert (field.field_name);
+ adtFieldIndexToField[field_index] = &field;
+ }
+}
+
+void
+TypeCheckStructExpr::visit (HIR::StructExprFieldIndexValue &field)
+{
+ std::string field_name (std::to_string (field.get_tuple_index ()));
+ auto it = fields_assigned.find (field_name);
+ if (it != fields_assigned.end ())
+ {
+ rust_fatal_error (field.get_locus (), "used more than once");
+ return;
+ }
+
+ size_t field_index;
+ TyTy::StructFieldType *field_type;
+ bool ok = variant->lookup_field (field_name, &field_type, &field_index);
+ if (!ok)
+ {
+ rust_error_at (field.get_locus (), "unknown field");
+ return;
+ }
+
+ TyTy::BaseType *value = TypeCheckExpr::Resolve (field.get_value (), false);
+ resolved_field_value_expr = field_type->get_field_type ()->unify (value);
+ if (resolved_field_value_expr != nullptr)
+ {
+ fields_assigned.insert (field_name);
+ adtFieldIndexToField[field_index] = &field;
+ }
+}
+
+void
+TypeCheckStructExpr::visit (HIR::StructExprFieldIdentifier &field)
+{
+ auto it = fields_assigned.find (field.get_field_name ());
+ if (it != fields_assigned.end ())
+ {
+ rust_fatal_error (field.get_locus (), "used more than once");
+ return;
+ }
+
+ size_t field_index;
+ TyTy::StructFieldType *field_type;
+ bool ok = variant->lookup_field (field.get_field_name (), &field_type,
+ &field_index);
+ if (!ok)
+ {
+ rust_error_at (field.get_locus (), "unknown field");
+ return;
+ }
+
+ // we can make the field look like an identifier expr to take advantage of
+ // existing code to figure out the type
+ HIR::IdentifierExpr expr (field.get_mappings (), field.get_field_name (),
+ field.get_locus ());
+ TyTy::BaseType *value = TypeCheckExpr::Resolve (&expr, false);
+
+ resolved_field_value_expr = field_type->get_field_type ()->unify (value);
+ if (resolved_field_value_expr != nullptr)
+
+ {
+ fields_assigned.insert (field.field_name);
+ adtFieldIndexToField[field_index] = &field;
+ }
+}
+
+} // namespace Resolver
+} // namespace Rust
diff --git a/gcc/rust/typecheck/rust-hir-type-check-toplevel.h b/gcc/rust/typecheck/rust-hir-type-check-toplevel.h
index a32d4a4..7b1dfc9 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-toplevel.h
+++ b/gcc/rust/typecheck/rust-hir-type-check-toplevel.h
@@ -24,6 +24,7 @@
#include "rust-hir-type-check-implitem.h"
#include "rust-hir-type-check-type.h"
#include "rust-hir-type-check-expr.h"
+#include "rust-hir-type-check-enumitem.h"
#include "rust-tyty.h"
namespace Rust {
@@ -87,7 +88,6 @@ public:
}
std::vector<TyTy::StructFieldType *> fields;
-
size_t idx = 0;
for (auto &field : struct_decl.get_fields ())
{
@@ -102,12 +102,18 @@ public:
idx++;
}
+ // there is only a single variant
+ std::vector<TyTy::VariantDef *> variants;
+ variants.push_back (new TyTy::VariantDef (
+ struct_decl.get_mappings ().get_hirid (), struct_decl.get_identifier (),
+ TyTy::VariantDef::VariantType::TUPLE, std::move (fields)));
+
TyTy::BaseType *type
= new TyTy::ADTType (struct_decl.get_mappings ().get_hirid (),
mappings->get_next_hir_id (),
struct_decl.get_identifier (),
TyTy::ADTType::ADTKind::TUPLE_STRUCT,
- std::move (fields), std::move (substitutions));
+ std::move (variants), std::move (substitutions));
context->insert_type (struct_decl.get_mappings (), type);
}
@@ -165,16 +171,73 @@ public:
ty_field->get_field_type ());
}
+ // there is only a single variant
+ std::vector<TyTy::VariantDef *> variants;
+ variants.push_back (new TyTy::VariantDef (
+ struct_decl.get_mappings ().get_hirid (), struct_decl.get_identifier (),
+ TyTy::VariantDef::VariantType::STRUCT, std::move (fields)));
+
TyTy::BaseType *type
= new TyTy::ADTType (struct_decl.get_mappings ().get_hirid (),
mappings->get_next_hir_id (),
struct_decl.get_identifier (),
TyTy::ADTType::ADTKind::STRUCT_STRUCT,
- std::move (fields), std::move (substitutions));
+ std::move (variants), std::move (substitutions));
context->insert_type (struct_decl.get_mappings (), type);
}
+ void visit (HIR::Enum &enum_decl) override
+ {
+ std::vector<TyTy::SubstitutionParamMapping> substitutions;
+ if (enum_decl.has_generics ())
+ {
+ for (auto &generic_param : enum_decl.get_generic_params ())
+ {
+ switch (generic_param.get ()->get_kind ())
+ {
+ case HIR::GenericParam::GenericKind::LIFETIME:
+ // Skipping Lifetime completely until better handling.
+ break;
+
+ case HIR::GenericParam::GenericKind::TYPE: {
+ auto param_type
+ = TypeResolveGenericParam::Resolve (generic_param.get ());
+ context->insert_type (generic_param->get_mappings (),
+ param_type);
+
+ substitutions.push_back (TyTy::SubstitutionParamMapping (
+ static_cast<HIR::TypeParam &> (*generic_param),
+ param_type));
+ }
+ break;
+ }
+ }
+ }
+
+ std::vector<TyTy::VariantDef *> variants;
+ int64_t discriminant_value = 0;
+ for (auto &variant : enum_decl.get_variants ())
+ {
+ TyTy::VariantDef *field_type
+ = TypeCheckEnumItem::Resolve (variant.get (), discriminant_value);
+
+ variants.push_back (field_type);
+ if (field_type->get_variant_type ()
+ == TyTy::VariantDef::VariantType::NUM)
+ discriminant_value = field_type->get_discriminant ();
+ }
+
+ TyTy::BaseType *type
+ = new TyTy::ADTType (enum_decl.get_mappings ().get_hirid (),
+ mappings->get_next_hir_id (),
+ enum_decl.get_identifier (),
+ TyTy::ADTType::ADTKind::ENUM, std::move (variants),
+ std::move (substitutions));
+
+ context->insert_type (enum_decl.get_mappings (), type);
+ }
+
void visit (HIR::Union &union_decl) override
{
std::vector<TyTy::SubstitutionParamMapping> substitutions;
@@ -208,18 +271,24 @@ public:
ResolveWhereClauseItem::Resolve (*where_clause_item.get ());
}
- std::vector<TyTy::StructFieldType *> variants;
- union_decl.iterate ([&] (HIR::StructField &variant) mutable -> bool {
- TyTy::BaseType *variant_type
- = TypeCheckType::Resolve (variant.get_field_type ().get ());
- TyTy::StructFieldType *ty_variant
- = new TyTy::StructFieldType (variant.get_mappings ().get_hirid (),
- variant.get_field_name (), variant_type);
- variants.push_back (ty_variant);
- context->insert_type (variant.get_mappings (),
- ty_variant->get_field_type ());
- return true;
- });
+ std::vector<TyTy::StructFieldType *> fields;
+ for (auto &variant : union_decl.get_variants ())
+ {
+ TyTy::BaseType *variant_type
+ = TypeCheckType::Resolve (variant.get_field_type ().get ());
+ TyTy::StructFieldType *ty_variant
+ = new TyTy::StructFieldType (variant.get_mappings ().get_hirid (),
+ variant.get_field_name (), variant_type);
+ fields.push_back (ty_variant);
+ context->insert_type (variant.get_mappings (),
+ ty_variant->get_field_type ());
+ }
+
+ // there is only a single variant
+ std::vector<TyTy::VariantDef *> variants;
+ variants.push_back (new TyTy::VariantDef (
+ union_decl.get_mappings ().get_hirid (), union_decl.get_identifier (),
+ TyTy::VariantDef::VariantType::STRUCT, std::move (fields)));
TyTy::BaseType *type
= new TyTy::ADTType (union_decl.get_mappings ().get_hirid (),
diff --git a/gcc/rust/typecheck/rust-hir-type-check.cc b/gcc/rust/typecheck/rust-hir-type-check.cc
index 0febc6c..5237082 100644
--- a/gcc/rust/typecheck/rust-hir-type-check.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check.cc
@@ -120,262 +120,6 @@ TypeCheckExpr::visit (HIR::BlockExpr &expr)
infered = new TyTy::NeverType (expr.get_mappings ().get_hirid ());
}
-// RUST_HIR_TYPE_CHECK_STRUCT_FIELD
-
-void
-TypeCheckStructExpr::visit (HIR::StructExprStructFields &struct_expr)
-{
- TyTy::BaseType *struct_path_ty
- = TypeCheckExpr::Resolve (&struct_expr.get_struct_name (), false);
- if (struct_path_ty->get_kind () != TyTy::TypeKind::ADT)
- {
- rust_error_at (struct_expr.get_struct_name ().get_locus (),
- "expected an ADT type for constructor");
- return;
- }
-
- struct_path_resolved = static_cast<TyTy::ADTType *> (struct_path_ty);
- TyTy::ADTType *struct_def = struct_path_resolved;
- if (struct_expr.has_struct_base ())
- {
- TyTy::BaseType *base_resolved
- = TypeCheckExpr::Resolve (struct_expr.struct_base->base_struct.get (),
- false);
- struct_def
- = (TyTy::ADTType *) struct_path_resolved->unify (base_resolved);
- if (struct_def == nullptr)
- {
- rust_fatal_error (struct_expr.struct_base->base_struct->get_locus (),
- "incompatible types for base struct reference");
- return;
- }
- }
-
- std::vector<TyTy::StructFieldType *> infered_fields;
- bool ok = true;
-
- for (auto &field : struct_expr.get_fields ())
- {
- resolved_field_value_expr = nullptr;
- field->accept_vis (*this);
- if (resolved_field_value_expr == nullptr)
- {
- rust_fatal_error (field->get_locus (),
- "failed to resolve type for field");
- ok = false;
- break;
- }
-
- context->insert_type (field->get_mappings (), resolved_field_value_expr);
- }
-
- // something failed setting up the fields
- if (!ok)
- {
- rust_error_at (struct_expr.get_locus (),
- "constructor type resolution failure");
- return;
- }
-
- // check the arguments are all assigned and fix up the ordering
- if (fields_assigned.size () != struct_path_resolved->num_fields ())
- {
- if (struct_def->is_union ())
- {
- if (fields_assigned.size () != 1 || struct_expr.has_struct_base ())
- {
- rust_error_at (
- struct_expr.get_locus (),
- "union must have exactly one field variant assigned");
- return;
- }
- }
- else if (!struct_expr.has_struct_base ())
- {
- rust_error_at (struct_expr.get_locus (),
- "constructor is missing fields");
- return;
- }
- else
- {
- // we have a struct base to assign the missing fields from.
- // the missing fields can be implicit FieldAccessExprs for the value
- std::set<std::string> missing_fields;
- struct_path_resolved->iterate_fields (
- [&] (TyTy::StructFieldType *field) mutable -> bool {
- auto it = fields_assigned.find (field->get_name ());
- if (it == fields_assigned.end ())
- missing_fields.insert (field->get_name ());
- return true;
- });
-
- // we can generate FieldAccessExpr or TupleAccessExpr for the values
- // of the missing fields.
- for (auto &missing : missing_fields)
- {
- HIR::Expr *receiver
- = struct_expr.struct_base->base_struct->clone_expr_impl ();
-
- HIR::StructExprField *implicit_field = nullptr;
-
- AST::AttrVec outer_attribs;
- auto crate_num = mappings->get_current_crate ();
- Analysis::NodeMapping mapping (
- crate_num,
- struct_expr.struct_base->base_struct->get_mappings ()
- .get_nodeid (),
- mappings->get_next_hir_id (crate_num), UNKNOWN_LOCAL_DEFID);
-
- HIR::Expr *field_value = new HIR::FieldAccessExpr (
- mapping, std::unique_ptr<HIR::Expr> (receiver), missing,
- std::move (outer_attribs),
- struct_expr.struct_base->base_struct->get_locus ());
-
- implicit_field = new HIR::StructExprFieldIdentifierValue (
- mapping, missing, std::unique_ptr<HIR::Expr> (field_value),
- struct_expr.struct_base->base_struct->get_locus ());
-
- size_t field_index;
- bool ok = struct_path_resolved->get_field (missing, &field_index);
- rust_assert (ok);
-
- adtFieldIndexToField[field_index] = implicit_field;
- struct_expr.get_fields ().push_back (
- std::unique_ptr<HIR::StructExprField> (implicit_field));
- }
- }
- }
-
- if (struct_def->is_union ())
- {
- // There is exactly one field in this constructor, we need to
- // figure out the field index to make sure we initialize the
- // right union field.
- for (size_t i = 0; i < adtFieldIndexToField.size (); i++)
- {
- if (adtFieldIndexToField[i])
- {
- struct_expr.union_index = i;
- break;
- }
- }
- rust_assert (struct_expr.union_index != -1);
- }
- else
- {
- // everything is ok, now we need to ensure all field values are ordered
- // correctly. The GIMPLE backend uses a simple algorithm that assumes each
- // assigned field in the constructor is in the same order as the field in
- // the type
- for (auto &field : struct_expr.get_fields ())
- field.release ();
-
- std::vector<std::unique_ptr<HIR::StructExprField> > ordered_fields;
- for (size_t i = 0; i < adtFieldIndexToField.size (); i++)
- {
- ordered_fields.push_back (
- std::unique_ptr<HIR::StructExprField> (adtFieldIndexToField[i]));
- }
- struct_expr.set_fields_as_owner (std::move (ordered_fields));
- }
-
- resolved = struct_def;
-}
-
-void
-TypeCheckStructExpr::visit (HIR::StructExprFieldIdentifierValue &field)
-{
- auto it = fields_assigned.find (field.field_name);
- if (it != fields_assigned.end ())
- {
- rust_fatal_error (field.get_locus (), "used more than once");
- return;
- }
-
- size_t field_index;
- TyTy::StructFieldType *field_type
- = struct_path_resolved->get_field (field.field_name, &field_index);
- if (field_type == nullptr)
- {
- rust_error_at (field.get_locus (), "unknown field");
- return;
- }
-
- TyTy::BaseType *value = TypeCheckExpr::Resolve (field.get_value (), false);
- resolved_field_value_expr = field_type->get_field_type ()->unify (value);
- if (resolved_field_value_expr != nullptr)
- {
- fields_assigned.insert (field.field_name);
- adtFieldIndexToField[field_index] = &field;
- }
-}
-
-void
-TypeCheckStructExpr::visit (HIR::StructExprFieldIndexValue &field)
-{
- std::string field_name (std::to_string (field.get_tuple_index ()));
- auto it = fields_assigned.find (field_name);
- if (it != fields_assigned.end ())
- {
- rust_fatal_error (field.get_locus (), "used more than once");
- return;
- }
-
- size_t field_index;
-
- TyTy::StructFieldType *field_type
- = struct_path_resolved->get_field (field_name, &field_index);
- if (field_type == nullptr)
- {
- rust_error_at (field.get_locus (), "unknown field");
- return;
- }
-
- TyTy::BaseType *value = TypeCheckExpr::Resolve (field.get_value (), false);
- resolved_field_value_expr = field_type->get_field_type ()->unify (value);
- if (resolved_field_value_expr != nullptr)
- {
- fields_assigned.insert (field_name);
- adtFieldIndexToField[field_index] = &field;
- }
-}
-
-void
-TypeCheckStructExpr::visit (HIR::StructExprFieldIdentifier &field)
-{
- auto it = fields_assigned.find (field.get_field_name ());
- if (it != fields_assigned.end ())
- {
- rust_fatal_error (field.get_locus (), "used more than once");
- return;
- }
-
- size_t field_index;
- TyTy::StructFieldType *field_type
- = struct_path_resolved->get_field (field.get_field_name (), &field_index);
- if (field_type == nullptr)
- {
- rust_error_at (field.get_locus (), "unknown field");
- return;
- }
-
- // we can make the field look like an identifier expr to take advantage of
- // existing code to figure out the type
- HIR::IdentifierExpr expr (field.get_mappings (), field.get_field_name (),
- field.get_locus ());
- TyTy::BaseType *value = TypeCheckExpr::Resolve (&expr, false);
-
- resolved_field_value_expr = field_type->get_field_type ()->unify (value);
- if (resolved_field_value_expr != nullptr)
-
- {
- fields_assigned.insert (field.field_name);
- adtFieldIndexToField[field_index] = &field;
- }
-}
-
-// rust-hir-type-check-type.h
-
void
TypeCheckType::visit (HIR::ArrayType &type)
{
diff --git a/gcc/rust/typecheck/rust-hir-type-check.h b/gcc/rust/typecheck/rust-hir-type-check.h
index 76eac3f..aa10f41 100644
--- a/gcc/rust/typecheck/rust-hir-type-check.h
+++ b/gcc/rust/typecheck/rust-hir-type-check.h
@@ -214,6 +214,24 @@ public:
return true;
}
+ void insert_variant_definition (HirId id, HirId variant)
+ {
+ auto it = variants.find (id);
+ rust_assert (it == variants.end ());
+
+ variants[id] = variant;
+ }
+
+ bool lookup_variant_definition (HirId id, HirId *variant)
+ {
+ auto it = variants.find (id);
+ if (it == variants.end ())
+ return false;
+
+ *variant = it->second;
+ return true;
+ }
+
private:
TypeCheckContext ();
@@ -234,6 +252,9 @@ private:
// adjustment mappings
std::map<HirId, std::vector<Adjustment>> autoderef_mappings;
+
+ // variants
+ std::map<HirId, HirId> variants;
};
class TypeResolution
diff --git a/gcc/rust/typecheck/rust-tyty-call.h b/gcc/rust/typecheck/rust-tyty-call.h
index c7001dd..c11fd4d 100644
--- a/gcc/rust/typecheck/rust-tyty-call.h
+++ b/gcc/rust/typecheck/rust-tyty-call.h
@@ -32,9 +32,10 @@ class TypeCheckCallExpr : private TyVisitor
{
public:
static BaseType *go (BaseType *ref, HIR::CallExpr &call,
+ TyTy::VariantDef &variant,
Resolver::TypeCheckContext *context)
{
- TypeCheckCallExpr checker (call, context);
+ TypeCheckCallExpr checker (call, variant, context);
ref->accept_vis (checker);
return checker.resolved;
}
@@ -58,6 +59,7 @@ public:
void visit (PlaceholderType &) override { gcc_unreachable (); }
void visit (ProjectionType &) override { gcc_unreachable (); }
void visit (DynamicObjectType &) override { gcc_unreachable (); }
+ void visit (ClosureType &type) override { gcc_unreachable (); }
// tuple-structs
void visit (ADTType &type) override;
@@ -65,16 +67,18 @@ public:
// call fns
void visit (FnType &type) override;
void visit (FnPtr &type) override;
- void visit (ClosureType &type) override { gcc_unreachable (); }
private:
- TypeCheckCallExpr (HIR::CallExpr &c, Resolver::TypeCheckContext *context)
- : resolved (nullptr), call (c), context (context),
+ TypeCheckCallExpr (HIR::CallExpr &c, TyTy::VariantDef &variant,
+ Resolver::TypeCheckContext *context)
+ : resolved (new TyTy::ErrorType (c.get_mappings ().get_hirid ())), call (c),
+ variant (variant), context (context),
mappings (Analysis::Mappings::get ())
{}
BaseType *resolved;
HIR::CallExpr &call;
+ TyTy::VariantDef &variant;
Resolver::TypeCheckContext *context;
Analysis::Mappings *mappings;
};
diff --git a/gcc/rust/typecheck/rust-tyty-cast.h b/gcc/rust/typecheck/rust-tyty-cast.h
index 874fe2a..aaa589b 100644
--- a/gcc/rust/typecheck/rust-tyty-cast.h
+++ b/gcc/rust/typecheck/rust-tyty-cast.h
@@ -993,29 +993,47 @@ public:
void visit (ADTType &type) override
{
+ if (base->get_adt_kind () != type.get_adt_kind ())
+ {
+ BaseCastRules::visit (type);
+ return;
+ }
+
if (base->get_identifier ().compare (type.get_identifier ()) != 0)
{
BaseCastRules::visit (type);
return;
}
- if (base->num_fields () != type.num_fields ())
+ if (base->number_of_variants () != type.number_of_variants ())
{
BaseCastRules::visit (type);
return;
}
- for (size_t i = 0; i < type.num_fields (); ++i)
+ for (size_t i = 0; i < type.number_of_variants (); ++i)
{
- TyTy::StructFieldType *base_field = base->get_field (i);
- TyTy::StructFieldType *other_field = type.get_field (i);
+ TyTy::VariantDef *a = base->get_variants ().at (i);
+ TyTy::VariantDef *b = type.get_variants ().at (i);
- TyTy::BaseType *this_field_ty = base_field->get_field_type ();
- TyTy::BaseType *other_field_ty = other_field->get_field_type ();
+ if (a->num_fields () != b->num_fields ())
+ {
+ BaseCastRules::visit (type);
+ return;
+ }
- BaseType *unified_ty = this_field_ty->unify (other_field_ty);
- if (unified_ty->get_kind () == TyTy::TypeKind::ERROR)
- return;
+ for (size_t j = 0; j < a->num_fields (); j++)
+ {
+ TyTy::StructFieldType *base_field = a->get_field_at_index (i);
+ TyTy::StructFieldType *other_field = b->get_field_at_index (i);
+
+ TyTy::BaseType *this_field_ty = base_field->get_field_type ();
+ TyTy::BaseType *other_field_ty = other_field->get_field_type ();
+
+ BaseType *unified_ty = this_field_ty->unify (other_field_ty);
+ if (unified_ty->get_kind () == TyTy::TypeKind::ERROR)
+ return;
+ }
}
resolved = type.clone ();
diff --git a/gcc/rust/typecheck/rust-tyty-cmp.h b/gcc/rust/typecheck/rust-tyty-cmp.h
index 68b04fe..4ab3df2 100644
--- a/gcc/rust/typecheck/rust-tyty-cmp.h
+++ b/gcc/rust/typecheck/rust-tyty-cmp.h
@@ -990,32 +990,50 @@ public:
void visit (const ADTType &type) override
{
- if (base->get_identifier ().compare (type.get_identifier ()) != 0)
+ if (base->get_adt_kind () != type.get_adt_kind ())
{
BaseCmp::visit (type);
return;
}
- if (base->num_fields () != type.num_fields ())
+ if (base->get_identifier ().compare (type.get_identifier ()) != 0)
{
BaseCmp::visit (type);
return;
}
- for (size_t i = 0; i < type.num_fields (); ++i)
+ if (base->number_of_variants () != type.number_of_variants ())
{
- const TyTy::StructFieldType *base_field = base->get_imm_field (i);
- const TyTy::StructFieldType *other_field = type.get_imm_field (i);
+ BaseCmp::visit (type);
+ return;
+ }
- TyTy::BaseType *this_field_ty = base_field->get_field_type ();
- TyTy::BaseType *other_field_ty = other_field->get_field_type ();
+ for (size_t i = 0; i < type.number_of_variants (); ++i)
+ {
+ TyTy::VariantDef *a = base->get_variants ().at (i);
+ TyTy::VariantDef *b = type.get_variants ().at (i);
- if (!this_field_ty->can_eq (other_field_ty, emit_error_flag,
- autoderef_mode_flag))
+ if (a->num_fields () != b->num_fields ())
{
BaseCmp::visit (type);
return;
}
+
+ for (size_t j = 0; j < a->num_fields (); j++)
+ {
+ TyTy::StructFieldType *base_field = a->get_field_at_index (i);
+ TyTy::StructFieldType *other_field = b->get_field_at_index (i);
+
+ TyTy::BaseType *this_field_ty = base_field->get_field_type ();
+ TyTy::BaseType *other_field_ty = other_field->get_field_type ();
+
+ if (!this_field_ty->can_eq (other_field_ty, emit_error_flag,
+ autoderef_mode_flag))
+ {
+ BaseCmp::visit (type);
+ return;
+ }
+ }
}
ok = true;
diff --git a/gcc/rust/typecheck/rust-tyty-coercion.h b/gcc/rust/typecheck/rust-tyty-coercion.h
index fc34ac8..6525da3 100644
--- a/gcc/rust/typecheck/rust-tyty-coercion.h
+++ b/gcc/rust/typecheck/rust-tyty-coercion.h
@@ -1000,29 +1000,47 @@ public:
void visit (ADTType &type) override
{
+ if (base->get_adt_kind () != type.get_adt_kind ())
+ {
+ BaseCoercionRules::visit (type);
+ return;
+ }
+
if (base->get_identifier ().compare (type.get_identifier ()) != 0)
{
BaseCoercionRules::visit (type);
return;
}
- if (base->num_fields () != type.num_fields ())
+ if (base->number_of_variants () != type.number_of_variants ())
{
BaseCoercionRules::visit (type);
return;
}
- for (size_t i = 0; i < type.num_fields (); ++i)
+ for (size_t i = 0; i < type.number_of_variants (); ++i)
{
- TyTy::StructFieldType *base_field = base->get_field (i);
- TyTy::StructFieldType *other_field = type.get_field (i);
+ TyTy::VariantDef *a = base->get_variants ().at (i);
+ TyTy::VariantDef *b = type.get_variants ().at (i);
- TyTy::BaseType *this_field_ty = base_field->get_field_type ();
- TyTy::BaseType *other_field_ty = other_field->get_field_type ();
+ if (a->num_fields () != b->num_fields ())
+ {
+ BaseCoercionRules::visit (type);
+ return;
+ }
- BaseType *unified_ty = this_field_ty->unify (other_field_ty);
- if (unified_ty->get_kind () == TyTy::TypeKind::ERROR)
- return;
+ for (size_t j = 0; j < a->num_fields (); j++)
+ {
+ TyTy::StructFieldType *base_field = a->get_field_at_index (i);
+ TyTy::StructFieldType *other_field = b->get_field_at_index (i);
+
+ TyTy::BaseType *this_field_ty = base_field->get_field_type ();
+ TyTy::BaseType *other_field_ty = other_field->get_field_type ();
+
+ BaseType *unified_ty = this_field_ty->unify (other_field_ty);
+ if (unified_ty->get_kind () == TyTy::TypeKind::ERROR)
+ return;
+ }
}
resolved = type.clone ();
diff --git a/gcc/rust/typecheck/rust-tyty-rules.h b/gcc/rust/typecheck/rust-tyty-rules.h
index b7b845a..db86de9 100644
--- a/gcc/rust/typecheck/rust-tyty-rules.h
+++ b/gcc/rust/typecheck/rust-tyty-rules.h
@@ -1016,29 +1016,47 @@ public:
void visit (ADTType &type) override
{
+ if (base->get_adt_kind () != type.get_adt_kind ())
+ {
+ BaseRules::visit (type);
+ return;
+ }
+
if (base->get_identifier ().compare (type.get_identifier ()) != 0)
{
BaseRules::visit (type);
return;
}
- if (base->num_fields () != type.num_fields ())
+ if (base->number_of_variants () != type.number_of_variants ())
{
BaseRules::visit (type);
return;
}
- for (size_t i = 0; i < type.num_fields (); ++i)
+ for (size_t i = 0; i < type.number_of_variants (); ++i)
{
- TyTy::StructFieldType *base_field = base->get_field (i);
- TyTy::StructFieldType *other_field = type.get_field (i);
+ TyTy::VariantDef *a = base->get_variants ().at (i);
+ TyTy::VariantDef *b = type.get_variants ().at (i);
- TyTy::BaseType *this_field_ty = base_field->get_field_type ();
- TyTy::BaseType *other_field_ty = other_field->get_field_type ();
+ if (a->num_fields () != b->num_fields ())
+ {
+ BaseRules::visit (type);
+ return;
+ }
- BaseType *unified_ty = this_field_ty->unify (other_field_ty);
- if (unified_ty->get_kind () == TyTy::TypeKind::ERROR)
- return;
+ for (size_t j = 0; j < a->num_fields (); j++)
+ {
+ TyTy::StructFieldType *base_field = a->get_field_at_index (i);
+ TyTy::StructFieldType *other_field = b->get_field_at_index (i);
+
+ TyTy::BaseType *this_field_ty = base_field->get_field_type ();
+ TyTy::BaseType *other_field_ty = other_field->get_field_type ();
+
+ BaseType *unified_ty = this_field_ty->unify (other_field_ty);
+ if (unified_ty->get_kind () == TyTy::TypeKind::ERROR)
+ return;
+ }
}
resolved = type.clone ();
diff --git a/gcc/rust/typecheck/rust-tyty.cc b/gcc/rust/typecheck/rust-tyty.cc
index 91d3b5c..16cabc8 100644
--- a/gcc/rust/typecheck/rust-tyty.cc
+++ b/gcc/rust/typecheck/rust-tyty.cc
@@ -590,35 +590,16 @@ ADTType::accept_vis (TyConstVisitor &vis) const
std::string
ADTType::as_string () const
{
- if (num_fields () == 0)
- return identifier;
-
- std::string fields_buffer;
- for (size_t i = 0; i < num_fields (); ++i)
+ std::string variants_buffer;
+ for (size_t i = 0; i < number_of_variants (); ++i)
{
- fields_buffer += get_field (i)->as_string ();
- if ((i + 1) < num_fields ())
- fields_buffer += ", ";
+ TyTy::VariantDef *variant = variants.at (i);
+ variants_buffer += variant->as_string ();
+ if ((i + 1) < number_of_variants ())
+ variants_buffer += ", ";
}
- return identifier + subst_as_string () + "{" + fields_buffer + "}";
-}
-
-const StructFieldType *
-ADTType::get_field (size_t index) const
-{
- return fields.at (index);
-}
-
-const BaseType *
-ADTType::get_field_type (size_t index) const
-{
- const StructFieldType *ref = get_field (index);
- auto context = Resolver::TypeCheckContext::get ();
- BaseType *lookup = nullptr;
- bool ok = context->lookup_type (ref->get_field_type ()->get_ref (), &lookup);
- rust_assert (ok);
- return lookup;
+ return identifier + subst_as_string () + "{" + variants_buffer + "}";
}
BaseType *
@@ -657,7 +638,10 @@ ADTType::is_equal (const BaseType &other) const
return false;
auto other2 = static_cast<const ADTType &> (other);
- if (num_fields () != other2.num_fields ())
+ if (get_adt_kind () != other2.get_adt_kind ())
+ return false;
+
+ if (number_of_variants () != other2.number_of_variants ())
return false;
if (has_subsititions_defined () != other2.has_subsititions_defined ())
@@ -683,9 +667,12 @@ ADTType::is_equal (const BaseType &other) const
}
else
{
- for (size_t i = 0; i < num_fields (); i++)
+ for (size_t i = 0; i < number_of_variants (); i++)
{
- if (!get_field (i)->is_equal (*other2.get_field (i)))
+ const TyTy::VariantDef *a = get_variants ().at (i);
+ const TyTy::VariantDef *b = other2.get_variants ().at (i);
+
+ if (!a->is_equal (*b))
return false;
}
}
@@ -696,15 +683,66 @@ ADTType::is_equal (const BaseType &other) const
BaseType *
ADTType::clone () const
{
- std::vector<StructFieldType *> cloned_fields;
- for (auto &f : fields)
- cloned_fields.push_back ((StructFieldType *) f->clone ());
+ std::vector<VariantDef *> cloned_variants;
+ for (auto &variant : variants)
+ cloned_variants.push_back (variant->clone ());
return new ADTType (get_ref (), get_ty_ref (), identifier, get_adt_kind (),
- cloned_fields, clone_substs (), used_arguments,
+ cloned_variants, clone_substs (), used_arguments,
get_combined_refs ());
}
+static bool
+handle_substitions (SubstitutionArgumentMappings &subst_mappings,
+ StructFieldType *field)
+{
+ auto fty = field->get_field_type ();
+ bool is_param_ty = fty->get_kind () == TypeKind::PARAM;
+ if (is_param_ty)
+ {
+ ParamType *p = static_cast<ParamType *> (fty);
+
+ SubstitutionArg arg = SubstitutionArg::error ();
+ bool ok = subst_mappings.get_argument_for_symbol (p, &arg);
+ if (ok)
+ {
+ auto argt = arg.get_tyty ();
+ bool arg_is_param = argt->get_kind () == TyTy::TypeKind::PARAM;
+ bool arg_is_concrete = argt->get_kind () != TyTy::TypeKind::INFER;
+
+ if (arg_is_param || arg_is_concrete)
+ {
+ auto new_field = argt->clone ();
+ new_field->set_ref (fty->get_ref ());
+ field->set_field_type (new_field);
+ }
+ else
+ {
+ field->get_field_type ()->set_ty_ref (argt->get_ref ());
+ }
+ }
+ }
+ else if (fty->has_subsititions_defined () || fty->contains_type_parameters ())
+ {
+ BaseType *concrete
+ = Resolver::SubstMapperInternal::Resolve (fty, subst_mappings);
+
+ if (concrete->get_kind () == TyTy::TypeKind::ERROR)
+ {
+ rust_error_at (subst_mappings.get_locus (),
+ "Failed to resolve field substitution type: %s",
+ fty->as_string ().c_str ());
+ return false;
+ }
+
+ auto new_field = concrete->clone ();
+ new_field->set_ref (fty->get_ref ());
+ field->set_field_type (new_field);
+ }
+
+ return true;
+}
+
ADTType *
ADTType::handle_substitions (SubstitutionArgumentMappings subst_mappings)
{
@@ -721,54 +759,15 @@ ADTType::handle_substitions (SubstitutionArgumentMappings subst_mappings)
sub.fill_param_ty (*arg.get_tyty (), subst_mappings.get_locus ());
}
- adt->iterate_fields ([&] (StructFieldType *field) mutable -> bool {
- auto fty = field->get_field_type ();
- bool is_param_ty = fty->get_kind () == TypeKind::PARAM;
- if (is_param_ty)
- {
- ParamType *p = static_cast<ParamType *> (fty);
-
- SubstitutionArg arg = SubstitutionArg::error ();
- bool ok = subst_mappings.get_argument_for_symbol (p, &arg);
- if (ok)
- {
- auto argt = arg.get_tyty ();
- bool arg_is_param = argt->get_kind () == TyTy::TypeKind::PARAM;
- bool arg_is_concrete = argt->get_kind () != TyTy::TypeKind::INFER;
-
- if (arg_is_param || arg_is_concrete)
- {
- auto new_field = argt->clone ();
- new_field->set_ref (fty->get_ref ());
- field->set_field_type (new_field);
- }
- else
- {
- field->get_field_type ()->set_ty_ref (argt->get_ref ());
- }
- }
- }
- else if (fty->has_subsititions_defined ()
- || fty->contains_type_parameters ())
- {
- BaseType *concrete
- = Resolver::SubstMapperInternal::Resolve (fty, subst_mappings);
-
- if (concrete->get_kind () == TyTy::TypeKind::ERROR)
- {
- rust_error_at (subst_mappings.get_locus (),
- "Failed to resolve field substitution type: %s",
- fty->as_string ().c_str ());
- return false;
- }
-
- auto new_field = concrete->clone ();
- new_field->set_ref (fty->get_ref ());
- field->set_field_type (new_field);
- }
-
- return true;
- });
+ for (auto &variant : adt->get_variants ())
+ {
+ for (auto &field : variant->get_fields ())
+ {
+ bool ok = ::Rust::TyTy::handle_substitions (subst_mappings, field);
+ if (!ok)
+ return adt;
+ }
+ }
return adt;
}
@@ -2538,7 +2537,8 @@ DynamicObjectType::get_object_items () const
void
TypeCheckCallExpr::visit (ADTType &type)
{
- if (!type.is_tuple_struct ())
+ rust_assert (!variant.is_error ());
+ if (variant.get_variant_type () != TyTy::VariantDef::VariantType::TUPLE)
{
rust_error_at (
call.get_locus (),
@@ -2547,18 +2547,18 @@ TypeCheckCallExpr::visit (ADTType &type)
return;
}
- if (call.num_params () != type.num_fields ())
+ if (call.num_params () != variant.num_fields ())
{
rust_error_at (call.get_locus (),
"unexpected number of arguments %lu expected %lu",
- call.num_params (), type.num_fields ());
+ call.num_params (), variant.num_fields ());
return;
}
size_t i = 0;
for (auto &argument : call.get_arguments ())
{
- StructFieldType *field = type.get_field (i);
+ StructFieldType *field = variant.get_field_at_index (i);
BaseType *field_tyty = field->get_field_type ();
BaseType *arg = Resolver::TypeCheckExpr::Resolve (argument.get (), false);
diff --git a/gcc/rust/typecheck/rust-tyty.h b/gcc/rust/typecheck/rust-tyty.h
index ef37dc6..5ffd95c 100644
--- a/gcc/rust/typecheck/rust-tyty.h
+++ b/gcc/rust/typecheck/rust-tyty.h
@@ -1009,6 +1009,150 @@ protected:
SubstitutionArgumentMappings used_arguments;
};
+// https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.VariantDef.html
+class VariantDef
+{
+public:
+ enum VariantType
+ {
+ NUM,
+ TUPLE,
+ STRUCT
+ };
+
+ VariantDef (HirId id, std::string identifier, int discriminant)
+ : id (id), identifier (identifier), discriminant (discriminant)
+ {
+ type = VariantType::NUM;
+ fields = {};
+ }
+
+ VariantDef (HirId id, std::string identifier, VariantType type,
+ std::vector<StructFieldType *> fields)
+ : id (id), identifier (identifier), type (type), fields (fields)
+ {
+ discriminant = 0;
+ rust_assert (type == VariantType::TUPLE || type == VariantType::STRUCT);
+ }
+
+ VariantDef (HirId id, std::string identifier, VariantType type,
+ int discriminant, std::vector<StructFieldType *> fields)
+ : id (id), identifier (identifier), type (type),
+ discriminant (discriminant), fields (fields)
+ {
+ rust_assert ((type == VariantType::NUM && fields.empty ())
+ || (type == VariantType::TUPLE && discriminant == 0)
+ || (type == VariantType::STRUCT && discriminant == 0));
+ }
+
+ static VariantDef &get_error_node ()
+ {
+ static VariantDef node = VariantDef (UNKNOWN_HIRID, "", -1);
+ return node;
+ }
+
+ bool is_error () const { return get_id () == UNKNOWN_HIRID; }
+
+ HirId get_id () const { return id; }
+
+ VariantType get_variant_type () const { return type; }
+
+ std::string get_identifier () const { return identifier; }
+ int get_discriminant () const { return discriminant; }
+
+ size_t num_fields () const { return fields.size (); }
+ StructFieldType *get_field_at_index (size_t index)
+ {
+ // FIXME this is not safe
+ return fields.at (index);
+ }
+
+ std::vector<StructFieldType *> &get_fields ()
+ {
+ rust_assert (type != NUM);
+ return fields;
+ }
+
+ bool lookup_field (const std::string &lookup, StructFieldType **field_lookup,
+ size_t *index) const
+ {
+ size_t i = 0;
+ for (auto &field : fields)
+ {
+ if (field->get_name ().compare (lookup) == 0)
+ {
+ if (index != nullptr)
+ *index = i;
+
+ if (field_lookup != nullptr)
+ *field_lookup = field;
+
+ return true;
+ }
+ i++;
+ }
+ return false;
+ }
+
+ std::string as_string () const
+ {
+ if (type == VariantType::NUM)
+ return identifier + " = " + std::to_string (discriminant);
+
+ std::string buffer;
+ for (size_t i = 0; i < fields.size (); ++i)
+ {
+ buffer += fields.at (i)->as_string ();
+ if ((i + 1) < fields.size ())
+ buffer += ", ";
+ }
+
+ if (type == VariantType::TUPLE)
+ return identifier + " (" + buffer + ")";
+ else
+ return identifier + " {" + buffer + "}";
+ }
+
+ bool is_equal (const VariantDef &other) const
+ {
+ if (type != other.type)
+ return false;
+
+ if (identifier.compare (other.identifier) != 0)
+ return false;
+
+ if (discriminant != other.discriminant)
+ return false;
+
+ if (fields.size () != other.fields.size ())
+ return false;
+
+ for (size_t i = 0; i < fields.size (); i++)
+ {
+ if (!fields.at (i)->is_equal (*other.fields.at (i)))
+ return false;
+ }
+
+ return true;
+ }
+
+ VariantDef *clone () const
+ {
+ std::vector<StructFieldType *> cloned_fields;
+ for (auto &f : fields)
+ cloned_fields.push_back ((StructFieldType *) f->clone ());
+
+ return new VariantDef (id, identifier, type, discriminant, cloned_fields);
+ }
+
+private:
+ HirId id;
+ std::string identifier;
+ VariantType type;
+ int discriminant; /* Either discriminant or fields are valid. */
+ std::vector<StructFieldType *> fields;
+};
+
class ADTType : public BaseType, public SubstitutionRef
{
public:
@@ -1017,36 +1161,48 @@ public:
STRUCT_STRUCT,
TUPLE_STRUCT,
UNION,
- // ENUM ?
+ ENUM
};
ADTType (HirId ref, std::string identifier, ADTKind adt_kind,
- std::vector<StructFieldType *> fields,
+ std::vector<VariantDef *> variants,
std::vector<SubstitutionParamMapping> subst_refs,
SubstitutionArgumentMappings generic_arguments
= SubstitutionArgumentMappings::error (),
std::set<HirId> refs = std::set<HirId> ())
: BaseType (ref, ref, TypeKind::ADT, refs),
SubstitutionRef (std::move (subst_refs), std::move (generic_arguments)),
- identifier (identifier), fields (fields), adt_kind (adt_kind)
+ identifier (identifier), variants (variants), adt_kind (adt_kind)
{}
ADTType (HirId ref, HirId ty_ref, std::string identifier, ADTKind adt_kind,
- std::vector<StructFieldType *> fields,
+ std::vector<VariantDef *> variants,
std::vector<SubstitutionParamMapping> subst_refs,
SubstitutionArgumentMappings generic_arguments
= SubstitutionArgumentMappings::error (),
std::set<HirId> refs = std::set<HirId> ())
: BaseType (ref, ty_ref, TypeKind::ADT, refs),
SubstitutionRef (std::move (subst_refs), std::move (generic_arguments)),
- identifier (identifier), fields (fields), adt_kind (adt_kind)
+ identifier (identifier), variants (variants), adt_kind (adt_kind)
{}
ADTKind get_adt_kind () const { return adt_kind; }
+
+ bool is_struct_struct () const { return adt_kind == STRUCT_STRUCT; }
bool is_tuple_struct () const { return adt_kind == TUPLE_STRUCT; }
bool is_union () const { return adt_kind == UNION; }
+ bool is_enum () const { return adt_kind == ENUM; }
- bool is_unit () const override { return this->fields.empty (); }
+ bool is_unit () const override
+ {
+ if (number_of_variants () == 0)
+ return true;
+
+ if (number_of_variants () == 1)
+ return variants.at (0)->num_fields () == 0;
+
+ return false;
+ }
void accept_vis (TyVisitor &vis) override;
void accept_vis (TyConstVisitor &vis) const override;
@@ -1061,8 +1217,6 @@ public:
bool is_equal (const BaseType &other) const override;
- size_t num_fields () const { return fields.size (); }
-
std::string get_identifier () const { return identifier; }
std::string get_name () const override final
@@ -1070,60 +1224,50 @@ public:
return identifier + subst_as_string ();
}
- BaseType *get_field_type (size_t index);
-
- const BaseType *get_field_type (size_t index) const;
+ BaseType *clone () const final override;
- const StructFieldType *get_field (size_t index) const;
+ bool needs_generic_substitutions () const override final
+ {
+ return needs_substitution ();
+ }
- StructFieldType *get_field (size_t index) { return fields.at (index); }
+ bool supports_substitutions () const override final { return true; }
- const StructFieldType *get_imm_field (size_t index) const
+ bool has_subsititions_defined () const override final
{
- return fields.at (index);
+ return has_substitutions ();
}
- StructFieldType *get_field (const std::string &lookup,
- size_t *index = nullptr) const
+ size_t number_of_variants () const { return variants.size (); }
+
+ std::vector<VariantDef *> &get_variants () { return variants; }
+ const std::vector<VariantDef *> &get_variants () const { return variants; }
+
+ bool lookup_variant (const std::string &lookup,
+ VariantDef **found_variant) const
{
- size_t i = 0;
- for (auto &field : fields)
+ for (auto &variant : variants)
{
- if (field->get_name ().compare (lookup) == 0)
+ if (variant->get_identifier ().compare (lookup) == 0)
{
- if (index != nullptr)
- *index = i;
- return field;
+ *found_variant = variant;
+ return true;
}
- i++;
}
- return nullptr;
+ return false;
}
- BaseType *clone () const final override;
-
- std::vector<StructFieldType *> &get_fields () { return fields; }
- const std::vector<StructFieldType *> &get_fields () const { return fields; }
-
- void iterate_fields (std::function<bool (StructFieldType *)> cb)
+ bool lookup_variant_by_id (HirId id, VariantDef **found_variant) const
{
- for (auto &f : fields)
+ for (auto &variant : variants)
{
- if (!cb (f))
- return;
+ if (variant->get_id () == id)
+ {
+ *found_variant = variant;
+ return true;
+ }
}
- }
-
- bool needs_generic_substitutions () const override final
- {
- return needs_substitution ();
- }
-
- bool supports_substitutions () const override final { return true; }
-
- bool has_subsititions_defined () const override final
- {
- return has_substitutions ();
+ return false;
}
ADTType *
@@ -1131,7 +1275,7 @@ public:
private:
std::string identifier;
- std::vector<StructFieldType *> fields;
+ std::vector<VariantDef *> variants;
ADTType::ADTKind adt_kind;
};
diff --git a/gcc/testsuite/rust/compile/func2.rs b/gcc/testsuite/rust/compile/func2.rs
index 219bbfe..0b8d999 100644
--- a/gcc/testsuite/rust/compile/func2.rs
+++ b/gcc/testsuite/rust/compile/func2.rs
@@ -4,6 +4,4 @@ fn test(a: i32, b: i32) -> i32 {
fn main() {
let a = test(1); // { dg-error "unexpected number of arguments 1 expected 2" }
- // { dg-error "failed to lookup type to CallExpr" "" { target *-*-* } .-1 }
- // { dg-error "failed to type resolve expression" "" { target *-*-* } .-2 }
}
diff --git a/gcc/testsuite/rust/compile/func3.rs b/gcc/testsuite/rust/compile/func3.rs
index 3ab374a..2a32947 100644
--- a/gcc/testsuite/rust/compile/func3.rs
+++ b/gcc/testsuite/rust/compile/func3.rs
@@ -6,6 +6,4 @@ fn main() {
let a = test(1, true);
// { dg-error "expected .i32. got .bool." "" { target *-*-* } .-1 }
// { dg-error "Type Resolution failure on parameter" "" { 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/compile/tuple_struct1.rs b/gcc/testsuite/rust/compile/tuple_struct1.rs
index c382909..2f4cb4a 100644
--- a/gcc/testsuite/rust/compile/tuple_struct1.rs
+++ b/gcc/testsuite/rust/compile/tuple_struct1.rs
@@ -5,6 +5,4 @@ struct Foo {
fn main() {
let a = Foo(1, 2); // { dg-error "expected function, tuple struct or tuple variant, found struct 'Foo'" }
- // { dg-error "failed to lookup type to CallExpr" "" { target *-*-* } .-1 }
- // { dg-error "failed to type resolve expression" "" { target *-*-* } .-2 }
}
diff --git a/gcc/testsuite/rust/compile/tuple_struct2.rs b/gcc/testsuite/rust/compile/tuple_struct2.rs
index dba0511..1fc1896 100644
--- a/gcc/testsuite/rust/compile/tuple_struct2.rs
+++ b/gcc/testsuite/rust/compile/tuple_struct2.rs
@@ -2,6 +2,4 @@ struct Bar(i32, i32, bool);
fn main() {
let a = Bar(1, 2); // { dg-error "unexpected number of arguments 2 expected 3" }
- // { dg-error "failed to lookup type to CallExpr" "" { target *-*-* } .-1 }
- // { dg-error "failed to type resolve expression" "" { target *-*-* } .-2 }
}
diff --git a/gcc/testsuite/rust/compile/tuple_struct3.rs b/gcc/testsuite/rust/compile/tuple_struct3.rs
index a70306d..4af66b8 100644
--- a/gcc/testsuite/rust/compile/tuple_struct3.rs
+++ b/gcc/testsuite/rust/compile/tuple_struct3.rs
@@ -3,6 +3,4 @@ struct Foo(i32, i32, bool);
fn main() {
let c = Foo(1, 2f32, true);
// { dg-error "expected .i32. got .f32." "" { target *-*-* } .-1 }
- // { dg-error "failed to lookup type to CallExpr" "" { target *-*-* } .-2 }
- // { dg-error "failed to type resolve expression" "" { target *-*-* } .-3 }
}