diff options
28 files changed, 2666 insertions, 2242 deletions
diff --git a/gcc/rust/Make-lang.in b/gcc/rust/Make-lang.in index 886bafb..23dad26 100644 --- a/gcc/rust/Make-lang.in +++ b/gcc/rust/Make-lang.in @@ -117,6 +117,9 @@ GRS_OBJS = \ rust/rust-hir-type-check-struct.o \ rust/rust-hir-type-check-pattern.o \ rust/rust-hir-type-check-expr.o \ + rust/rust-hir-type-check-stmt.o \ + rust/rust-hir-type-check-enumitem.o \ + rust/rust-hir-type-check-implitem.o \ rust/rust-hir-dot-operator.o \ rust/rust-coercion.o \ rust/rust-hir-type-check-base.o \ diff --git a/gcc/rust/hir/tree/rust-hir-expr.h b/gcc/rust/hir/tree/rust-hir-expr.h index 7cb86a6..8327852 100644 --- a/gcc/rust/hir/tree/rust-hir-expr.h +++ b/gcc/rust/hir/tree/rust-hir-expr.h @@ -1409,6 +1409,13 @@ public: class StructExprField { public: + enum StructExprFieldKind + { + IDENTIFIER_VALUE, + IDENTIFIER, + INDEX_VALUE, + }; + virtual ~StructExprField () {} // Unique pointer custom clone function @@ -1426,6 +1433,8 @@ public: Location get_locus () { return locus; } + virtual StructExprFieldKind get_kind () const = 0; + protected: // pure virtual clone implementation virtual StructExprField *clone_struct_expr_field_impl () const = 0; @@ -1441,11 +1450,11 @@ protected: // Identifier-only variant of StructExprField HIR node class StructExprFieldIdentifier : public StructExprField { -public: +private: Identifier field_name; // TODO: should this store location data? - +public: StructExprFieldIdentifier (Analysis::NodeMapping mapping, Identifier field_identifier, Location locus) : StructExprField (mapping, locus), @@ -1459,6 +1468,11 @@ public: Identifier get_field_name () const { return field_name; } + StructExprFieldKind get_kind () const override + { + return StructExprFieldKind::IDENTIFIER; + } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -1527,6 +1541,11 @@ public: void accept_vis (HIRFullVisitor &vis) override; void accept_vis (HIRExpressionVisitor &vis) override; + StructExprFieldKind get_kind () const override + { + return StructExprFieldKind::IDENTIFIER_VALUE; + } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -1558,6 +1577,11 @@ public: void accept_vis (HIRFullVisitor &vis) override; void accept_vis (HIRExpressionVisitor &vis) override; + StructExprFieldKind get_kind () const override + { + return StructExprFieldKind::INDEX_VALUE; + } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ diff --git a/gcc/rust/typecheck/rust-hir-inherent-impl-overlap.h b/gcc/rust/typecheck/rust-hir-inherent-impl-overlap.h index 9abf872..2890b54 100644 --- a/gcc/rust/typecheck/rust-hir-inherent-impl-overlap.h +++ b/gcc/rust/typecheck/rust-hir-inherent-impl-overlap.h @@ -25,10 +25,8 @@ namespace Rust { namespace Resolver { -class ImplItemToName : public TypeCheckBase +class ImplItemToName : private TypeCheckBase, private HIR::HIRImplVisitor { - using Rust::Resolver::TypeCheckBase::visit; - public: static bool resolve (HIR::ImplItem *item, std::string &name_result) { @@ -66,8 +64,6 @@ private: class OverlappingImplItemPass : public TypeCheckBase { - using Rust::Resolver::TypeCheckBase::visit; - public: static void go () { diff --git a/gcc/rust/typecheck/rust-hir-path-probe.h b/gcc/rust/typecheck/rust-hir-path-probe.h index 348b9f7..bd4f91e 100644 --- a/gcc/rust/typecheck/rust-hir-path-probe.h +++ b/gcc/rust/typecheck/rust-hir-path-probe.h @@ -125,11 +125,8 @@ struct PathProbeCandidate bool is_error () const { return type == ERROR; } }; -class PathProbeType : public TypeCheckBase +class PathProbeType : public TypeCheckBase, public HIR::HIRImplVisitor { -protected: - using Rust::Resolver::TypeCheckBase::visit; - public: static std::vector<PathProbeCandidate> Probe (const TyTy::BaseType *receiver, @@ -452,10 +449,9 @@ protected: DefId specific_trait_id; }; -class ReportMultipleCandidateError : private TypeCheckBase +class ReportMultipleCandidateError : private TypeCheckBase, + private HIR::HIRImplVisitor { - using Rust::Resolver::TypeCheckBase::visit; - public: static void Report (std::vector<PathProbeCandidate> &candidates, const HIR::PathIdentSegment &query, Location query_locus) diff --git a/gcc/rust/typecheck/rust-hir-trait-resolve.h b/gcc/rust/typecheck/rust-hir-trait-resolve.h index a73b67f..c4aaf42 100644 --- a/gcc/rust/typecheck/rust-hir-trait-resolve.h +++ b/gcc/rust/typecheck/rust-hir-trait-resolve.h @@ -20,19 +20,15 @@ #define RUST_HIR_TRAIT_RESOLVE_H #include "rust-hir-type-check-base.h" -#include "rust-hir-full.h" -#include "rust-tyty-visitor.h" #include "rust-hir-type-check-type.h" #include "rust-hir-trait-ref.h" -#include "rust-expr.h" namespace Rust { namespace Resolver { -class ResolveTraitItemToRef : public TypeCheckBase +class ResolveTraitItemToRef : public TypeCheckBase, + private HIR::HIRTraitItemVisitor { - using Rust::Resolver::TypeCheckBase::visit; - public: static TraitItemReference Resolve (HIR::TraitItem &item, TyTy::BaseType *self, @@ -59,9 +55,9 @@ private: std::vector<TyTy::SubstitutionParamMapping> substitutions; }; -class TraitResolver : public TypeCheckBase +class TraitResolver : public TypeCheckBase, private HIR::HIRFullVisitorBase { - using Rust::Resolver::TypeCheckBase::visit; + using HIR::HIRFullVisitorBase::visit; public: static TraitReference *Resolve (HIR::TypePath &path); diff --git a/gcc/rust/typecheck/rust-hir-type-bounds.h b/gcc/rust/typecheck/rust-hir-type-bounds.h index a0016ee..44400ef 100644 --- a/gcc/rust/typecheck/rust-hir-type-bounds.h +++ b/gcc/rust/typecheck/rust-hir-type-bounds.h @@ -28,8 +28,6 @@ namespace Resolver { class TypeBoundsProbe : public TypeCheckBase { - using Rust::Resolver::TypeCheckBase::visit; - public: static std::vector<std::pair<TraitReference *, HIR::ImplBlock *>> Probe (const TyTy::BaseType *receiver) diff --git a/gcc/rust/typecheck/rust-hir-type-check-base.h b/gcc/rust/typecheck/rust-hir-type-check-base.h index b6f4b63..449ff6a 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-base.h +++ b/gcc/rust/typecheck/rust-hir-type-check-base.h @@ -30,13 +30,9 @@ namespace Rust { namespace Resolver { class TraitReference; - -// base class to allow derivatives to overload as needed -class TypeCheckBase : public HIR::HIRFullVisitorBase +class TypeCheckBase { public: - using Rust::HIR::HIRFullVisitorBase::visit; - virtual ~TypeCheckBase () {} static TyTy::BaseType *coercion_site (HirId id, TyTy::BaseType *lhs, diff --git a/gcc/rust/typecheck/rust-hir-type-check-enumitem.cc b/gcc/rust/typecheck/rust-hir-type-check-enumitem.cc new file mode 100644 index 0000000..e65b201 --- /dev/null +++ b/gcc/rust/typecheck/rust-hir-type-check-enumitem.cc @@ -0,0 +1,213 @@ +// Copyright (C) 2020-2022 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-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 { + +TyTy::VariantDef * +TypeCheckEnumItem::Resolve (HIR::EnumItem *item, int64_t last_discriminant) +{ + TypeCheckEnumItem resolver (last_discriminant); + switch (item->get_enum_item_kind ()) + { + case HIR::EnumItem::EnumItemKind::Named: + resolver.visit (static_cast<HIR::EnumItem &> (*item)); + break; + + case HIR::EnumItem::EnumItemKind::Tuple: + resolver.visit (static_cast<HIR::EnumItemTuple &> (*item)); + break; + + case HIR::EnumItem::EnumItemKind::Struct: + resolver.visit (static_cast<HIR::EnumItemStruct &> (*item)); + break; + + case HIR::EnumItem::EnumItemKind::Discriminant: + resolver.visit (static_cast<HIR::EnumItemDiscriminant &> (*item)); + break; + } + return resolver.variant; +} + +TypeCheckEnumItem::TypeCheckEnumItem (int64_t last_discriminant) + : TypeCheckBase (), variant (nullptr), last_discriminant (last_discriminant) +{} + +void +TypeCheckEnumItem::visit (HIR::EnumItem &item) +{ + if (last_discriminant == INT64_MAX) + rust_error_at (item.get_locus (), "discriminant too big"); + + Analysis::NodeMapping mapping (item.get_mappings ().get_crate_num (), + item.get_mappings ().get_nodeid (), + mappings->get_next_hir_id ( + item.get_mappings ().get_crate_num ()), + item.get_mappings ().get_local_defid ()); + HIR::LiteralExpr *discim_expr + = new HIR::LiteralExpr (mapping, std::to_string (last_discriminant), + HIR::Literal::LitType::INT, + PrimitiveCoreType::CORETYPE_I64, item.get_locus (), + {}); + + TyTy::BaseType *isize = nullptr; + bool ok = context->lookup_builtin ("isize", &isize); + rust_assert (ok); + context->insert_type (mapping, isize); + + const CanonicalPath *canonical_path = nullptr; + ok = mappings->lookup_canonical_path (item.get_mappings ().get_nodeid (), + &canonical_path); + rust_assert (ok); + + RustIdent ident{*canonical_path, item.get_locus ()}; + variant = new TyTy::VariantDef (item.get_mappings ().get_hirid (), + item.get_identifier (), ident, discim_expr); +} + +void +TypeCheckEnumItem::visit (HIR::EnumItemDiscriminant &item) +{ + 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 ()); + if (capacity_type->get_kind () == TyTy::TypeKind::ERROR) + return; + + TyTy::ISizeType *expected_ty + = new TyTy::ISizeType (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; + + const CanonicalPath *canonical_path = nullptr; + bool ok = mappings->lookup_canonical_path (item.get_mappings ().get_nodeid (), + &canonical_path); + rust_assert (ok); + + RustIdent ident{*canonical_path, item.get_locus ()}; + variant = new TyTy::VariantDef (item.get_mappings ().get_hirid (), + item.get_identifier (), ident, + item.get_discriminant_expression ().get ()); +} + +void +TypeCheckEnumItem::visit (HIR::EnumItemTuple &item) +{ + 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++; + } + + Analysis::NodeMapping mapping (item.get_mappings ().get_crate_num (), + item.get_mappings ().get_nodeid (), + mappings->get_next_hir_id ( + item.get_mappings ().get_crate_num ()), + item.get_mappings ().get_local_defid ()); + HIR::LiteralExpr *discim_expr + = new HIR::LiteralExpr (mapping, std::to_string (last_discriminant), + HIR::Literal::LitType::INT, + PrimitiveCoreType::CORETYPE_I64, item.get_locus (), + {}); + + TyTy::BaseType *isize = nullptr; + bool ok = context->lookup_builtin ("isize", &isize); + rust_assert (ok); + context->insert_type (mapping, isize); + + const CanonicalPath *canonical_path = nullptr; + ok = mappings->lookup_canonical_path (item.get_mappings ().get_nodeid (), + &canonical_path); + rust_assert (ok); + + RustIdent ident{*canonical_path, item.get_locus ()}; + variant = new TyTy::VariantDef (item.get_mappings ().get_hirid (), + item.get_identifier (), ident, + TyTy::VariantDef::VariantType::TUPLE, + discim_expr, fields); +} + +void +TypeCheckEnumItem::visit (HIR::EnumItemStruct &item) +{ + 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 ()); + } + + Analysis::NodeMapping mapping (item.get_mappings ().get_crate_num (), + item.get_mappings ().get_nodeid (), + mappings->get_next_hir_id ( + item.get_mappings ().get_crate_num ()), + item.get_mappings ().get_local_defid ()); + HIR::LiteralExpr *discrim_expr + = new HIR::LiteralExpr (mapping, std::to_string (last_discriminant), + HIR::Literal::LitType::INT, + PrimitiveCoreType::CORETYPE_I64, item.get_locus (), + {}); + + TyTy::BaseType *isize = nullptr; + bool ok = context->lookup_builtin ("isize", &isize); + rust_assert (ok); + context->insert_type (mapping, isize); + + const CanonicalPath *canonical_path = nullptr; + ok = mappings->lookup_canonical_path (item.get_mappings ().get_nodeid (), + &canonical_path); + rust_assert (ok); + + RustIdent ident{*canonical_path, item.get_locus ()}; + variant = new TyTy::VariantDef (item.get_mappings ().get_hirid (), + item.get_identifier (), ident, + TyTy::VariantDef::VariantType::STRUCT, + discrim_expr, fields); +} + +} // namespace Resolver +} // namespace Rust diff --git a/gcc/rust/typecheck/rust-hir-type-check-enumitem.h b/gcc/rust/typecheck/rust-hir-type-check-enumitem.h index bc91f45..c771ea3 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-enumitem.h +++ b/gcc/rust/typecheck/rust-hir-type-check-enumitem.h @@ -21,187 +21,24 @@ #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"); - - Analysis::NodeMapping mapping (item.get_mappings ().get_crate_num (), - item.get_mappings ().get_nodeid (), - mappings->get_next_hir_id ( - item.get_mappings ().get_crate_num ()), - item.get_mappings ().get_local_defid ()); - HIR::LiteralExpr *discim_expr - = new HIR::LiteralExpr (mapping, std::to_string (last_discriminant), - HIR::Literal::LitType::INT, - PrimitiveCoreType::CORETYPE_I64, - item.get_locus (), {}); - - TyTy::BaseType *isize = nullptr; - bool ok = context->lookup_builtin ("isize", &isize); - rust_assert (ok); - context->insert_type (mapping, isize); - - const CanonicalPath *canonical_path = nullptr; - ok = mappings->lookup_canonical_path (item.get_mappings ().get_nodeid (), - &canonical_path); - rust_assert (ok); - - RustIdent ident{*canonical_path, item.get_locus ()}; - variant = new TyTy::VariantDef (item.get_mappings ().get_hirid (), - item.get_identifier (), ident, discim_expr); - } - - 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 ()); - if (capacity_type->get_kind () == TyTy::TypeKind::ERROR) - return; - - TyTy::ISizeType *expected_ty - = new TyTy::ISizeType (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; - - const CanonicalPath *canonical_path = nullptr; - bool ok - = mappings->lookup_canonical_path (item.get_mappings ().get_nodeid (), - &canonical_path); - rust_assert (ok); - - RustIdent ident{*canonical_path, item.get_locus ()}; - variant = new TyTy::VariantDef (item.get_mappings ().get_hirid (), - item.get_identifier (), ident, - item.get_discriminant_expression ().get ()); - } - - 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++; - } - - Analysis::NodeMapping mapping (item.get_mappings ().get_crate_num (), - item.get_mappings ().get_nodeid (), - mappings->get_next_hir_id ( - item.get_mappings ().get_crate_num ()), - item.get_mappings ().get_local_defid ()); - HIR::LiteralExpr *discim_expr - = new HIR::LiteralExpr (mapping, std::to_string (last_discriminant), - HIR::Literal::LitType::INT, - PrimitiveCoreType::CORETYPE_I64, - item.get_locus (), {}); - - TyTy::BaseType *isize = nullptr; - bool ok = context->lookup_builtin ("isize", &isize); - rust_assert (ok); - context->insert_type (mapping, isize); - - const CanonicalPath *canonical_path = nullptr; - ok = mappings->lookup_canonical_path (item.get_mappings ().get_nodeid (), - &canonical_path); - rust_assert (ok); - - RustIdent ident{*canonical_path, item.get_locus ()}; - variant = new TyTy::VariantDef (item.get_mappings ().get_hirid (), - item.get_identifier (), ident, - TyTy::VariantDef::VariantType::TUPLE, - discim_expr, 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 ()); - } - - Analysis::NodeMapping mapping (item.get_mappings ().get_crate_num (), - item.get_mappings ().get_nodeid (), - mappings->get_next_hir_id ( - item.get_mappings ().get_crate_num ()), - item.get_mappings ().get_local_defid ()); - HIR::LiteralExpr *discrim_expr - = new HIR::LiteralExpr (mapping, std::to_string (last_discriminant), - HIR::Literal::LitType::INT, - PrimitiveCoreType::CORETYPE_I64, - item.get_locus (), {}); - - TyTy::BaseType *isize = nullptr; - bool ok = context->lookup_builtin ("isize", &isize); - rust_assert (ok); - context->insert_type (mapping, isize); - - const CanonicalPath *canonical_path = nullptr; - ok = mappings->lookup_canonical_path (item.get_mappings ().get_nodeid (), - &canonical_path); - rust_assert (ok); + int64_t last_discriminant); - RustIdent ident{*canonical_path, item.get_locus ()}; - variant = new TyTy::VariantDef (item.get_mappings ().get_hirid (), - item.get_identifier (), ident, - TyTy::VariantDef::VariantType::STRUCT, - discrim_expr, fields); - } +protected: + void visit (HIR::EnumItem &item); + void visit (HIR::EnumItemDiscriminant &item); + void visit (HIR::EnumItemTuple &item); + void visit (HIR::EnumItemStruct &item); private: - TypeCheckEnumItem (int64_t last_discriminant) - : TypeCheckBase (), variant (nullptr), last_discriminant (last_discriminant) - {} + TypeCheckEnumItem (int64_t last_discriminant); TyTy::VariantDef *variant; int64_t last_discriminant; diff --git a/gcc/rust/typecheck/rust-hir-type-check-expr.cc b/gcc/rust/typecheck/rust-hir-type-check-expr.cc index ff1165d..03999ba 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-expr.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-expr.cc @@ -16,11 +16,555 @@ // along with GCC; see the file COPYING3. If not see // <http://www.gnu.org/licenses/>. +#include "rust-hir-full.h" +#include "rust-tyty-call.h" +#include "rust-hir-type-check-struct-field.h" +#include "rust-hir-path-probe.h" +#include "rust-substitution-mapper.h" +#include "rust-hir-trait-resolve.h" +#include "rust-hir-type-bounds.h" +#include "rust-hir-dot-operator.h" +#include "rust-hir-type-check-pattern.h" #include "rust-hir-type-check-expr.h" +#include "rust-hir-type-check-stmt.h" namespace Rust { namespace Resolver { +TypeCheckExpr::TypeCheckExpr () : TypeCheckBase (), infered (nullptr) {} + +// Perform type checking on expr. Also runs type unification algorithm. +// Returns the unified type of expr +TyTy::BaseType * +TypeCheckExpr::Resolve (HIR::Expr *expr) +{ + TypeCheckExpr resolver; + expr->accept_vis (resolver); + + if (resolver.infered == nullptr) + { + // FIXME + // this is an internal error message for debugging and should be removed + // at some point + rust_error_at (expr->get_locus (), "failed to type resolve expression"); + return new TyTy::ErrorType (expr->get_mappings ().get_hirid ()); + } + + auto ref = expr->get_mappings ().get_hirid (); + resolver.infered->set_ref (ref); + resolver.context->insert_type (expr->get_mappings (), resolver.infered); + + return resolver.infered; +} + +void +TypeCheckExpr::visit (HIR::TupleIndexExpr &expr) +{ + auto resolved = TypeCheckExpr::Resolve (expr.get_tuple_expr ().get ()); + if (resolved->get_kind () == TyTy::TypeKind::ERROR) + { + rust_error_at (expr.get_tuple_expr ()->get_locus (), + "failed to resolve TupleIndexExpr receiver"); + return; + } + + // FIXME does this require autoderef here? + if (resolved->get_kind () == TyTy::TypeKind::REF) + { + TyTy::ReferenceType *r = static_cast<TyTy::ReferenceType *> (resolved); + resolved = r->get_base (); + } + + bool is_valid_type = resolved->get_kind () == TyTy::TypeKind::ADT + || resolved->get_kind () == TyTy::TypeKind::TUPLE; + if (!is_valid_type) + { + rust_error_at (expr.get_tuple_expr ()->get_locus (), + "Expected Tuple or ADT got: %s", + resolved->as_string ().c_str ()); + return; + } + + if (resolved->get_kind () == TyTy::TypeKind::TUPLE) + { + TyTy::TupleType *tuple = static_cast<TyTy::TupleType *> (resolved); + TupleIndex index = expr.get_tuple_index (); + if ((size_t) index >= tuple->num_fields ()) + { + rust_error_at (expr.get_locus (), "unknown field at index %i", index); + return; + } + + auto field_tyty = tuple->get_field ((size_t) index); + if (field_tyty == nullptr) + { + rust_error_at (expr.get_locus (), + "failed to lookup field type at index %i", index); + return; + } + + infered = field_tyty; + return; + } + + 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 >= variant->num_fields ()) + { + rust_error_at (expr.get_locus (), "unknown field at index %i", index); + return; + } + + auto field_tyty = variant->get_field_at_index ((size_t) index); + if (field_tyty == nullptr) + { + rust_error_at (expr.get_locus (), + "failed to lookup field type at index %i", index); + return; + } + + infered = field_tyty->get_field_type (); +} + +void +TypeCheckExpr::visit (HIR::TupleExpr &expr) +{ + if (expr.is_unit ()) + { + auto unit_node_id = resolver->get_unit_type_node_id (); + if (!context->lookup_builtin (unit_node_id, &infered)) + { + rust_error_at (expr.get_locus (), + "failed to lookup builtin unit type"); + } + return; + } + + std::vector<TyTy::TyVar> fields; + for (auto &elem : expr.get_tuple_elems ()) + { + auto field_ty = TypeCheckExpr::Resolve (elem.get ()); + fields.push_back (TyTy::TyVar (field_ty->get_ref ())); + } + infered = new TyTy::TupleType (expr.get_mappings ().get_hirid (), + expr.get_locus (), fields); +} + +void +TypeCheckExpr::visit (HIR::ReturnExpr &expr) +{ + auto fn_return_tyty = context->peek_return_type (); + rust_assert (fn_return_tyty != nullptr); + + TyTy::BaseType *expr_ty + = expr.has_return_expr () + ? TypeCheckExpr::Resolve (expr.get_expr ()) + : TyTy::TupleType::get_unit_type (expr.get_mappings ().get_hirid ()); + + infered = fn_return_tyty->unify (expr_ty); + fn_return_tyty->append_reference (expr_ty->get_ref ()); + for (auto &ref : infered->get_combined_refs ()) + fn_return_tyty->append_reference (ref); + + infered = new TyTy::NeverType (expr.get_mappings ().get_hirid ()); +} + +void +TypeCheckExpr::visit (HIR::CallExpr &expr) +{ + TyTy::BaseType *function_tyty = TypeCheckExpr::Resolve (expr.get_fnexpr ()); + + bool valid_tyty = function_tyty->get_kind () == TyTy::TypeKind::ADT + || function_tyty->get_kind () == TyTy::TypeKind::FNDEF + || function_tyty->get_kind () == TyTy::TypeKind::FNPTR; + if (!valid_tyty) + { + rust_error_at (expr.get_locus (), + "Failed to resolve expression of function call"); + return; + } + + 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); +} + +void +TypeCheckExpr::visit (HIR::AssignmentExpr &expr) +{ + infered = TyTy::TupleType::get_unit_type (expr.get_mappings ().get_hirid ()); + + auto lhs = TypeCheckExpr::Resolve (expr.get_lhs ()); + auto rhs = TypeCheckExpr::Resolve (expr.get_rhs ()); + + coercion_site (expr.get_mappings ().get_hirid (), lhs, rhs, + expr.get_locus ()); +} + +void +TypeCheckExpr::visit (HIR::CompoundAssignmentExpr &expr) +{ + infered = TyTy::TupleType::get_unit_type (expr.get_mappings ().get_hirid ()); + + auto lhs = TypeCheckExpr::Resolve (expr.get_left_expr ().get ()); + auto rhs = TypeCheckExpr::Resolve (expr.get_right_expr ().get ()); + + // we dont care about the result of the unify from a compound assignment + // since this is a unit-type expr + auto result = lhs->unify (rhs); + if (result->get_kind () == TyTy::TypeKind::ERROR) + return; + + auto lang_item_type + = Analysis::RustLangItem::CompoundAssignmentOperatorToLangItem ( + expr.get_expr_type ()); + bool operator_overloaded + = resolve_operator_overload (lang_item_type, expr, lhs, rhs); + if (operator_overloaded) + return; + + bool valid_lhs = validate_arithmetic_type (lhs, expr.get_expr_type ()); + bool valid_rhs = validate_arithmetic_type (rhs, expr.get_expr_type ()); + bool valid = valid_lhs && valid_rhs; + if (!valid) + { + rust_error_at (expr.get_locus (), + "cannot apply this operator to types %s and %s", + lhs->as_string ().c_str (), rhs->as_string ().c_str ()); + return; + } +} + +void +TypeCheckExpr::visit (HIR::IdentifierExpr &expr) +{ + NodeId ast_node_id = expr.get_mappings ().get_nodeid (); + + // then lookup the reference_node_id + NodeId ref_node_id = UNKNOWN_NODEID; + if (!resolver->lookup_resolved_name (ast_node_id, &ref_node_id)) + { + resolver->lookup_resolved_type (ast_node_id, &ref_node_id); + } + + if (ref_node_id == UNKNOWN_NODEID) + { + // FIXME this needs to go away and just return error node + rust_error_at (expr.get_locus (), "unresolved node: %s", + expr.as_string ().c_str ()); + return; + } + + // node back to HIR + HirId ref; + if (!mappings->lookup_node_to_hir (ref_node_id, &ref)) + { + // FIXME + // this is an internal error + rust_error_at (expr.get_locus (), "123 reverse lookup failure"); + return; + } + + // the base reference for this name _must_ have a type set + TyTy::BaseType *lookup; + if (!context->lookup_type (ref, &lookup)) + { + // FIXME + // this is an internal error + rust_error_at (mappings->lookup_location (ref), + "Failed to resolve IdentifierExpr type: %s", + expr.as_string ().c_str ()); + return; + } + + infered = lookup->clone (); + + // Generic unit structs look like an identifier but they actually need be + // handled as a path-in-expression so this gives us a chance to infer the + // generic parameters. + // see https://github.com/Rust-GCC/gccrs/issues/1447 + bool is_unit_struct + = infered->get_kind () == TyTy::TypeKind::ADT && infered->is_unit (); + if (is_unit_struct && infered->needs_generic_substitutions ()) + { + infered = SubstMapper::InferSubst (infered, expr.get_locus ()); + } +} + +void +TypeCheckExpr::visit (HIR::LiteralExpr &expr) +{ + infered = resolve_literal (expr.get_mappings (), expr.get_literal (), + expr.get_locus ()); +} + +void +TypeCheckExpr::visit (HIR::ArithmeticOrLogicalExpr &expr) +{ + auto lhs = TypeCheckExpr::Resolve (expr.get_lhs ()); + auto rhs = TypeCheckExpr::Resolve (expr.get_rhs ()); + + auto lang_item_type + = Analysis::RustLangItem::OperatorToLangItem (expr.get_expr_type ()); + bool operator_overloaded + = resolve_operator_overload (lang_item_type, expr, lhs, rhs); + if (operator_overloaded) + return; + + bool valid_lhs = validate_arithmetic_type (lhs, expr.get_expr_type ()); + bool valid_rhs = validate_arithmetic_type (rhs, expr.get_expr_type ()); + bool valid = valid_lhs && valid_rhs; + if (!valid) + { + rust_error_at (expr.get_locus (), + "cannot apply this operator to types %s and %s", + lhs->as_string ().c_str (), rhs->as_string ().c_str ()); + return; + } + + switch (expr.get_expr_type ()) + { + case ArithmeticOrLogicalOperator::LEFT_SHIFT: + case ArithmeticOrLogicalOperator::RIGHT_SHIFT: + infered = rhs->cast (lhs); + break; + + default: + infered = lhs->unify (rhs); + break; + } +} + +void +TypeCheckExpr::visit (HIR::ComparisonExpr &expr) +{ + auto lhs = TypeCheckExpr::Resolve (expr.get_lhs ()); + auto rhs = TypeCheckExpr::Resolve (expr.get_rhs ()); + + auto result = lhs->unify (rhs); + if (result == nullptr || result->get_kind () == TyTy::TypeKind::ERROR) + return; + + bool ok = context->lookup_builtin ("bool", &infered); + rust_assert (ok); +} + +void +TypeCheckExpr::visit (HIR::LazyBooleanExpr &expr) +{ + auto lhs = TypeCheckExpr::Resolve (expr.get_lhs ()); + auto rhs = TypeCheckExpr::Resolve (expr.get_rhs ()); + + // we expect the lhs and rhs must be bools at this point + TyTy::BoolType elhs (expr.get_mappings ().get_hirid ()); + lhs = elhs.unify (lhs); + if (lhs->get_kind () == TyTy::TypeKind::ERROR) + return; + + TyTy::BoolType rlhs (expr.get_mappings ().get_hirid ()); + rhs = elhs.unify (rhs); + if (lhs->get_kind () == TyTy::TypeKind::ERROR) + return; + + infered = lhs->unify (rhs); +} + +void +TypeCheckExpr::visit (HIR::NegationExpr &expr) +{ + auto negated_expr_ty = TypeCheckExpr::Resolve (expr.get_expr ().get ()); + + // check for operator overload + auto lang_item_type = Analysis::RustLangItem::NegationOperatorToLangItem ( + expr.get_expr_type ()); + bool operator_overloaded + = resolve_operator_overload (lang_item_type, expr, negated_expr_ty, + nullptr); + if (operator_overloaded) + return; + + // https://doc.rust-lang.org/reference/expressions/operator-expr.html#negation-operators + switch (expr.get_expr_type ()) + { + case NegationOperator::NEGATE: { + bool valid + = (negated_expr_ty->get_kind () == TyTy::TypeKind::INT) + || (negated_expr_ty->get_kind () == TyTy::TypeKind::UINT) + || (negated_expr_ty->get_kind () == TyTy::TypeKind::FLOAT) + || (negated_expr_ty->get_kind () == TyTy::TypeKind::ISIZE) + || (negated_expr_ty->get_kind () == TyTy::TypeKind::USIZE) + || (negated_expr_ty->get_kind () == TyTy::TypeKind::INFER + && (((TyTy::InferType *) negated_expr_ty)->get_infer_kind () + == TyTy::InferType::INTEGRAL)) + || (negated_expr_ty->get_kind () == TyTy::TypeKind::INFER + && (((TyTy::InferType *) negated_expr_ty)->get_infer_kind () + == TyTy::InferType::FLOAT)); + if (!valid) + { + rust_error_at (expr.get_locus (), "cannot apply unary - to %s", + negated_expr_ty->as_string ().c_str ()); + return; + } + } + break; + + case NegationOperator::NOT: { + bool valid + = (negated_expr_ty->get_kind () == TyTy::TypeKind::BOOL) + || (negated_expr_ty->get_kind () == TyTy::TypeKind::INT) + || (negated_expr_ty->get_kind () == TyTy::TypeKind::UINT) + || (negated_expr_ty->get_kind () == TyTy::TypeKind::INFER + && (((TyTy::InferType *) negated_expr_ty)->get_infer_kind () + == TyTy::InferType::INTEGRAL)); + if (!valid) + { + rust_error_at (expr.get_locus (), "cannot apply unary %<!%> to %s", + negated_expr_ty->as_string ().c_str ()); + return; + } + } + break; + } + + infered = negated_expr_ty->clone (); + infered->append_reference (negated_expr_ty->get_ref ()); +} + +void +TypeCheckExpr::visit (HIR::IfExpr &expr) +{ + TypeCheckExpr::Resolve (expr.get_if_condition ()); + TypeCheckExpr::Resolve (expr.get_if_block ()); + + infered = TyTy::TupleType::get_unit_type (expr.get_mappings ().get_hirid ()); +} + +void +TypeCheckExpr::visit (HIR::IfExprConseqElse &expr) +{ + TypeCheckExpr::Resolve (expr.get_if_condition ()); + auto if_blk_resolved = TypeCheckExpr::Resolve (expr.get_if_block ()); + auto else_blk_resolved = TypeCheckExpr::Resolve (expr.get_else_block ()); + + if (if_blk_resolved->get_kind () == TyTy::NEVER) + infered = else_blk_resolved; + else if (else_blk_resolved->get_kind () == TyTy::NEVER) + infered = if_blk_resolved; + else + infered = if_blk_resolved->unify (else_blk_resolved); +} + +void +TypeCheckExpr::visit (HIR::IfExprConseqIf &expr) +{ + TypeCheckExpr::Resolve (expr.get_if_condition ()); + auto if_blk_resolved = TypeCheckExpr::Resolve (expr.get_if_block ()); + auto else_blk_resolved = TypeCheckExpr::Resolve (expr.get_conseq_if_expr ()); + + if (if_blk_resolved->get_kind () == TyTy::NEVER) + infered = else_blk_resolved; + else if (else_blk_resolved->get_kind () == TyTy::NEVER) + infered = if_blk_resolved; + else + infered = if_blk_resolved->unify (else_blk_resolved); +} + +void +TypeCheckExpr::visit (HIR::IfLetExpr &expr) +{ + // this needs to perform a least upper bound coercion on the blocks and then + // unify the scruintee and arms + TyTy::BaseType *scrutinee_tyty + = TypeCheckExpr::Resolve (expr.get_scrutinee_expr ().get ()); + + for (auto &pattern : expr.get_patterns ()) + { + TyTy::BaseType *kase_arm_ty + = TypeCheckPattern::Resolve (pattern.get (), scrutinee_tyty); + + TyTy::BaseType *checked_kase = scrutinee_tyty->unify (kase_arm_ty); + if (checked_kase->get_kind () == TyTy::TypeKind::ERROR) + return; + } + + TypeCheckExpr::Resolve (expr.get_if_block ()); + + infered = TyTy::TupleType::get_unit_type (expr.get_mappings ().get_hirid ()); +} + +void +TypeCheckExpr::visit (HIR::UnsafeBlockExpr &expr) +{ + infered = TypeCheckExpr::Resolve (expr.get_block_expr ().get ()); +} + +void +TypeCheckExpr::visit (HIR::BlockExpr &expr) +{ + for (auto &s : expr.get_statements ()) + { + if (!s->is_item ()) + continue; + + TypeCheckStmt::Resolve (s.get ()); + } + + for (auto &s : expr.get_statements ()) + { + if (s->is_item ()) + continue; + + auto resolved = TypeCheckStmt::Resolve (s.get ()); + if (resolved == nullptr) + { + rust_error_at (s->get_locus (), "failure to resolve type"); + return; + } + + if (s->is_unit_check_needed () && !resolved->is_unit ()) + { + auto unit + = TyTy::TupleType::get_unit_type (s->get_mappings ().get_hirid ()); + resolved = unit->unify (resolved); + } + } + + if (expr.has_expr ()) + infered = TypeCheckExpr::Resolve (expr.get_final_expr ().get ())->clone (); + else if (expr.is_tail_reachable ()) + infered + = TyTy::TupleType::get_unit_type (expr.get_mappings ().get_hirid ()); + else + infered = new TyTy::NeverType (expr.get_mappings ().get_hirid ()); +} + void TypeCheckExpr::visit (HIR::RangeFromToExpr &expr) { @@ -305,6 +849,146 @@ TypeCheckExpr::visit (HIR::ArrayIndexExpr &expr) } void +TypeCheckExpr::visit (HIR::ArrayExpr &expr) +{ + HIR::ArrayElems &elements = *expr.get_internal_elements (); + + HIR::Expr *capacity_expr = nullptr; + TyTy::BaseType *element_type = nullptr; + switch (elements.get_array_expr_type ()) + { + case HIR::ArrayElems::ArrayExprType::COPIED: { + HIR::ArrayElemsCopied &elems + = static_cast<HIR::ArrayElemsCopied &> (elements); + element_type = TypeCheckExpr::Resolve (elems.get_elem_to_copy ()); + + auto capacity_type + = TypeCheckExpr::Resolve (elems.get_num_copies_expr ()); + + TyTy::BaseType *expected_ty = nullptr; + bool ok = context->lookup_builtin ("usize", &expected_ty); + rust_assert (ok); + context->insert_type (elems.get_num_copies_expr ()->get_mappings (), + expected_ty); + + auto unified = expected_ty->unify (capacity_type); + if (unified->get_kind () == TyTy::TypeKind::ERROR) + return; + + capacity_expr = elems.get_num_copies_expr (); + } + break; + + case HIR::ArrayElems::ArrayExprType::VALUES: { + HIR::ArrayElemsValues &elems + = static_cast<HIR::ArrayElemsValues &> (elements); + + std::vector<TyTy::BaseType *> types; + for (auto &elem : elems.get_values ()) + { + types.push_back (TypeCheckExpr::Resolve (elem.get ())); + } + + element_type + = TyTy::TyVar::get_implicit_infer_var (expr.get_locus ()).get_tyty (); + for (auto &type : types) + { + element_type = element_type->unify (type); + } + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, UNKNOWN_NODEID, + mappings->get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + std::string capacity_str = std::to_string (elems.get_num_elements ()); + capacity_expr = new HIR::LiteralExpr (mapping, capacity_str, + HIR::Literal::LitType::INT, + PrimitiveCoreType::CORETYPE_USIZE, + Location (), {}); + + // mark the type for this implicit node + TyTy::BaseType *expected_ty = nullptr; + bool ok = context->lookup_builtin ("usize", &expected_ty); + rust_assert (ok); + context->insert_type (mapping, expected_ty); + } + break; + } + + infered = new TyTy::ArrayType (expr.get_mappings ().get_hirid (), + expr.get_locus (), *capacity_expr, + TyTy::TyVar (element_type->get_ref ())); +} + +// empty struct +void +TypeCheckExpr::visit (HIR::StructExprStruct &struct_expr) +{ + TyTy::BaseType *struct_path_ty + = TypeCheckExpr::Resolve (&struct_expr.get_struct_name ()); + 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; + } + + infered = struct_path_ty; +} + +void +TypeCheckExpr::visit (HIR::StructExprStructFields &struct_expr) +{ + infered = TypeCheckStructExpr::Resolve (&struct_expr); +} + +void +TypeCheckExpr::visit (HIR::GroupedExpr &expr) +{ + infered = TypeCheckExpr::Resolve (expr.get_expr_in_parens ().get ()); +} + +void +TypeCheckExpr::visit (HIR::FieldAccessExpr &expr) +{ + auto struct_base = TypeCheckExpr::Resolve (expr.get_receiver_expr ().get ()); + + // FIXME does this require autoderef here? + if (struct_base->get_kind () == TyTy::TypeKind::REF) + { + TyTy::ReferenceType *r = static_cast<TyTy::ReferenceType *> (struct_base); + struct_base = r->get_base (); + } + + bool is_valid_type = struct_base->get_kind () == TyTy::TypeKind::ADT; + if (!is_valid_type) + { + rust_error_at (expr.get_locus (), + "expected algebraic data type got: [%s]", + struct_base->as_string ().c_str ()); + return; + } + + TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (struct_base); + 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 (), + adt->as_string ().c_str ()); + return; + } + + infered = lookup->get_field_type (); +} + +void TypeCheckExpr::visit (HIR::MethodCallExpr &expr) { auto receiver_tyty = TypeCheckExpr::Resolve (expr.get_receiver ().get ()); @@ -459,6 +1143,232 @@ TypeCheckExpr::visit (HIR::MethodCallExpr &expr) infered = function_ret_tyty; } +void +TypeCheckExpr::visit (HIR::LoopExpr &expr) +{ + context->push_new_loop_context (expr.get_mappings ().get_hirid (), + expr.get_locus ()); + TyTy::BaseType *block_expr + = TypeCheckExpr::Resolve (expr.get_loop_block ().get ()); + if (!block_expr->is_unit ()) + { + rust_error_at (expr.get_loop_block ()->get_locus (), + "expected %<()%> got %s", + block_expr->as_string ().c_str ()); + return; + } + + TyTy::BaseType *loop_context_type = context->pop_loop_context (); + + bool loop_context_type_infered + = (loop_context_type->get_kind () != TyTy::TypeKind::INFER) + || ((loop_context_type->get_kind () == TyTy::TypeKind::INFER) + && (((TyTy::InferType *) loop_context_type)->get_infer_kind () + != TyTy::InferType::GENERAL)); + + infered + = loop_context_type_infered + ? loop_context_type + : TyTy::TupleType::get_unit_type (expr.get_mappings ().get_hirid ()); +} + +void +TypeCheckExpr::visit (HIR::WhileLoopExpr &expr) +{ + context->push_new_while_loop_context (expr.get_mappings ().get_hirid ()); + + TypeCheckExpr::Resolve (expr.get_predicate_expr ().get ()); + TyTy::BaseType *block_expr + = TypeCheckExpr::Resolve (expr.get_loop_block ().get ()); + + if (!block_expr->is_unit ()) + { + rust_error_at (expr.get_loop_block ()->get_locus (), + "expected %<()%> got %s", + block_expr->as_string ().c_str ()); + return; + } + + context->pop_loop_context (); + infered = TyTy::TupleType::get_unit_type (expr.get_mappings ().get_hirid ()); +} + +void +TypeCheckExpr::visit (HIR::BreakExpr &expr) +{ + if (!context->have_loop_context ()) + { + rust_error_at (expr.get_locus (), "cannot %<break%> outside of a loop"); + return; + } + + if (expr.has_break_expr ()) + { + TyTy::BaseType *break_expr_tyty + = TypeCheckExpr::Resolve (expr.get_expr ().get ()); + + TyTy::BaseType *loop_context = context->peek_loop_context (); + if (loop_context->get_kind () == TyTy::TypeKind::ERROR) + { + rust_error_at (expr.get_locus (), + "can only break with a value inside %<loop%>"); + return; + } + + TyTy::BaseType *unified_ty = loop_context->unify (break_expr_tyty); + context->swap_head_loop_context (unified_ty); + } + + infered = new TyTy::NeverType (expr.get_mappings ().get_hirid ()); +} + +void +TypeCheckExpr::visit (HIR::ContinueExpr &expr) +{ + if (!context->have_loop_context ()) + { + rust_error_at (expr.get_locus (), + "cannot %<continue%> outside of a loop"); + return; + } + + infered = new TyTy::NeverType (expr.get_mappings ().get_hirid ()); +} + +void +TypeCheckExpr::visit (HIR::BorrowExpr &expr) +{ + TyTy::BaseType *resolved_base + = TypeCheckExpr::Resolve (expr.get_expr ().get ()); + + // In Rust this is valid because of DST's + // + // fn test() { + // let a:&str = "TEST 1"; + // let b:&str = &"TEST 2"; + // } + if (resolved_base->get_kind () == TyTy::TypeKind::REF) + { + const TyTy::ReferenceType *ref + = static_cast<const TyTy::ReferenceType *> (resolved_base); + + // this might end up being a more generic is_dyn object check but lets + // double check dyn traits type-layout first + if (ref->is_dyn_str_type ()) + { + infered = resolved_base; + return; + } + } + + if (expr.get_is_double_borrow ()) + { + // FIXME double_reference + gcc_unreachable (); + } + + infered = new TyTy::ReferenceType (expr.get_mappings ().get_hirid (), + TyTy::TyVar (resolved_base->get_ref ()), + expr.get_mut ()); +} + +void +TypeCheckExpr::visit (HIR::DereferenceExpr &expr) +{ + TyTy::BaseType *resolved_base + = TypeCheckExpr::Resolve (expr.get_expr ().get ()); + + auto lang_item_type = Analysis::RustLangItem::ItemType::DEREF; + bool operator_overloaded + = resolve_operator_overload (lang_item_type, expr, resolved_base, nullptr); + if (operator_overloaded) + { + // operator overloaded deref always refurns a reference type lets assert + // this + rust_assert (infered->get_kind () == TyTy::TypeKind::REF); + resolved_base = infered; + } + + bool is_valid_type = resolved_base->get_kind () == TyTy::TypeKind::REF + || resolved_base->get_kind () == TyTy::TypeKind::POINTER; + if (!is_valid_type) + { + rust_error_at (expr.get_locus (), "expected reference type got %s", + resolved_base->as_string ().c_str ()); + return; + } + + if (resolved_base->get_kind () == TyTy::TypeKind::REF) + { + TyTy::ReferenceType *ref_base + = static_cast<TyTy::ReferenceType *> (resolved_base); + infered = ref_base->get_base ()->clone (); + } + else + { + TyTy::PointerType *ref_base + = static_cast<TyTy::PointerType *> (resolved_base); + infered = ref_base->get_base ()->clone (); + } +} + +void +TypeCheckExpr::visit (HIR::TypeCastExpr &expr) +{ + TyTy::BaseType *expr_to_convert + = TypeCheckExpr::Resolve (expr.get_casted_expr ().get ()); + TyTy::BaseType *tyty_to_convert_to + = TypeCheckType::Resolve (expr.get_type_to_convert_to ().get ()); + + infered = expr_to_convert->cast (tyty_to_convert_to); +} + +void +TypeCheckExpr::visit (HIR::MatchExpr &expr) +{ + // this needs to perform a least upper bound coercion on the blocks and then + // unify the scruintee and arms + TyTy::BaseType *scrutinee_tyty + = TypeCheckExpr::Resolve (expr.get_scrutinee_expr ().get ()); + + std::vector<TyTy::BaseType *> kase_block_tys; + for (auto &kase : expr.get_match_cases ()) + { + // lets check the arms + HIR::MatchArm &kase_arm = kase.get_arm (); + for (auto &pattern : kase_arm.get_patterns ()) + { + TyTy::BaseType *kase_arm_ty + = TypeCheckPattern::Resolve (pattern.get (), scrutinee_tyty); + + TyTy::BaseType *checked_kase = scrutinee_tyty->unify (kase_arm_ty); + if (checked_kase->get_kind () == TyTy::TypeKind::ERROR) + return; + } + + // check the kase type + TyTy::BaseType *kase_block_ty + = TypeCheckExpr::Resolve (kase.get_expr ().get ()); + kase_block_tys.push_back (kase_block_ty); + } + + if (kase_block_tys.size () == 0) + { + infered + = TyTy::TupleType::get_unit_type (expr.get_mappings ().get_hirid ()); + return; + } + + infered = kase_block_tys.at (0); + for (size_t i = 1; i < kase_block_tys.size (); i++) + { + TyTy::BaseType *kase_ty = kase_block_tys.at (i); + infered = infered->unify (kase_ty); + if (infered->get_kind () == TyTy::TypeKind::ERROR) + return; + } +} + bool TypeCheckExpr::resolve_operator_overload ( Analysis::RustLangItem::ItemType lang_item_type, HIR::OperatorExprMeta expr, @@ -644,5 +1554,61 @@ TypeCheckExpr::resolve_operator_overload ( return true; } +bool +TypeCheckExpr::validate_arithmetic_type ( + const TyTy::BaseType *tyty, HIR::ArithmeticOrLogicalExpr::ExprType expr_type) +{ + const TyTy::BaseType *type = tyty->destructure (); + + // https://doc.rust-lang.org/reference/expressions/operator-expr.html#arithmetic-and-logical-binary-operators + // this will change later when traits are added + switch (expr_type) + { + case ArithmeticOrLogicalOperator::ADD: + case ArithmeticOrLogicalOperator::SUBTRACT: + case ArithmeticOrLogicalOperator::MULTIPLY: + case ArithmeticOrLogicalOperator::DIVIDE: + case ArithmeticOrLogicalOperator::MODULUS: + return (type->get_kind () == TyTy::TypeKind::INT) + || (type->get_kind () == TyTy::TypeKind::UINT) + || (type->get_kind () == TyTy::TypeKind::FLOAT) + || (type->get_kind () == TyTy::TypeKind::USIZE) + || (type->get_kind () == TyTy::TypeKind::ISIZE) + || (type->get_kind () == TyTy::TypeKind::INFER + && (((const TyTy::InferType *) type)->get_infer_kind () + == TyTy::InferType::INTEGRAL)) + || (type->get_kind () == TyTy::TypeKind::INFER + && (((const TyTy::InferType *) type)->get_infer_kind () + == TyTy::InferType::FLOAT)); + + // integers or bools + case ArithmeticOrLogicalOperator::BITWISE_AND: + case ArithmeticOrLogicalOperator::BITWISE_OR: + case ArithmeticOrLogicalOperator::BITWISE_XOR: + return (type->get_kind () == TyTy::TypeKind::INT) + || (type->get_kind () == TyTy::TypeKind::UINT) + || (type->get_kind () == TyTy::TypeKind::USIZE) + || (type->get_kind () == TyTy::TypeKind::ISIZE) + || (type->get_kind () == TyTy::TypeKind::BOOL) + || (type->get_kind () == TyTy::TypeKind::INFER + && (((const TyTy::InferType *) type)->get_infer_kind () + == TyTy::InferType::INTEGRAL)); + + // integers only + case ArithmeticOrLogicalOperator::LEFT_SHIFT: + case ArithmeticOrLogicalOperator::RIGHT_SHIFT: + return (type->get_kind () == TyTy::TypeKind::INT) + || (type->get_kind () == TyTy::TypeKind::UINT) + || (type->get_kind () == TyTy::TypeKind::USIZE) + || (type->get_kind () == TyTy::TypeKind::ISIZE) + || (type->get_kind () == TyTy::TypeKind::INFER + && (((const TyTy::InferType *) type)->get_infer_kind () + == TyTy::InferType::INTEGRAL)); + } + + gcc_unreachable (); + return false; +} + } // namespace Resolver } // namespace Rust diff --git a/gcc/rust/typecheck/rust-hir-type-check-expr.h b/gcc/rust/typecheck/rust-hir-type-check-expr.h index 0c44f28..01cb213 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-expr.h +++ b/gcc/rust/typecheck/rust-hir-type-check-expr.h @@ -20,888 +20,85 @@ #define RUST_HIR_TYPE_CHECK_EXPR #include "rust-hir-type-check-base.h" -#include "rust-hir-full.h" -#include "rust-system.h" #include "rust-tyty.h" -#include "rust-tyty-call.h" -#include "rust-hir-type-check-struct-field.h" -#include "rust-hir-path-probe.h" -#include "rust-substitution-mapper.h" -#include "rust-hir-trait-resolve.h" -#include "rust-hir-type-bounds.h" -#include "rust-hir-dot-operator.h" -#include "rust-hir-type-check-pattern.h" namespace Rust { namespace Resolver { -class TypeCheckExpr : public TypeCheckBase +class TypeCheckExpr : public TypeCheckBase, private HIR::HIRExpressionVisitor { - using Rust::Resolver::TypeCheckBase::visit; - public: - // Perform type checking on expr. Also runs type unification algorithm. - // Returns the unified type of expr - static TyTy::BaseType *Resolve (HIR::Expr *expr) - { - TypeCheckExpr resolver; - expr->accept_vis (resolver); - - if (resolver.infered == nullptr) - { - // FIXME - // this is an internal error message for debugging and should be removed - // at some point - rust_error_at (expr->get_locus (), "failed to type resolve expression"); - return new TyTy::ErrorType (expr->get_mappings ().get_hirid ()); - } - - auto ref = expr->get_mappings ().get_hirid (); - resolver.infered->set_ref (ref); - resolver.context->insert_type (expr->get_mappings (), resolver.infered); - - return resolver.infered; - } - - void visit (HIR::TupleIndexExpr &expr) override - { - auto resolved = TypeCheckExpr::Resolve (expr.get_tuple_expr ().get ()); - if (resolved->get_kind () == TyTy::TypeKind::ERROR) - { - rust_error_at (expr.get_tuple_expr ()->get_locus (), - "failed to resolve TupleIndexExpr receiver"); - return; - } - - // FIXME does this require autoderef here? - if (resolved->get_kind () == TyTy::TypeKind::REF) - { - TyTy::ReferenceType *r = static_cast<TyTy::ReferenceType *> (resolved); - resolved = r->get_base (); - } - - bool is_valid_type = resolved->get_kind () == TyTy::TypeKind::ADT - || resolved->get_kind () == TyTy::TypeKind::TUPLE; - if (!is_valid_type) - { - rust_error_at (expr.get_tuple_expr ()->get_locus (), - "Expected Tuple or ADT got: %s", - resolved->as_string ().c_str ()); - return; - } - - if (resolved->get_kind () == TyTy::TypeKind::TUPLE) - { - TyTy::TupleType *tuple = static_cast<TyTy::TupleType *> (resolved); - TupleIndex index = expr.get_tuple_index (); - if ((size_t) index >= tuple->num_fields ()) - { - rust_error_at (expr.get_locus (), "unknown field at index %i", - index); - return; - } - - auto field_tyty = tuple->get_field ((size_t) index); - if (field_tyty == nullptr) - { - rust_error_at (expr.get_locus (), - "failed to lookup field type at index %i", index); - return; - } - - infered = field_tyty; - return; - } - - 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 >= variant->num_fields ()) - { - rust_error_at (expr.get_locus (), "unknown field at index %i", index); - return; - } - - auto field_tyty = variant->get_field_at_index ((size_t) index); - if (field_tyty == nullptr) - { - rust_error_at (expr.get_locus (), - "failed to lookup field type at index %i", index); - return; - } - - infered = field_tyty->get_field_type (); - } - - void visit (HIR::TupleExpr &expr) override - { - if (expr.is_unit ()) - { - auto unit_node_id = resolver->get_unit_type_node_id (); - if (!context->lookup_builtin (unit_node_id, &infered)) - { - rust_error_at (expr.get_locus (), - "failed to lookup builtin unit type"); - } - return; - } - - std::vector<TyTy::TyVar> fields; - for (auto &elem : expr.get_tuple_elems ()) - { - auto field_ty = TypeCheckExpr::Resolve (elem.get ()); - fields.push_back (TyTy::TyVar (field_ty->get_ref ())); - } - infered = new TyTy::TupleType (expr.get_mappings ().get_hirid (), - expr.get_locus (), fields); - } - - void visit (HIR::ReturnExpr &expr) override - { - auto fn_return_tyty = context->peek_return_type (); - rust_assert (fn_return_tyty != nullptr); - - TyTy::BaseType *expr_ty - = expr.has_return_expr () - ? TypeCheckExpr::Resolve (expr.get_expr ()) - : TyTy::TupleType::get_unit_type (expr.get_mappings ().get_hirid ()); - - infered = fn_return_tyty->unify (expr_ty); - fn_return_tyty->append_reference (expr_ty->get_ref ()); - for (auto &ref : infered->get_combined_refs ()) - fn_return_tyty->append_reference (ref); - - infered = new TyTy::NeverType (expr.get_mappings ().get_hirid ()); - } - - void visit (HIR::CallExpr &expr) override - { - TyTy::BaseType *function_tyty = TypeCheckExpr::Resolve (expr.get_fnexpr ()); - - bool valid_tyty = function_tyty->get_kind () == TyTy::TypeKind::ADT - || function_tyty->get_kind () == TyTy::TypeKind::FNDEF - || function_tyty->get_kind () == TyTy::TypeKind::FNPTR; - if (!valid_tyty) - { - rust_error_at (expr.get_locus (), - "Failed to resolve expression of function call"); - return; - } - - 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); - } + static TyTy::BaseType *Resolve (HIR::Expr *expr); + void visit (HIR::TupleIndexExpr &expr) override; + void visit (HIR::TupleExpr &expr) override; + void visit (HIR::ReturnExpr &expr) override; + void visit (HIR::CallExpr &expr) override; void visit (HIR::MethodCallExpr &expr) override; - - void visit (HIR::AssignmentExpr &expr) override - { - infered - = TyTy::TupleType::get_unit_type (expr.get_mappings ().get_hirid ()); - - auto lhs = TypeCheckExpr::Resolve (expr.get_lhs ()); - auto rhs = TypeCheckExpr::Resolve (expr.get_rhs ()); - - coercion_site (expr.get_mappings ().get_hirid (), lhs, rhs, - expr.get_locus ()); - } - - void visit (HIR::CompoundAssignmentExpr &expr) override - { - infered - = TyTy::TupleType::get_unit_type (expr.get_mappings ().get_hirid ()); - - auto lhs = TypeCheckExpr::Resolve (expr.get_left_expr ().get ()); - auto rhs = TypeCheckExpr::Resolve (expr.get_right_expr ().get ()); - - // we dont care about the result of the unify from a compound assignment - // since this is a unit-type expr - auto result = lhs->unify (rhs); - if (result->get_kind () == TyTy::TypeKind::ERROR) - return; - - auto lang_item_type - = Analysis::RustLangItem::CompoundAssignmentOperatorToLangItem ( - expr.get_expr_type ()); - bool operator_overloaded - = resolve_operator_overload (lang_item_type, expr, lhs, rhs); - if (operator_overloaded) - return; - - bool valid_lhs = validate_arithmetic_type (lhs, expr.get_expr_type ()); - bool valid_rhs = validate_arithmetic_type (rhs, expr.get_expr_type ()); - bool valid = valid_lhs && valid_rhs; - if (!valid) - { - rust_error_at (expr.get_locus (), - "cannot apply this operator to types %s and %s", - lhs->as_string ().c_str (), rhs->as_string ().c_str ()); - return; - } - } - - void visit (HIR::IdentifierExpr &expr) override - { - NodeId ast_node_id = expr.get_mappings ().get_nodeid (); - - // then lookup the reference_node_id - NodeId ref_node_id = UNKNOWN_NODEID; - if (!resolver->lookup_resolved_name (ast_node_id, &ref_node_id)) - { - resolver->lookup_resolved_type (ast_node_id, &ref_node_id); - } - - if (ref_node_id == UNKNOWN_NODEID) - { - // FIXME this needs to go away and just return error node - rust_error_at (expr.get_locus (), "unresolved node: %s", - expr.as_string ().c_str ()); - return; - } - - // node back to HIR - HirId ref; - if (!mappings->lookup_node_to_hir (ref_node_id, &ref)) - { - // FIXME - // this is an internal error - rust_error_at (expr.get_locus (), "123 reverse lookup failure"); - return; - } - - // the base reference for this name _must_ have a type set - TyTy::BaseType *lookup; - if (!context->lookup_type (ref, &lookup)) - { - // FIXME - // this is an internal error - rust_error_at (mappings->lookup_location (ref), - "Failed to resolve IdentifierExpr type: %s", - expr.as_string ().c_str ()); - return; - } - - infered = lookup->clone (); - - // Generic unit structs look like an identifier but they actually need be - // handled as a path-in-expression so this gives us a chance to infer the - // generic parameters. - // see https://github.com/Rust-GCC/gccrs/issues/1447 - bool is_unit_struct - = infered->get_kind () == TyTy::TypeKind::ADT && infered->is_unit (); - if (is_unit_struct && infered->needs_generic_substitutions ()) - { - infered = SubstMapper::InferSubst (infered, expr.get_locus ()); - } - } - - void visit (HIR::LiteralExpr &expr) override - { - infered = resolve_literal (expr.get_mappings (), expr.get_literal (), - expr.get_locus ()); - } - - void visit (HIR::ArithmeticOrLogicalExpr &expr) override - { - auto lhs = TypeCheckExpr::Resolve (expr.get_lhs ()); - auto rhs = TypeCheckExpr::Resolve (expr.get_rhs ()); - - auto lang_item_type - = Analysis::RustLangItem::OperatorToLangItem (expr.get_expr_type ()); - bool operator_overloaded - = resolve_operator_overload (lang_item_type, expr, lhs, rhs); - if (operator_overloaded) - return; - - bool valid_lhs = validate_arithmetic_type (lhs, expr.get_expr_type ()); - bool valid_rhs = validate_arithmetic_type (rhs, expr.get_expr_type ()); - bool valid = valid_lhs && valid_rhs; - if (!valid) - { - rust_error_at (expr.get_locus (), - "cannot apply this operator to types %s and %s", - lhs->as_string ().c_str (), rhs->as_string ().c_str ()); - return; - } - - switch (expr.get_expr_type ()) - { - case ArithmeticOrLogicalOperator::LEFT_SHIFT: - case ArithmeticOrLogicalOperator::RIGHT_SHIFT: - infered = rhs->cast (lhs); - break; - - default: - infered = lhs->unify (rhs); - break; - } - } - - void visit (HIR::ComparisonExpr &expr) override - { - auto lhs = TypeCheckExpr::Resolve (expr.get_lhs ()); - auto rhs = TypeCheckExpr::Resolve (expr.get_rhs ()); - - auto result = lhs->unify (rhs); - if (result == nullptr || result->get_kind () == TyTy::TypeKind::ERROR) - return; - - bool ok = context->lookup_builtin ("bool", &infered); - rust_assert (ok); - } - - void visit (HIR::LazyBooleanExpr &expr) override - { - auto lhs = TypeCheckExpr::Resolve (expr.get_lhs ()); - auto rhs = TypeCheckExpr::Resolve (expr.get_rhs ()); - - // we expect the lhs and rhs must be bools at this point - TyTy::BoolType elhs (expr.get_mappings ().get_hirid ()); - lhs = elhs.unify (lhs); - if (lhs->get_kind () == TyTy::TypeKind::ERROR) - return; - - TyTy::BoolType rlhs (expr.get_mappings ().get_hirid ()); - rhs = elhs.unify (rhs); - if (lhs->get_kind () == TyTy::TypeKind::ERROR) - return; - - infered = lhs->unify (rhs); - } - - void visit (HIR::NegationExpr &expr) override - { - auto negated_expr_ty = TypeCheckExpr::Resolve (expr.get_expr ().get ()); - - // check for operator overload - auto lang_item_type = Analysis::RustLangItem::NegationOperatorToLangItem ( - expr.get_expr_type ()); - bool operator_overloaded - = resolve_operator_overload (lang_item_type, expr, negated_expr_ty, - nullptr); - if (operator_overloaded) - return; - - // https://doc.rust-lang.org/reference/expressions/operator-expr.html#negation-operators - switch (expr.get_expr_type ()) - { - case NegationOperator::NEGATE: { - bool valid - = (negated_expr_ty->get_kind () == TyTy::TypeKind::INT) - || (negated_expr_ty->get_kind () == TyTy::TypeKind::UINT) - || (negated_expr_ty->get_kind () == TyTy::TypeKind::FLOAT) - || (negated_expr_ty->get_kind () == TyTy::TypeKind::ISIZE) - || (negated_expr_ty->get_kind () == TyTy::TypeKind::USIZE) - || (negated_expr_ty->get_kind () == TyTy::TypeKind::INFER - && (((TyTy::InferType *) negated_expr_ty)->get_infer_kind () - == TyTy::InferType::INTEGRAL)) - || (negated_expr_ty->get_kind () == TyTy::TypeKind::INFER - && (((TyTy::InferType *) negated_expr_ty)->get_infer_kind () - == TyTy::InferType::FLOAT)); - if (!valid) - { - rust_error_at (expr.get_locus (), "cannot apply unary - to %s", - negated_expr_ty->as_string ().c_str ()); - return; - } - } - break; - - case NegationOperator::NOT: { - bool valid - = (negated_expr_ty->get_kind () == TyTy::TypeKind::BOOL) - || (negated_expr_ty->get_kind () == TyTy::TypeKind::INT) - || (negated_expr_ty->get_kind () == TyTy::TypeKind::UINT) - || (negated_expr_ty->get_kind () == TyTy::TypeKind::INFER - && (((TyTy::InferType *) negated_expr_ty)->get_infer_kind () - == TyTy::InferType::INTEGRAL)); - if (!valid) - { - rust_error_at (expr.get_locus (), - "cannot apply unary %<!%> to %s", - negated_expr_ty->as_string ().c_str ()); - return; - } - } - break; - } - - infered = negated_expr_ty->clone (); - infered->append_reference (negated_expr_ty->get_ref ()); - } - - void visit (HIR::IfExpr &expr) override - { - TypeCheckExpr::Resolve (expr.get_if_condition ()); - TypeCheckExpr::Resolve (expr.get_if_block ()); - - infered - = TyTy::TupleType::get_unit_type (expr.get_mappings ().get_hirid ()); - } - - void visit (HIR::IfExprConseqElse &expr) override - { - TypeCheckExpr::Resolve (expr.get_if_condition ()); - auto if_blk_resolved = TypeCheckExpr::Resolve (expr.get_if_block ()); - auto else_blk_resolved = TypeCheckExpr::Resolve (expr.get_else_block ()); - - if (if_blk_resolved->get_kind () == TyTy::NEVER) - infered = else_blk_resolved; - else if (else_blk_resolved->get_kind () == TyTy::NEVER) - infered = if_blk_resolved; - else - infered = if_blk_resolved->unify (else_blk_resolved); - } - - void visit (HIR::IfExprConseqIf &expr) override - { - TypeCheckExpr::Resolve (expr.get_if_condition ()); - auto if_blk_resolved = TypeCheckExpr::Resolve (expr.get_if_block ()); - auto else_blk_resolved - = TypeCheckExpr::Resolve (expr.get_conseq_if_expr ()); - - if (if_blk_resolved->get_kind () == TyTy::NEVER) - infered = else_blk_resolved; - else if (else_blk_resolved->get_kind () == TyTy::NEVER) - infered = if_blk_resolved; - else - infered = if_blk_resolved->unify (else_blk_resolved); - } - - void visit (HIR::IfLetExpr &expr) override - { - // this needs to perform a least upper bound coercion on the blocks and then - // unify the scruintee and arms - TyTy::BaseType *scrutinee_tyty - = TypeCheckExpr::Resolve (expr.get_scrutinee_expr ().get ()); - - for (auto &pattern : expr.get_patterns ()) - { - TyTy::BaseType *kase_arm_ty - = TypeCheckPattern::Resolve (pattern.get (), scrutinee_tyty); - - TyTy::BaseType *checked_kase = scrutinee_tyty->unify (kase_arm_ty); - if (checked_kase->get_kind () == TyTy::TypeKind::ERROR) - return; - } - - TypeCheckExpr::Resolve (expr.get_if_block ()); - - infered - = TyTy::TupleType::get_unit_type (expr.get_mappings ().get_hirid ()); - } - + void visit (HIR::AssignmentExpr &expr) override; + void visit (HIR::CompoundAssignmentExpr &expr) override; + void visit (HIR::IdentifierExpr &expr) override; + void visit (HIR::LiteralExpr &expr) override; + void visit (HIR::ArithmeticOrLogicalExpr &expr) override; + void visit (HIR::ComparisonExpr &expr) override; + void visit (HIR::LazyBooleanExpr &expr) override; + void visit (HIR::NegationExpr &expr) override; + void visit (HIR::IfExpr &expr) override; + void visit (HIR::IfExprConseqElse &expr) override; + void visit (HIR::IfExprConseqIf &expr) override; + void visit (HIR::IfLetExpr &expr) override; void visit (HIR::BlockExpr &expr) override; - - void visit (HIR::UnsafeBlockExpr &expr) override - { - infered = TypeCheckExpr::Resolve (expr.get_block_expr ().get ()); - } - + void visit (HIR::UnsafeBlockExpr &expr) override; void visit (HIR::ArrayIndexExpr &expr) override; - - void visit (HIR::ArrayExpr &expr) override - { - HIR::ArrayElems &elements = *expr.get_internal_elements (); - - HIR::Expr *capacity_expr = nullptr; - TyTy::BaseType *element_type = nullptr; - switch (elements.get_array_expr_type ()) - { - case HIR::ArrayElems::ArrayExprType::COPIED: { - HIR::ArrayElemsCopied &elems - = static_cast<HIR::ArrayElemsCopied &> (elements); - element_type = TypeCheckExpr::Resolve (elems.get_elem_to_copy ()); - - auto capacity_type - = TypeCheckExpr::Resolve (elems.get_num_copies_expr ()); - - TyTy::BaseType *expected_ty = nullptr; - bool ok = context->lookup_builtin ("usize", &expected_ty); - rust_assert (ok); - context->insert_type (elems.get_num_copies_expr ()->get_mappings (), - expected_ty); - - auto unified = expected_ty->unify (capacity_type); - if (unified->get_kind () == TyTy::TypeKind::ERROR) - return; - - capacity_expr = elems.get_num_copies_expr (); - } - break; - - case HIR::ArrayElems::ArrayExprType::VALUES: { - HIR::ArrayElemsValues &elems - = static_cast<HIR::ArrayElemsValues &> (elements); - - std::vector<TyTy::BaseType *> types; - for (auto &elem : elems.get_values ()) - { - types.push_back (TypeCheckExpr::Resolve (elem.get ())); - } - - element_type = TyTy::TyVar::get_implicit_infer_var (expr.get_locus ()) - .get_tyty (); - for (auto &type : types) - { - element_type = element_type->unify (type); - } - - auto crate_num = mappings->get_current_crate (); - Analysis::NodeMapping mapping (crate_num, UNKNOWN_NODEID, - mappings->get_next_hir_id (crate_num), - UNKNOWN_LOCAL_DEFID); - std::string capacity_str = std::to_string (elems.get_num_elements ()); - capacity_expr - = new HIR::LiteralExpr (mapping, capacity_str, - HIR::Literal::LitType::INT, - PrimitiveCoreType::CORETYPE_USIZE, - Location (), {}); - - // mark the type for this implicit node - TyTy::BaseType *expected_ty = nullptr; - bool ok = context->lookup_builtin ("usize", &expected_ty); - rust_assert (ok); - context->insert_type (mapping, expected_ty); - } - break; - } - - infered = new TyTy::ArrayType (expr.get_mappings ().get_hirid (), - expr.get_locus (), *capacity_expr, - TyTy::TyVar (element_type->get_ref ())); - } - - // empty struct - void visit (HIR::StructExprStruct &struct_expr) override - { - TyTy::BaseType *struct_path_ty - = TypeCheckExpr::Resolve (&struct_expr.get_struct_name ()); - 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; - } - - infered = struct_path_ty; - } - - void visit (HIR::StructExprStructFields &struct_expr) override - { - infered = TypeCheckStructExpr::Resolve (&struct_expr); - } - - void visit (HIR::GroupedExpr &expr) override - { - infered = TypeCheckExpr::Resolve (expr.get_expr_in_parens ().get ()); - } - - void visit (HIR::FieldAccessExpr &expr) override - { - auto struct_base - = TypeCheckExpr::Resolve (expr.get_receiver_expr ().get ()); - - // FIXME does this require autoderef here? - if (struct_base->get_kind () == TyTy::TypeKind::REF) - { - TyTy::ReferenceType *r - = static_cast<TyTy::ReferenceType *> (struct_base); - struct_base = r->get_base (); - } - - bool is_valid_type = struct_base->get_kind () == TyTy::TypeKind::ADT; - if (!is_valid_type) - { - rust_error_at (expr.get_locus (), - "expected algebraic data type got: [%s]", - struct_base->as_string ().c_str ()); - return; - } - - TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (struct_base); - 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 (), - adt->as_string ().c_str ()); - return; - } - - infered = lookup->get_field_type (); - } - + void visit (HIR::ArrayExpr &expr) override; + void visit (HIR::StructExprStruct &struct_expr) override; + void visit (HIR::StructExprStructFields &struct_expr) override; + void visit (HIR::GroupedExpr &expr) override; + void visit (HIR::FieldAccessExpr &expr) override; void visit (HIR::QualifiedPathInExpression &expr) override; - void visit (HIR::PathInExpression &expr) override; - - void visit (HIR::LoopExpr &expr) override - { - context->push_new_loop_context (expr.get_mappings ().get_hirid (), - expr.get_locus ()); - TyTy::BaseType *block_expr - = TypeCheckExpr::Resolve (expr.get_loop_block ().get ()); - if (!block_expr->is_unit ()) - { - rust_error_at (expr.get_loop_block ()->get_locus (), - "expected %<()%> got %s", - block_expr->as_string ().c_str ()); - return; - } - - TyTy::BaseType *loop_context_type = context->pop_loop_context (); - - bool loop_context_type_infered - = (loop_context_type->get_kind () != TyTy::TypeKind::INFER) - || ((loop_context_type->get_kind () == TyTy::TypeKind::INFER) - && (((TyTy::InferType *) loop_context_type)->get_infer_kind () - != TyTy::InferType::GENERAL)); - - infered - = loop_context_type_infered - ? loop_context_type - : TyTy::TupleType::get_unit_type (expr.get_mappings ().get_hirid ()); - } - - void visit (HIR::WhileLoopExpr &expr) override - { - context->push_new_while_loop_context (expr.get_mappings ().get_hirid ()); - - TypeCheckExpr::Resolve (expr.get_predicate_expr ().get ()); - TyTy::BaseType *block_expr - = TypeCheckExpr::Resolve (expr.get_loop_block ().get ()); - - if (!block_expr->is_unit ()) - { - rust_error_at (expr.get_loop_block ()->get_locus (), - "expected %<()%> got %s", - block_expr->as_string ().c_str ()); - return; - } - - context->pop_loop_context (); - infered - = TyTy::TupleType::get_unit_type (expr.get_mappings ().get_hirid ()); - } - - void visit (HIR::BreakExpr &expr) override - { - if (!context->have_loop_context ()) - { - rust_error_at (expr.get_locus (), "cannot %<break%> outside of a loop"); - return; - } - - if (expr.has_break_expr ()) - { - TyTy::BaseType *break_expr_tyty - = TypeCheckExpr::Resolve (expr.get_expr ().get ()); - - TyTy::BaseType *loop_context = context->peek_loop_context (); - if (loop_context->get_kind () == TyTy::TypeKind::ERROR) - { - rust_error_at (expr.get_locus (), - "can only break with a value inside %<loop%>"); - return; - } - - TyTy::BaseType *unified_ty = loop_context->unify (break_expr_tyty); - context->swap_head_loop_context (unified_ty); - } - - infered = new TyTy::NeverType (expr.get_mappings ().get_hirid ()); - } - - void visit (HIR::ContinueExpr &expr) override - { - if (!context->have_loop_context ()) - { - rust_error_at (expr.get_locus (), - "cannot %<continue%> outside of a loop"); - return; - } - - infered = new TyTy::NeverType (expr.get_mappings ().get_hirid ()); - } - - void visit (HIR::BorrowExpr &expr) override - { - TyTy::BaseType *resolved_base - = TypeCheckExpr::Resolve (expr.get_expr ().get ()); - - // In Rust this is valid because of DST's - // - // fn test() { - // let a:&str = "TEST 1"; - // let b:&str = &"TEST 2"; - // } - if (resolved_base->get_kind () == TyTy::TypeKind::REF) - { - const TyTy::ReferenceType *ref - = static_cast<const TyTy::ReferenceType *> (resolved_base); - - // this might end up being a more generic is_dyn object check but lets - // double check dyn traits type-layout first - if (ref->is_dyn_str_type ()) - { - infered = resolved_base; - return; - } - } - - if (expr.get_is_double_borrow ()) - { - // FIXME double_reference - gcc_unreachable (); - } - - infered = new TyTy::ReferenceType (expr.get_mappings ().get_hirid (), - TyTy::TyVar (resolved_base->get_ref ()), - expr.get_mut ()); - } - - void visit (HIR::DereferenceExpr &expr) override + void visit (HIR::LoopExpr &expr) override; + void visit (HIR::BreakExpr &expr) override; + void visit (HIR::ContinueExpr &expr) override; + void visit (HIR::BorrowExpr &expr) override; + void visit (HIR::DereferenceExpr &expr) override; + void visit (HIR::TypeCastExpr &expr) override; + void visit (HIR::MatchExpr &expr) override; + void visit (HIR::RangeFromToExpr &expr) override; + void visit (HIR::RangeFromExpr &expr) override; + void visit (HIR::RangeToExpr &expr) override; + void visit (HIR::RangeFullExpr &expr) override; + void visit (HIR::RangeFromToInclExpr &expr) override; + void visit (HIR::WhileLoopExpr &expr) override; + + // TODO + void visit (HIR::ClosureExprInnerTyped &) override {} + void visit (HIR::ClosureExprInner &expr) override {} + void visit (HIR::ErrorPropagationExpr &expr) override {} + void visit (HIR::RangeToInclExpr &expr) override {} + void visit (HIR::WhileLetLoopExpr &expr) override {} + void visit (HIR::ForLoopExpr &expr) override {} + void visit (HIR::IfExprConseqIfLet &expr) override {} + void visit (HIR::IfLetExprConseqElse &expr) override {} + void visit (HIR::IfLetExprConseqIf &expr) override {} + void visit (HIR::IfLetExprConseqIfLet &expr) override {} + void visit (HIR::AwaitExpr &expr) override {} + void visit (HIR::AsyncBlockExpr &expr) override {} + + // don't need to implement these see rust-hir-type-check-struct-field.h + void visit (HIR::StructExprFieldIdentifier &field) override { - TyTy::BaseType *resolved_base - = TypeCheckExpr::Resolve (expr.get_expr ().get ()); - - auto lang_item_type = Analysis::RustLangItem::ItemType::DEREF; - bool operator_overloaded - = resolve_operator_overload (lang_item_type, expr, resolved_base, - nullptr); - if (operator_overloaded) - { - // operator overloaded deref always refurns a reference type lets assert - // this - rust_assert (infered->get_kind () == TyTy::TypeKind::REF); - resolved_base = infered; - } - - bool is_valid_type - = resolved_base->get_kind () == TyTy::TypeKind::REF - || resolved_base->get_kind () == TyTy::TypeKind::POINTER; - if (!is_valid_type) - { - rust_error_at (expr.get_locus (), "expected reference type got %s", - resolved_base->as_string ().c_str ()); - return; - } - - if (resolved_base->get_kind () == TyTy::TypeKind::REF) - { - TyTy::ReferenceType *ref_base - = static_cast<TyTy::ReferenceType *> (resolved_base); - infered = ref_base->get_base ()->clone (); - } - else - { - TyTy::PointerType *ref_base - = static_cast<TyTy::PointerType *> (resolved_base); - infered = ref_base->get_base ()->clone (); - } + gcc_unreachable (); } - - void visit (HIR::TypeCastExpr &expr) override + void visit (HIR::StructExprFieldIdentifierValue &field) override { - TyTy::BaseType *expr_to_convert - = TypeCheckExpr::Resolve (expr.get_casted_expr ().get ()); - TyTy::BaseType *tyty_to_convert_to - = TypeCheckType::Resolve (expr.get_type_to_convert_to ().get ()); - - infered = expr_to_convert->cast (tyty_to_convert_to); + gcc_unreachable (); } - - void visit (HIR::MatchExpr &expr) override + void visit (HIR::StructExprFieldIndexValue &field) override { - // this needs to perform a least upper bound coercion on the blocks and then - // unify the scruintee and arms - TyTy::BaseType *scrutinee_tyty - = TypeCheckExpr::Resolve (expr.get_scrutinee_expr ().get ()); - - std::vector<TyTy::BaseType *> kase_block_tys; - for (auto &kase : expr.get_match_cases ()) - { - // lets check the arms - HIR::MatchArm &kase_arm = kase.get_arm (); - for (auto &pattern : kase_arm.get_patterns ()) - { - TyTy::BaseType *kase_arm_ty - = TypeCheckPattern::Resolve (pattern.get (), scrutinee_tyty); - - TyTy::BaseType *checked_kase = scrutinee_tyty->unify (kase_arm_ty); - if (checked_kase->get_kind () == TyTy::TypeKind::ERROR) - return; - } - - // check the kase type - TyTy::BaseType *kase_block_ty - = TypeCheckExpr::Resolve (kase.get_expr ().get ()); - kase_block_tys.push_back (kase_block_ty); - } - - if (kase_block_tys.size () == 0) - { - infered - = TyTy::TupleType::get_unit_type (expr.get_mappings ().get_hirid ()); - return; - } - - infered = kase_block_tys.at (0); - for (size_t i = 1; i < kase_block_tys.size (); i++) - { - TyTy::BaseType *kase_ty = kase_block_tys.at (i); - infered = infered->unify (kase_ty); - if (infered->get_kind () == TyTy::TypeKind::ERROR) - return; - } + gcc_unreachable (); } - void visit (HIR::RangeFromToExpr &expr) override; - - void visit (HIR::RangeFromExpr &expr) override; - - void visit (HIR::RangeToExpr &expr) override; - - void visit (HIR::RangeFullExpr &expr) override; - - void visit (HIR::RangeFromToInclExpr &expr) override; - protected: bool resolve_operator_overload (Analysis::RustLangItem::ItemType lang_item_type, @@ -909,7 +106,7 @@ protected: TyTy::BaseType *rhs); private: - TypeCheckExpr () : TypeCheckBase (), infered (nullptr) {} + TypeCheckExpr (); TyTy::BaseType *resolve_root_path (HIR::PathInExpression &expr, size_t *offset, @@ -923,59 +120,7 @@ private: bool validate_arithmetic_type (const TyTy::BaseType *tyty, - HIR::ArithmeticOrLogicalExpr::ExprType expr_type) - { - const TyTy::BaseType *type = tyty->destructure (); - - // https://doc.rust-lang.org/reference/expressions/operator-expr.html#arithmetic-and-logical-binary-operators - // this will change later when traits are added - switch (expr_type) - { - case ArithmeticOrLogicalOperator::ADD: - case ArithmeticOrLogicalOperator::SUBTRACT: - case ArithmeticOrLogicalOperator::MULTIPLY: - case ArithmeticOrLogicalOperator::DIVIDE: - case ArithmeticOrLogicalOperator::MODULUS: - return (type->get_kind () == TyTy::TypeKind::INT) - || (type->get_kind () == TyTy::TypeKind::UINT) - || (type->get_kind () == TyTy::TypeKind::FLOAT) - || (type->get_kind () == TyTy::TypeKind::USIZE) - || (type->get_kind () == TyTy::TypeKind::ISIZE) - || (type->get_kind () == TyTy::TypeKind::INFER - && (((const TyTy::InferType *) type)->get_infer_kind () - == TyTy::InferType::INTEGRAL)) - || (type->get_kind () == TyTy::TypeKind::INFER - && (((const TyTy::InferType *) type)->get_infer_kind () - == TyTy::InferType::FLOAT)); - - // integers or bools - case ArithmeticOrLogicalOperator::BITWISE_AND: - case ArithmeticOrLogicalOperator::BITWISE_OR: - case ArithmeticOrLogicalOperator::BITWISE_XOR: - return (type->get_kind () == TyTy::TypeKind::INT) - || (type->get_kind () == TyTy::TypeKind::UINT) - || (type->get_kind () == TyTy::TypeKind::USIZE) - || (type->get_kind () == TyTy::TypeKind::ISIZE) - || (type->get_kind () == TyTy::TypeKind::BOOL) - || (type->get_kind () == TyTy::TypeKind::INFER - && (((const TyTy::InferType *) type)->get_infer_kind () - == TyTy::InferType::INTEGRAL)); - - // integers only - case ArithmeticOrLogicalOperator::LEFT_SHIFT: - case ArithmeticOrLogicalOperator::RIGHT_SHIFT: - return (type->get_kind () == TyTy::TypeKind::INT) - || (type->get_kind () == TyTy::TypeKind::UINT) - || (type->get_kind () == TyTy::TypeKind::USIZE) - || (type->get_kind () == TyTy::TypeKind::ISIZE) - || (type->get_kind () == TyTy::TypeKind::INFER - && (((const TyTy::InferType *) type)->get_infer_kind () - == TyTy::InferType::INTEGRAL)); - } - - gcc_unreachable (); - return false; - } + HIR::ArithmeticOrLogicalExpr::ExprType expr_type); /* The return value of TypeCheckExpr::Resolve */ TyTy::BaseType *infered; diff --git a/gcc/rust/typecheck/rust-hir-type-check-implitem.cc b/gcc/rust/typecheck/rust-hir-type-check-implitem.cc new file mode 100644 index 0000000..784e499 --- /dev/null +++ b/gcc/rust/typecheck/rust-hir-type-check-implitem.cc @@ -0,0 +1,583 @@ +// Copyright (C) 2020-2022 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-implitem.h" +#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" +#include "rust-hir-type-check-pattern.h" +#include "rust-tyty.h" + +namespace Rust { +namespace Resolver { + +TypeCheckTopLevelExternItem::TypeCheckTopLevelExternItem ( + const HIR::ExternBlock &parent) + : TypeCheckBase (), parent (parent) +{} + +void +TypeCheckTopLevelExternItem::Resolve (HIR::ExternalItem *item, + const HIR::ExternBlock &parent) +{ + TypeCheckTopLevelExternItem resolver (parent); + item->accept_vis (resolver); +} + +void +TypeCheckTopLevelExternItem::visit (HIR::ExternalStaticItem &item) +{ + TyTy::BaseType *actual_type + = TypeCheckType::Resolve (item.get_item_type ().get ()); + + context->insert_type (item.get_mappings (), actual_type); +} + +void +TypeCheckTopLevelExternItem::visit (HIR::ExternalFunctionItem &function) +{ + std::vector<TyTy::SubstitutionParamMapping> substitutions; + if (function.has_generics ()) + { + for (auto &generic_param : function.get_generic_params ()) + { + switch (generic_param.get ()->get_kind ()) + { + case HIR::GenericParam::GenericKind::LIFETIME: + case HIR::GenericParam::GenericKind::CONST: + // FIXME: Skipping Lifetime and Const 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; + } + } + } + + TyTy::BaseType *ret_type = nullptr; + if (!function.has_return_type ()) + ret_type + = TyTy::TupleType::get_unit_type (function.get_mappings ().get_hirid ()); + else + { + auto resolved + = TypeCheckType::Resolve (function.get_return_type ().get ()); + if (resolved == nullptr) + { + rust_error_at (function.get_locus (), + "failed to resolve return type"); + return; + } + + ret_type = resolved->clone (); + ret_type->set_ref ( + function.get_return_type ()->get_mappings ().get_hirid ()); + } + + std::vector<std::pair<HIR::Pattern *, TyTy::BaseType *> > params; + for (auto ¶m : function.get_function_params ()) + { + // get the name as well required for later on + auto param_tyty = TypeCheckType::Resolve (param.get_type ().get ()); + + // these are implicit mappings and not used + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, mappings->get_next_node_id (), + mappings->get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + + HIR::IdentifierPattern *param_pattern + = new HIR::IdentifierPattern (mapping, param.get_param_name (), + Location (), false, Mutability::Imm, + std::unique_ptr<HIR::Pattern> (nullptr)); + + params.push_back ( + std::pair<HIR::Pattern *, TyTy::BaseType *> (param_pattern, + param_tyty)); + + context->insert_type (param.get_mappings (), param_tyty); + + // FIXME do we need error checking for patterns here? + // see https://github.com/Rust-GCC/gccrs/issues/995 + } + + uint8_t flags = TyTy::FnType::FNTYPE_IS_EXTERN_FLAG; + if (function.is_variadic ()) + flags |= TyTy::FnType::FNTYPE_IS_VARADIC_FLAG; + + RustIdent ident{ + CanonicalPath::new_seg (function.get_mappings ().get_nodeid (), + function.get_item_name ()), + function.get_locus ()}; + + auto fnType = new TyTy::FnType (function.get_mappings ().get_hirid (), + function.get_mappings ().get_defid (), + function.get_item_name (), ident, flags, + parent.get_abi (), std::move (params), + ret_type, std::move (substitutions)); + + context->insert_type (function.get_mappings (), fnType); +} + +TypeCheckTopLevelImplItem::TypeCheckTopLevelImplItem ( + TyTy::BaseType *self, + std::vector<TyTy::SubstitutionParamMapping> substitutions) + : TypeCheckBase (), self (self), substitutions (substitutions) +{} + +void +TypeCheckTopLevelImplItem::Resolve ( + HIR::ImplItem *item, TyTy::BaseType *self, + std::vector<TyTy::SubstitutionParamMapping> substitutions) +{ + TypeCheckTopLevelImplItem resolver (self, substitutions); + item->accept_vis (resolver); +} + +void +TypeCheckTopLevelImplItem::visit (HIR::TypeAlias &alias) +{ + TyTy::BaseType *actual_type + = TypeCheckType::Resolve (alias.get_type_aliased ().get ()); + + context->insert_type (alias.get_mappings (), actual_type); + + for (auto &where_clause_item : alias.get_where_clause ().get_items ()) + { + ResolveWhereClauseItem::Resolve (*where_clause_item.get ()); + } +} + +void +TypeCheckTopLevelImplItem::visit (HIR::ConstantItem &constant) +{ + TyTy::BaseType *type = TypeCheckType::Resolve (constant.get_type ()); + TyTy::BaseType *expr_type = TypeCheckExpr::Resolve (constant.get_expr ()); + + context->insert_type (constant.get_mappings (), type->unify (expr_type)); +} + +void +TypeCheckTopLevelImplItem::visit (HIR::Function &function) +{ + if (function.has_generics ()) + { + for (auto &generic_param : function.get_generic_params ()) + { + switch (generic_param.get ()->get_kind ()) + { + case HIR::GenericParam::GenericKind::LIFETIME: + case HIR::GenericParam::GenericKind::CONST: + // FIXME: Skipping Lifetime and Const 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; + } + } + } + + for (auto &where_clause_item : function.get_where_clause ().get_items ()) + { + ResolveWhereClauseItem::Resolve (*where_clause_item.get ()); + } + + TyTy::BaseType *ret_type = nullptr; + if (!function.has_function_return_type ()) + ret_type + = TyTy::TupleType::get_unit_type (function.get_mappings ().get_hirid ()); + else + { + auto resolved + = TypeCheckType::Resolve (function.get_return_type ().get ()); + if (resolved == nullptr) + { + rust_error_at (function.get_locus (), + "failed to resolve return type"); + return; + } + + ret_type = resolved->clone (); + ret_type->set_ref ( + function.get_return_type ()->get_mappings ().get_hirid ()); + } + + std::vector<std::pair<HIR::Pattern *, TyTy::BaseType *> > params; + if (function.is_method ()) + { + // these are implicit mappings and not used + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, mappings->get_next_node_id (), + mappings->get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + + // add the synthetic self param at the front, this is a placeholder for + // compilation to know parameter names. The types are ignored but we + // reuse the HIR identifier pattern which requires it + HIR::SelfParam &self_param = function.get_self_param (); + HIR::IdentifierPattern *self_pattern + = new HIR::IdentifierPattern (mapping, "self", self_param.get_locus (), + self_param.is_ref (), + self_param.get_mut (), + std::unique_ptr<HIR::Pattern> (nullptr)); + + // might have a specified type + TyTy::BaseType *self_type = nullptr; + if (self_param.has_type ()) + { + std::unique_ptr<HIR::Type> &specified_type = self_param.get_type (); + self_type = TypeCheckType::Resolve (specified_type.get ()); + } + else + { + switch (self_param.get_self_kind ()) + { + case HIR::SelfParam::IMM: + case HIR::SelfParam::MUT: + self_type = self->clone (); + break; + + case HIR::SelfParam::IMM_REF: + self_type = new TyTy::ReferenceType ( + self_param.get_mappings ().get_hirid (), + TyTy::TyVar (self->get_ref ()), Mutability::Imm); + break; + + case HIR::SelfParam::MUT_REF: + self_type = new TyTy::ReferenceType ( + self_param.get_mappings ().get_hirid (), + TyTy::TyVar (self->get_ref ()), Mutability::Mut); + break; + + default: + gcc_unreachable (); + return; + } + } + + context->insert_type (self_param.get_mappings (), self_type); + params.push_back ( + std::pair<HIR::Pattern *, TyTy::BaseType *> (self_pattern, self_type)); + } + + for (auto ¶m : function.get_function_params ()) + { + // get the name as well required for later on + auto param_tyty = TypeCheckType::Resolve (param.get_type ()); + params.push_back ( + std::pair<HIR::Pattern *, TyTy::BaseType *> (param.get_param_name (), + param_tyty)); + + context->insert_type (param.get_mappings (), param_tyty); + TypeCheckPattern::Resolve (param.get_param_name (), param_tyty); + } + + const CanonicalPath *canonical_path = nullptr; + bool ok + = mappings->lookup_canonical_path (function.get_mappings ().get_nodeid (), + &canonical_path); + rust_assert (ok); + + RustIdent ident{*canonical_path, function.get_locus ()}; + auto fnType = new TyTy::FnType (function.get_mappings ().get_hirid (), + function.get_mappings ().get_defid (), + function.get_function_name (), ident, + function.is_method () + ? TyTy::FnType::FNTYPE_IS_METHOD_FLAG + : TyTy::FnType::FNTYPE_DEFAULT_FLAGS, + ABI::RUST, std::move (params), ret_type, + std::move (substitutions)); + + context->insert_type (function.get_mappings (), fnType); +} + +TypeCheckImplItem::TypeCheckImplItem (HIR::ImplBlock *parent, + TyTy::BaseType *self) + : TypeCheckBase (), parent (parent), self (self) +{} + +void +TypeCheckImplItem::Resolve (HIR::ImplBlock *parent, HIR::ImplItem *item, + TyTy::BaseType *self) +{ + TypeCheckImplItem resolver (parent, self); + item->accept_vis (resolver); +} + +void +TypeCheckImplItem::visit (HIR::Function &function) +{ + TyTy::BaseType *lookup; + if (!context->lookup_type (function.get_mappings ().get_hirid (), &lookup)) + { + rust_error_at (function.get_locus (), "failed to lookup function type"); + return; + } + + if (lookup->get_kind () != TyTy::TypeKind::FNDEF) + { + rust_error_at (function.get_locus (), + "found invalid type for function [%s]", + lookup->as_string ().c_str ()); + return; + } + + // need to get the return type from this + TyTy::FnType *resolve_fn_type = static_cast<TyTy::FnType *> (lookup); + auto expected_ret_tyty = resolve_fn_type->get_return_type (); + context->push_return_type (TypeCheckContextItem (parent, &function), + expected_ret_tyty); + + auto block_expr_ty + = TypeCheckExpr::Resolve (function.get_definition ().get ()); + + context->pop_return_type (); + expected_ret_tyty->unify (block_expr_ty); +} + +void +TypeCheckImplItem::visit (HIR::ConstantItem &const_item) +{} + +void +TypeCheckImplItem::visit (HIR::TypeAlias &type_alias) +{} + +TypeCheckImplItemWithTrait::TypeCheckImplItemWithTrait ( + HIR::ImplBlock *parent, TyTy::BaseType *self, + TyTy::TypeBoundPredicate &trait_reference, + std::vector<TyTy::SubstitutionParamMapping> substitutions) + : TypeCheckImplItem (parent, self), trait_reference (trait_reference), + resolved_trait_item (TyTy::TypeBoundPredicateItem::error ()), + substitutions (substitutions) +{ + rust_assert (is_trait_impl_block ()); +} + +TyTy::TypeBoundPredicateItem +TypeCheckImplItemWithTrait::Resolve ( + HIR::ImplBlock *parent, HIR::ImplItem *item, TyTy::BaseType *self, + TyTy::TypeBoundPredicate &trait_reference, + std::vector<TyTy::SubstitutionParamMapping> substitutions) +{ + TypeCheckImplItemWithTrait resolver (parent, self, trait_reference, + substitutions); + item->accept_vis (resolver); + return resolver.resolved_trait_item; +} + +void +TypeCheckImplItemWithTrait::visit (HIR::ConstantItem &constant) +{ + // normal resolution of the item + TypeCheckImplItem::visit (constant); + TyTy::BaseType *lookup; + if (!context->lookup_type (constant.get_mappings ().get_hirid (), &lookup)) + return; + + // map the impl item to the associated trait item + const auto tref = trait_reference.get (); + const TraitItemReference *raw_trait_item = nullptr; + bool found + = tref->lookup_trait_item_by_type (constant.get_identifier (), + TraitItemReference::TraitItemType::CONST, + &raw_trait_item); + + // unknown trait item + if (!found || raw_trait_item->is_error ()) + { + RichLocation r (constant.get_locus ()); + r.add_range (trait_reference.get_locus ()); + rust_error_at (r, "constant %<%s%> is not a member of trait %<%s%>", + constant.get_identifier ().c_str (), + trait_reference.get_name ().c_str ()); + return; + } + + // get the item from the predicate + resolved_trait_item = trait_reference.lookup_associated_item (raw_trait_item); + rust_assert (!resolved_trait_item.is_error ()); + + // merge the attributes + const HIR::TraitItem *hir_trait_item + = resolved_trait_item.get_raw_item ()->get_hir_trait_item (); + merge_attributes (constant.get_outer_attrs (), *hir_trait_item); + + // check the types are compatible + auto trait_item_type = resolved_trait_item.get_tyty_for_receiver (self); + if (!trait_item_type->can_eq (lookup, true)) + { + RichLocation r (constant.get_locus ()); + r.add_range (resolved_trait_item.get_locus ()); + + rust_error_at ( + r, "constant %<%s%> has an incompatible type for trait %<%s%>", + constant.get_identifier ().c_str (), + trait_reference.get_name ().c_str ()); + } +} + +void +TypeCheckImplItemWithTrait::visit (HIR::TypeAlias &type) +{ + // normal resolution of the item + TypeCheckImplItem::visit (type); + TyTy::BaseType *lookup; + if (!context->lookup_type (type.get_mappings ().get_hirid (), &lookup)) + return; + + // map the impl item to the associated trait item + const auto tref = trait_reference.get (); + const TraitItemReference *raw_trait_item = nullptr; + bool found + = tref->lookup_trait_item_by_type (type.get_new_type_name (), + TraitItemReference::TraitItemType::TYPE, + &raw_trait_item); + + // unknown trait item + if (!found || raw_trait_item->is_error ()) + { + RichLocation r (type.get_locus ()); + r.add_range (trait_reference.get_locus ()); + rust_error_at (r, "type alias %<%s%> is not a member of trait %<%s%>", + type.get_new_type_name ().c_str (), + trait_reference.get_name ().c_str ()); + return; + } + + // get the item from the predicate + resolved_trait_item = trait_reference.lookup_associated_item (raw_trait_item); + rust_assert (!resolved_trait_item.is_error ()); + + // merge the attributes + const HIR::TraitItem *hir_trait_item + = resolved_trait_item.get_raw_item ()->get_hir_trait_item (); + merge_attributes (type.get_outer_attrs (), *hir_trait_item); + + // check the types are compatible + auto trait_item_type = resolved_trait_item.get_tyty_for_receiver (self); + if (!trait_item_type->can_eq (lookup, true)) + { + RichLocation r (type.get_locus ()); + r.add_range (resolved_trait_item.get_locus ()); + + rust_error_at ( + r, "type alias %<%s%> has an incompatible type for trait %<%s%>", + type.get_new_type_name ().c_str (), + trait_reference.get_name ().c_str ()); + } + + // 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 (type.get_mappings ().get_hirid (), lookup, tref, + raw_trait_item->get_mappings ().get_defid (), + substitutions); + + context->insert_type (type.get_mappings (), projection); + raw_trait_item->associated_type_set (projection); +} + +void +TypeCheckImplItemWithTrait::visit (HIR::Function &function) +{ + // we get the error checking from the base method here + TypeCheckImplItem::visit (function); + TyTy::BaseType *lookup; + if (!context->lookup_type (function.get_mappings ().get_hirid (), &lookup)) + return; + + // map the impl item to the associated trait item + const auto tref = trait_reference.get (); + const TraitItemReference *raw_trait_item = nullptr; + bool found + = tref->lookup_trait_item_by_type (function.get_function_name (), + TraitItemReference::TraitItemType::FN, + &raw_trait_item); + + // unknown trait item + if (!found || raw_trait_item->is_error ()) + { + RichLocation r (function.get_locus ()); + r.add_range (trait_reference.get_locus ()); + rust_error_at (r, "method %<%s%> is not a member of trait %<%s%>", + function.get_function_name ().c_str (), + trait_reference.get_name ().c_str ()); + return; + } + + // get the item from the predicate + resolved_trait_item = trait_reference.lookup_associated_item (raw_trait_item); + rust_assert (!resolved_trait_item.is_error ()); + + // merge the attributes + const HIR::TraitItem *hir_trait_item + = resolved_trait_item.get_raw_item ()->get_hir_trait_item (); + merge_attributes (function.get_outer_attrs (), *hir_trait_item); + + // check the types are compatible + auto trait_item_type = resolved_trait_item.get_tyty_for_receiver (self); + if (!trait_item_type->can_eq (lookup, true)) + { + RichLocation r (function.get_locus ()); + r.add_range (resolved_trait_item.get_locus ()); + + rust_error_at (r, + "method %<%s%> has an incompatible type for trait %<%s%>", + function.get_function_name ().c_str (), + trait_reference.get_name ().c_str ()); + } +} + +void +TypeCheckImplItemWithTrait::merge_attributes (AST::AttrVec &impl_item_attrs, + const HIR::TraitItem &trait_item) +{ + for (const auto &attr : trait_item.get_outer_attrs ()) + { + impl_item_attrs.push_back (attr); + } +} + +bool +TypeCheckImplItemWithTrait::is_trait_impl_block () const +{ + return !trait_reference.is_error (); +} + +} // namespace Resolver +} // namespace Rust diff --git a/gcc/rust/typecheck/rust-hir-type-check-implitem.h b/gcc/rust/typecheck/rust-hir-type-check-implitem.h index 294dffd..f2f3faa 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-implitem.h +++ b/gcc/rust/typecheck/rust-hir-type-check-implitem.h @@ -20,368 +20,58 @@ #define RUST_HIR_TYPE_CHECK_IMPLITEM_H #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" -#include "rust-tyty.h" namespace Rust { namespace Resolver { -class TypeCheckTopLevelExternItem : public TypeCheckBase +class TypeCheckTopLevelExternItem : public TypeCheckBase, + public HIR::HIRExternalItemVisitor { - using Rust::Resolver::TypeCheckBase::visit; - public: - static void Resolve (HIR::ExternalItem *item, const HIR::ExternBlock &parent) - { - TypeCheckTopLevelExternItem resolver (parent); - item->accept_vis (resolver); - } - - void visit (HIR::ExternalStaticItem &item) override - { - TyTy::BaseType *actual_type - = TypeCheckType::Resolve (item.get_item_type ().get ()); - - context->insert_type (item.get_mappings (), actual_type); - } - - void visit (HIR::ExternalFunctionItem &function) override - { - std::vector<TyTy::SubstitutionParamMapping> substitutions; - if (function.has_generics ()) - { - for (auto &generic_param : function.get_generic_params ()) - { - switch (generic_param.get ()->get_kind ()) - { - case HIR::GenericParam::GenericKind::LIFETIME: - case HIR::GenericParam::GenericKind::CONST: - // FIXME: Skipping Lifetime and Const 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; - } - } - } - - TyTy::BaseType *ret_type = nullptr; - if (!function.has_return_type ()) - ret_type = TyTy::TupleType::get_unit_type ( - function.get_mappings ().get_hirid ()); - else - { - auto resolved - = TypeCheckType::Resolve (function.get_return_type ().get ()); - if (resolved == nullptr) - { - rust_error_at (function.get_locus (), - "failed to resolve return type"); - return; - } - - ret_type = resolved->clone (); - ret_type->set_ref ( - function.get_return_type ()->get_mappings ().get_hirid ()); - } - - std::vector<std::pair<HIR::Pattern *, TyTy::BaseType *> > params; - for (auto ¶m : function.get_function_params ()) - { - // get the name as well required for later on - auto param_tyty = TypeCheckType::Resolve (param.get_type ().get ()); - - // these are implicit mappings and not used - auto crate_num = mappings->get_current_crate (); - Analysis::NodeMapping mapping (crate_num, mappings->get_next_node_id (), - mappings->get_next_hir_id (crate_num), - UNKNOWN_LOCAL_DEFID); - - HIR::IdentifierPattern *param_pattern = new HIR::IdentifierPattern ( - mapping, param.get_param_name (), Location (), false, Mutability::Imm, - std::unique_ptr<HIR::Pattern> (nullptr)); - - params.push_back ( - std::pair<HIR::Pattern *, TyTy::BaseType *> (param_pattern, - param_tyty)); - - context->insert_type (param.get_mappings (), param_tyty); - - // FIXME do we need error checking for patterns here? - // see https://github.com/Rust-GCC/gccrs/issues/995 - } - - uint8_t flags = TyTy::FnType::FNTYPE_IS_EXTERN_FLAG; - if (function.is_variadic ()) - flags |= TyTy::FnType::FNTYPE_IS_VARADIC_FLAG; - - RustIdent ident{ - CanonicalPath::new_seg (function.get_mappings ().get_nodeid (), - function.get_item_name ()), - function.get_locus ()}; - - auto fnType = new TyTy::FnType (function.get_mappings ().get_hirid (), - function.get_mappings ().get_defid (), - function.get_item_name (), ident, flags, - parent.get_abi (), std::move (params), - ret_type, std::move (substitutions)); + static void Resolve (HIR::ExternalItem *item, const HIR::ExternBlock &parent); - context->insert_type (function.get_mappings (), fnType); - } + void visit (HIR::ExternalStaticItem &item) override; + void visit (HIR::ExternalFunctionItem &function) override; private: - TypeCheckTopLevelExternItem (const HIR::ExternBlock &parent) - : TypeCheckBase (), parent (parent) - {} + TypeCheckTopLevelExternItem (const HIR::ExternBlock &parent); const HIR::ExternBlock &parent; }; -class TypeCheckTopLevelImplItem : public TypeCheckBase +class TypeCheckTopLevelImplItem : public TypeCheckBase, + public HIR::HIRImplVisitor { - using Rust::Resolver::TypeCheckBase::visit; - public: static void Resolve (HIR::ImplItem *item, TyTy::BaseType *self, - std::vector<TyTy::SubstitutionParamMapping> substitutions) - { - TypeCheckTopLevelImplItem resolver (self, substitutions); - item->accept_vis (resolver); - } - - void visit (HIR::TypeAlias &alias) override - { - TyTy::BaseType *actual_type - = TypeCheckType::Resolve (alias.get_type_aliased ().get ()); - - context->insert_type (alias.get_mappings (), actual_type); - - for (auto &where_clause_item : alias.get_where_clause ().get_items ()) - { - ResolveWhereClauseItem::Resolve (*where_clause_item.get ()); - } - } - - void visit (HIR::ConstantItem &constant) override - { - TyTy::BaseType *type = TypeCheckType::Resolve (constant.get_type ()); - TyTy::BaseType *expr_type = TypeCheckExpr::Resolve (constant.get_expr ()); - - context->insert_type (constant.get_mappings (), type->unify (expr_type)); - } - - void visit (HIR::Function &function) override - { - if (function.has_generics ()) - { - for (auto &generic_param : function.get_generic_params ()) - { - switch (generic_param.get ()->get_kind ()) - { - case HIR::GenericParam::GenericKind::LIFETIME: - case HIR::GenericParam::GenericKind::CONST: - // FIXME: Skipping Lifetime and Const 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; - } - } - } - - for (auto &where_clause_item : function.get_where_clause ().get_items ()) - { - ResolveWhereClauseItem::Resolve (*where_clause_item.get ()); - } - - TyTy::BaseType *ret_type = nullptr; - if (!function.has_function_return_type ()) - ret_type = TyTy::TupleType::get_unit_type ( - function.get_mappings ().get_hirid ()); - else - { - auto resolved - = TypeCheckType::Resolve (function.get_return_type ().get ()); - if (resolved == nullptr) - { - rust_error_at (function.get_locus (), - "failed to resolve return type"); - return; - } - - ret_type = resolved->clone (); - ret_type->set_ref ( - function.get_return_type ()->get_mappings ().get_hirid ()); - } - - std::vector<std::pair<HIR::Pattern *, TyTy::BaseType *> > params; - if (function.is_method ()) - { - // these are implicit mappings and not used - auto crate_num = mappings->get_current_crate (); - Analysis::NodeMapping mapping (crate_num, mappings->get_next_node_id (), - mappings->get_next_hir_id (crate_num), - UNKNOWN_LOCAL_DEFID); - - // add the synthetic self param at the front, this is a placeholder for - // compilation to know parameter names. The types are ignored but we - // reuse the HIR identifier pattern which requires it - HIR::SelfParam &self_param = function.get_self_param (); - HIR::IdentifierPattern *self_pattern = new HIR::IdentifierPattern ( - mapping, "self", self_param.get_locus (), self_param.is_ref (), - self_param.get_mut (), std::unique_ptr<HIR::Pattern> (nullptr)); - - // might have a specified type - TyTy::BaseType *self_type = nullptr; - if (self_param.has_type ()) - { - std::unique_ptr<HIR::Type> &specified_type = self_param.get_type (); - self_type = TypeCheckType::Resolve (specified_type.get ()); - } - else - { - switch (self_param.get_self_kind ()) - { - case HIR::SelfParam::IMM: - case HIR::SelfParam::MUT: - self_type = self->clone (); - break; - - case HIR::SelfParam::IMM_REF: - self_type = new TyTy::ReferenceType ( - self_param.get_mappings ().get_hirid (), - TyTy::TyVar (self->get_ref ()), Mutability::Imm); - break; - - case HIR::SelfParam::MUT_REF: - self_type = new TyTy::ReferenceType ( - self_param.get_mappings ().get_hirid (), - TyTy::TyVar (self->get_ref ()), Mutability::Mut); - break; + std::vector<TyTy::SubstitutionParamMapping> substitutions); - default: - gcc_unreachable (); - return; - } - } - - context->insert_type (self_param.get_mappings (), self_type); - params.push_back ( - std::pair<HIR::Pattern *, TyTy::BaseType *> (self_pattern, - self_type)); - } - - for (auto ¶m : function.get_function_params ()) - { - // get the name as well required for later on - auto param_tyty = TypeCheckType::Resolve (param.get_type ()); - params.push_back ( - std::pair<HIR::Pattern *, TyTy::BaseType *> (param.get_param_name (), - param_tyty)); - - context->insert_type (param.get_mappings (), param_tyty); - TypeCheckPattern::Resolve (param.get_param_name (), param_tyty); - } - - const CanonicalPath *canonical_path = nullptr; - bool ok - = mappings->lookup_canonical_path (function.get_mappings ().get_nodeid (), - &canonical_path); - rust_assert (ok); - - RustIdent ident{*canonical_path, function.get_locus ()}; - auto fnType = new TyTy::FnType (function.get_mappings ().get_hirid (), - function.get_mappings ().get_defid (), - function.get_function_name (), ident, - function.is_method () - ? TyTy::FnType::FNTYPE_IS_METHOD_FLAG - : TyTy::FnType::FNTYPE_DEFAULT_FLAGS, - ABI::RUST, std::move (params), ret_type, - std::move (substitutions)); - - context->insert_type (function.get_mappings (), fnType); - } + void visit (HIR::TypeAlias &alias) override; + void visit (HIR::ConstantItem &constant) override; + void visit (HIR::Function &function) override; private: TypeCheckTopLevelImplItem ( TyTy::BaseType *self, - std::vector<TyTy::SubstitutionParamMapping> substitutions) - : TypeCheckBase (), self (self), substitutions (substitutions) - {} + std::vector<TyTy::SubstitutionParamMapping> substitutions); TyTy::BaseType *self; std::vector<TyTy::SubstitutionParamMapping> substitutions; }; -class TypeCheckImplItem : public TypeCheckBase +class TypeCheckImplItem : public TypeCheckBase, public HIR::HIRImplVisitor { public: - using Rust::Resolver::TypeCheckBase::visit; - static void Resolve (HIR::ImplBlock *parent, HIR::ImplItem *item, - TyTy::BaseType *self) - { - TypeCheckImplItem resolver (parent, self); - item->accept_vis (resolver); - } - - void visit (HIR::Function &function) override - { - TyTy::BaseType *lookup; - if (!context->lookup_type (function.get_mappings ().get_hirid (), &lookup)) - { - rust_error_at (function.get_locus (), "failed to lookup function type"); - return; - } - - if (lookup->get_kind () != TyTy::TypeKind::FNDEF) - { - rust_error_at (function.get_locus (), - "found invalid type for function [%s]", - lookup->as_string ().c_str ()); - return; - } + TyTy::BaseType *self); - // need to get the return type from this - TyTy::FnType *resolve_fn_type = static_cast<TyTy::FnType *> (lookup); - auto expected_ret_tyty = resolve_fn_type->get_return_type (); - context->push_return_type (TypeCheckContextItem (parent, &function), - expected_ret_tyty); - - auto block_expr_ty - = TypeCheckExpr::Resolve (function.get_definition ().get ()); - - context->pop_return_type (); - expected_ret_tyty->unify (block_expr_ty); - } + void visit (HIR::Function &function) override; + void visit (HIR::ConstantItem &const_item) override; + void visit (HIR::TypeAlias &type_alias) override; protected: - TypeCheckImplItem (HIR::ImplBlock *parent, TyTy::BaseType *self) - : TypeCheckBase (), parent (parent), self (self) - {} + TypeCheckImplItem (HIR::ImplBlock *parent, TyTy::BaseType *self); HIR::ImplBlock *parent; TyTy::BaseType *self; @@ -389,207 +79,29 @@ protected: class TypeCheckImplItemWithTrait : public TypeCheckImplItem { - using Rust::Resolver::TypeCheckBase::visit; - public: static TyTy::TypeBoundPredicateItem Resolve (HIR::ImplBlock *parent, HIR::ImplItem *item, TyTy::BaseType *self, TyTy::TypeBoundPredicate &trait_reference, - std::vector<TyTy::SubstitutionParamMapping> substitutions) - { - TypeCheckImplItemWithTrait resolver (parent, self, trait_reference, - substitutions); - item->accept_vis (resolver); - return resolver.resolved_trait_item; - } - - void visit (HIR::ConstantItem &constant) override - { - // normal resolution of the item - TypeCheckImplItem::visit (constant); - TyTy::BaseType *lookup; - if (!context->lookup_type (constant.get_mappings ().get_hirid (), &lookup)) - return; - - // map the impl item to the associated trait item - const auto tref = trait_reference.get (); - const TraitItemReference *raw_trait_item = nullptr; - bool found = tref->lookup_trait_item_by_type ( - constant.get_identifier (), TraitItemReference::TraitItemType::CONST, - &raw_trait_item); - - // unknown trait item - if (!found || raw_trait_item->is_error ()) - { - RichLocation r (constant.get_locus ()); - r.add_range (trait_reference.get_locus ()); - rust_error_at (r, "constant %<%s%> is not a member of trait %<%s%>", - constant.get_identifier ().c_str (), - trait_reference.get_name ().c_str ()); - return; - } - - // get the item from the predicate - resolved_trait_item - = trait_reference.lookup_associated_item (raw_trait_item); - rust_assert (!resolved_trait_item.is_error ()); - - // merge the attributes - const HIR::TraitItem *hir_trait_item - = resolved_trait_item.get_raw_item ()->get_hir_trait_item (); - merge_attributes (constant.get_outer_attrs (), *hir_trait_item); - - // check the types are compatible - auto trait_item_type = resolved_trait_item.get_tyty_for_receiver (self); - if (!trait_item_type->can_eq (lookup, true)) - { - RichLocation r (constant.get_locus ()); - r.add_range (resolved_trait_item.get_locus ()); - - rust_error_at ( - r, "constant %<%s%> has an incompatible type for trait %<%s%>", - constant.get_identifier ().c_str (), - trait_reference.get_name ().c_str ()); - } - } - - void visit (HIR::TypeAlias &type) override - { - // normal resolution of the item - TypeCheckImplItem::visit (type); - TyTy::BaseType *lookup; - if (!context->lookup_type (type.get_mappings ().get_hirid (), &lookup)) - return; - - // map the impl item to the associated trait item - const auto tref = trait_reference.get (); - const TraitItemReference *raw_trait_item = nullptr; - bool found = tref->lookup_trait_item_by_type ( - type.get_new_type_name (), TraitItemReference::TraitItemType::TYPE, - &raw_trait_item); - - // unknown trait item - if (!found || raw_trait_item->is_error ()) - { - RichLocation r (type.get_locus ()); - r.add_range (trait_reference.get_locus ()); - rust_error_at (r, "type alias %<%s%> is not a member of trait %<%s%>", - type.get_new_type_name ().c_str (), - trait_reference.get_name ().c_str ()); - return; - } - - // get the item from the predicate - resolved_trait_item - = trait_reference.lookup_associated_item (raw_trait_item); - rust_assert (!resolved_trait_item.is_error ()); - - // merge the attributes - const HIR::TraitItem *hir_trait_item - = resolved_trait_item.get_raw_item ()->get_hir_trait_item (); - merge_attributes (type.get_outer_attrs (), *hir_trait_item); - - // check the types are compatible - auto trait_item_type = resolved_trait_item.get_tyty_for_receiver (self); - if (!trait_item_type->can_eq (lookup, true)) - { - RichLocation r (type.get_locus ()); - r.add_range (resolved_trait_item.get_locus ()); - - rust_error_at ( - r, "type alias %<%s%> has an incompatible type for trait %<%s%>", - type.get_new_type_name ().c_str (), - trait_reference.get_name ().c_str ()); - } - - // 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 (type.get_mappings ().get_hirid (), lookup, - tref, - raw_trait_item->get_mappings ().get_defid (), - substitutions); - - context->insert_type (type.get_mappings (), projection); - raw_trait_item->associated_type_set (projection); - } - - void visit (HIR::Function &function) override - { - // we get the error checking from the base method here - TypeCheckImplItem::visit (function); - TyTy::BaseType *lookup; - if (!context->lookup_type (function.get_mappings ().get_hirid (), &lookup)) - return; - - // map the impl item to the associated trait item - const auto tref = trait_reference.get (); - const TraitItemReference *raw_trait_item = nullptr; - bool found - = tref->lookup_trait_item_by_type (function.get_function_name (), - TraitItemReference::TraitItemType::FN, - &raw_trait_item); - - // unknown trait item - if (!found || raw_trait_item->is_error ()) - { - RichLocation r (function.get_locus ()); - r.add_range (trait_reference.get_locus ()); - rust_error_at (r, "method %<%s%> is not a member of trait %<%s%>", - function.get_function_name ().c_str (), - trait_reference.get_name ().c_str ()); - return; - } - - // get the item from the predicate - resolved_trait_item - = trait_reference.lookup_associated_item (raw_trait_item); - rust_assert (!resolved_trait_item.is_error ()); - - // merge the attributes - const HIR::TraitItem *hir_trait_item - = resolved_trait_item.get_raw_item ()->get_hir_trait_item (); - merge_attributes (function.get_outer_attrs (), *hir_trait_item); - - // check the types are compatible - auto trait_item_type = resolved_trait_item.get_tyty_for_receiver (self); - if (!trait_item_type->can_eq (lookup, true)) - { - RichLocation r (function.get_locus ()); - r.add_range (resolved_trait_item.get_locus ()); + std::vector<TyTy::SubstitutionParamMapping> substitutions); - rust_error_at ( - r, "method %<%s%> has an incompatible type for trait %<%s%>", - function.get_function_name ().c_str (), - trait_reference.get_name ().c_str ()); - } - } + void visit (HIR::ConstantItem &constant) override; + void visit (HIR::TypeAlias &type) override; + void visit (HIR::Function &function) override; protected: // this allows us to inherit the must_use specified on a trait definition onto // its implementation void merge_attributes (AST::AttrVec &impl_item_attrs, - const HIR::TraitItem &trait_item) - { - for (const auto &attr : trait_item.get_outer_attrs ()) - { - impl_item_attrs.push_back (attr); - } - } + const HIR::TraitItem &trait_item); private: TypeCheckImplItemWithTrait ( HIR::ImplBlock *parent, TyTy::BaseType *self, TyTy::TypeBoundPredicate &trait_reference, - std::vector<TyTy::SubstitutionParamMapping> substitutions) - : TypeCheckImplItem (parent, self), trait_reference (trait_reference), - resolved_trait_item (TyTy::TypeBoundPredicateItem::error ()), - substitutions (substitutions) - { - rust_assert (is_trait_impl_block ()); - } + std::vector<TyTy::SubstitutionParamMapping> substitutions); - bool is_trait_impl_block () const { return !trait_reference.is_error (); } + bool is_trait_impl_block () const; TyTy::TypeBoundPredicate &trait_reference; TyTy::TypeBoundPredicateItem resolved_trait_item; diff --git a/gcc/rust/typecheck/rust-hir-type-check-item.cc b/gcc/rust/typecheck/rust-hir-type-check-item.cc index 28cac51..d31a6df 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-item.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-item.cc @@ -17,15 +17,26 @@ // <http://www.gnu.org/licenses/>. #include "rust-hir-type-check-item.h" +#include "rust-hir-full.h" +#include "rust-hir-type-check-implitem.h" +#include "rust-hir-type-check-type.h" +#include "rust-hir-type-check-stmt.h" +#include "rust-hir-type-check-expr.h" +#include "rust-hir-trait-resolve.h" namespace Rust { - namespace Resolver { + +TypeCheckItem::TypeCheckItem () : TypeCheckBase () {} + void -TypeCheckItem::Resolve (HIR::Item *item) +TypeCheckItem::Resolve (HIR::Item &item) { + rust_assert (item.get_hir_kind () == HIR::Node::BaseKind::VIS_ITEM); + HIR::VisItem &vis_item = static_cast<HIR::VisItem &> (item); + TypeCheckItem resolver; - item->accept_vis (resolver); + vis_item.accept_vis (resolver); } void @@ -213,7 +224,7 @@ void TypeCheckItem::visit (HIR::Module &module) { for (auto &item : module.get_items ()) - TypeCheckItem::Resolve (item.get ()); + TypeCheckItem::Resolve (*item.get ()); } void diff --git a/gcc/rust/typecheck/rust-hir-type-check-item.h b/gcc/rust/typecheck/rust-hir-type-check-item.h index b9a0d9b..ba4de19 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-item.h +++ b/gcc/rust/typecheck/rust-hir-type-check-item.h @@ -20,30 +20,36 @@ #define RUST_HIR_TYPE_CHECK_ITEM #include "rust-hir-type-check-base.h" -#include "rust-hir-full.h" -#include "rust-hir-type-check-implitem.h" -#include "rust-hir-type-check-type.h" -#include "rust-hir-type-check-stmt.h" -#include "rust-hir-trait-resolve.h" -#include "rust-tyty-visitor.h" namespace Rust { namespace Resolver { -class TypeCheckItem : public TypeCheckBase +class TypeCheckItem : private TypeCheckBase, private HIR::HIRVisItemVisitor { - using Rust::Resolver::TypeCheckBase::visit; - public: - static void Resolve (HIR::Item *item); + static void Resolve (HIR::Item &item); void visit (HIR::ImplBlock &impl_block) override; void visit (HIR::Function &function) override; void visit (HIR::Module &module) override; void visit (HIR::Trait &trait) override; + // FIXME - get rid of toplevel pass + void visit (HIR::TypeAlias &alias) override{}; + void visit (HIR::TupleStruct &struct_decl) override{}; + void visit (HIR::StructStruct &struct_decl) override{}; + void visit (HIR::Enum &enum_decl) override{}; + void visit (HIR::Union &union_decl) override{}; + void visit (HIR::StaticItem &var) override{}; + void visit (HIR::ConstantItem &constant) override{}; + void visit (HIR::ExternBlock &extern_block) override{}; + + // nothing to do + void visit (HIR::ExternCrate &crate) override {} + void visit (HIR::UseDeclaration &use_decl) override {} + private: - TypeCheckItem () : TypeCheckBase () {} + TypeCheckItem (); }; } // namespace Resolver diff --git a/gcc/rust/typecheck/rust-hir-type-check-path.cc b/gcc/rust/typecheck/rust-hir-type-check-path.cc index ac1ebfd..fd0ca3e 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-path.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-path.cc @@ -17,6 +17,8 @@ // <http://www.gnu.org/licenses/>. #include "rust-hir-type-check-expr.h" +#include "rust-hir-type-check-type.h" +#include "rust-hir-trait-resolve.h" namespace Rust { namespace Resolver { diff --git a/gcc/rust/typecheck/rust-hir-type-check-pattern.cc b/gcc/rust/typecheck/rust-hir-type-check-pattern.cc index df312af..a62fbc9 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-pattern.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-pattern.cc @@ -22,6 +22,24 @@ namespace Rust { namespace Resolver { +TypeCheckPattern::TypeCheckPattern (TyTy::BaseType *parent) + : TypeCheckBase (), parent (parent), infered (nullptr) +{} + +TyTy::BaseType * +TypeCheckPattern::Resolve (HIR::Pattern *pattern, TyTy::BaseType *parent) +{ + TypeCheckPattern resolver (parent); + pattern->accept_vis (resolver); + + if (resolver.infered == nullptr) + return new TyTy::ErrorType (pattern->get_pattern_mappings ().get_hirid ()); + + resolver.context->insert_type (pattern->get_pattern_mappings (), + resolver.infered); + return resolver.infered; +} + void TypeCheckPattern::visit (HIR::PathInExpression &pattern) { @@ -357,5 +375,33 @@ TypeCheckPattern::visit (HIR::IdentifierPattern &pattern) infered = parent; } +void +TypeCheckPattern::visit (HIR::GroupedPattern &pattern) +{ + // TODO + gcc_unreachable (); +} + +void +TypeCheckPattern::visit (HIR::QualifiedPathInExpression &pattern) +{ + // TODO + gcc_unreachable (); +} + +void +TypeCheckPattern::visit (HIR::ReferencePattern &pattern) +{ + // TODO + gcc_unreachable (); +} + +void +TypeCheckPattern::visit (HIR::SlicePattern &pattern) +{ + // TODO + gcc_unreachable (); +} + } // namespace Resolver } // namespace Rust diff --git a/gcc/rust/typecheck/rust-hir-type-check-pattern.h b/gcc/rust/typecheck/rust-hir-type-check-pattern.h index 860aca9..8af1060 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-pattern.h +++ b/gcc/rust/typecheck/rust-hir-type-check-pattern.h @@ -25,45 +25,27 @@ namespace Rust { namespace Resolver { -class TypeCheckPattern : public TypeCheckBase +class TypeCheckPattern : public TypeCheckBase, public HIR::HIRPatternVisitor { - using Rust::Resolver::TypeCheckBase::visit; - public: - static TyTy::BaseType *Resolve (HIR::Pattern *pattern, TyTy::BaseType *parent) - { - TypeCheckPattern resolver (parent); - pattern->accept_vis (resolver); - - if (resolver.infered == nullptr) - return new TyTy::ErrorType ( - pattern->get_pattern_mappings ().get_hirid ()); - - resolver.context->insert_type (pattern->get_pattern_mappings (), - resolver.infered); - return resolver.infered; - } + static TyTy::BaseType *Resolve (HIR::Pattern *pattern, + TyTy::BaseType *parent); void visit (HIR::PathInExpression &pattern) override; - void visit (HIR::StructPattern &pattern) override; - void visit (HIR::TupleStructPattern &pattern) override; - void visit (HIR::WildcardPattern &pattern) override; - void visit (HIR::TuplePattern &pattern) override; - void visit (HIR::LiteralPattern &pattern) override; - void visit (HIR::RangePattern &pattern) override; - void visit (HIR::IdentifierPattern &pattern) override; + void visit (HIR::GroupedPattern &pattern) override; + void visit (HIR::QualifiedPathInExpression &pattern) override; + void visit (HIR::ReferencePattern &pattern) override; + void visit (HIR::SlicePattern &pattern) override; private: - TypeCheckPattern (TyTy::BaseType *parent) - : TypeCheckBase (), parent (parent), infered (nullptr) - {} + TypeCheckPattern (TyTy::BaseType *parent); static TyTy::BaseType * typecheck_range_pattern_bound (HIR::RangePatternBound *bound, diff --git a/gcc/rust/typecheck/rust-hir-type-check-stmt.cc b/gcc/rust/typecheck/rust-hir-type-check-stmt.cc new file mode 100644 index 0000000..9f34ed4 --- /dev/null +++ b/gcc/rust/typecheck/rust-hir-type-check-stmt.cc @@ -0,0 +1,498 @@ +// Copyright (C) 2020-2022 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-stmt.h" +#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" +#include "rust-hir-type-check-implitem.h" +#include "rust-hir-type-check-pattern.h" + +namespace Rust { +namespace Resolver { + +TyTy::BaseType * +TypeCheckStmt::Resolve (HIR::Stmt *stmt) +{ + TypeCheckStmt resolver; + stmt->accept_vis (resolver); + return resolver.infered; +} + +void +TypeCheckStmt::visit (HIR::ExprStmtWithBlock &stmt) +{ + infered = TypeCheckExpr::Resolve (stmt.get_expr ()); +} + +void +TypeCheckStmt::visit (HIR::ExprStmtWithoutBlock &stmt) +{ + infered = TypeCheckExpr::Resolve (stmt.get_expr ()); +} + +void +TypeCheckStmt::visit (HIR::EmptyStmt &stmt) +{ + infered = TyTy::TupleType::get_unit_type (stmt.get_mappings ().get_hirid ()); +} + +void +TypeCheckStmt::visit (HIR::ExternBlock &extern_block) +{ + for (auto &item : extern_block.get_extern_items ()) + { + TypeCheckTopLevelExternItem::Resolve (item.get (), extern_block); + } +} + +void +TypeCheckStmt::visit (HIR::ConstantItem &constant) +{ + TyTy::BaseType *type = TypeCheckType::Resolve (constant.get_type ()); + TyTy::BaseType *expr_type = TypeCheckExpr::Resolve (constant.get_expr ()); + + infered = type->unify (expr_type); + context->insert_type (constant.get_mappings (), infered); +} + +void +TypeCheckStmt::visit (HIR::LetStmt &stmt) +{ + infered = TyTy::TupleType::get_unit_type (stmt.get_mappings ().get_hirid ()); + + const HIR::Pattern &stmt_pattern = *stmt.get_pattern (); + TyTy::BaseType *init_expr_ty = nullptr; + if (stmt.has_init_expr ()) + { + init_expr_ty = TypeCheckExpr::Resolve (stmt.get_init_expr ()); + if (init_expr_ty->get_kind () == TyTy::TypeKind::ERROR) + return; + + init_expr_ty->append_reference ( + stmt_pattern.get_pattern_mappings ().get_hirid ()); + } + + TyTy::BaseType *specified_ty = nullptr; + if (stmt.has_type ()) + specified_ty = TypeCheckType::Resolve (stmt.get_type ()); + + // let x:i32 = 123; + if (specified_ty != nullptr && init_expr_ty != nullptr) + { + // FIXME use this result and look at the regressions + coercion_site (stmt.get_mappings ().get_hirid (), specified_ty, + init_expr_ty, stmt.get_locus ()); + context->insert_type (stmt_pattern.get_pattern_mappings (), specified_ty); + } + else + { + // let x:i32; + if (specified_ty != nullptr) + { + context->insert_type (stmt_pattern.get_pattern_mappings (), + specified_ty); + } + // let x = 123; + else if (init_expr_ty != nullptr) + { + context->insert_type (stmt_pattern.get_pattern_mappings (), + init_expr_ty); + } + // let x; + else + { + context->insert_type ( + stmt_pattern.get_pattern_mappings (), + new TyTy::InferType ( + stmt_pattern.get_pattern_mappings ().get_hirid (), + TyTy::InferType::InferTypeKind::GENERAL, stmt.get_locus ())); + } + } +} + +void +TypeCheckStmt::visit (HIR::TupleStruct &struct_decl) +{ + std::vector<TyTy::SubstitutionParamMapping> substitutions; + if (struct_decl.has_generics ()) + { + for (auto &generic_param : struct_decl.get_generic_params ()) + { + switch (generic_param.get ()->get_kind ()) + { + case HIR::GenericParam::GenericKind::LIFETIME: + case HIR::GenericParam::GenericKind::CONST: + // FIXME: Skipping Lifetime and Const 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::StructFieldType *> fields; + size_t idx = 0; + for (auto &field : struct_decl.get_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++; + } + + // get the path + const CanonicalPath *canonical_path = nullptr; + bool ok = mappings->lookup_canonical_path ( + struct_decl.get_mappings ().get_nodeid (), &canonical_path); + rust_assert (ok); + RustIdent ident{*canonical_path, struct_decl.get_locus ()}; + + // 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 (), + ident, TyTy::VariantDef::VariantType::TUPLE, nullptr, std::move (fields))); + + // Process #[repr(...)] attribute, if any + const AST::AttrVec &attrs = struct_decl.get_outer_attrs (); + TyTy::ADTType::ReprOptions repr + = parse_repr_options (attrs, struct_decl.get_locus ()); + + TyTy::BaseType *type + = new TyTy::ADTType (struct_decl.get_mappings ().get_hirid (), + mappings->get_next_hir_id (), + struct_decl.get_identifier (), ident, + TyTy::ADTType::ADTKind::TUPLE_STRUCT, + std::move (variants), std::move (substitutions), repr); + + context->insert_type (struct_decl.get_mappings (), type); + infered = type; +} + +void +TypeCheckStmt::visit (HIR::Enum &enum_decl) +{ + 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: + case HIR::GenericParam::GenericKind::CONST: + // FIXME: Skipping Lifetime and Const 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); + + discriminant_value++; + variants.push_back (field_type); + } + + // get the path + const CanonicalPath *canonical_path = nullptr; + bool ok + = mappings->lookup_canonical_path (enum_decl.get_mappings ().get_nodeid (), + &canonical_path); + rust_assert (ok); + RustIdent ident{*canonical_path, enum_decl.get_locus ()}; + + TyTy::BaseType *type + = new TyTy::ADTType (enum_decl.get_mappings ().get_hirid (), + mappings->get_next_hir_id (), + enum_decl.get_identifier (), ident, + TyTy::ADTType::ADTKind::ENUM, std::move (variants), + std::move (substitutions)); + + context->insert_type (enum_decl.get_mappings (), type); + infered = type; +} + +void +TypeCheckStmt::visit (HIR::StructStruct &struct_decl) +{ + std::vector<TyTy::SubstitutionParamMapping> substitutions; + if (struct_decl.has_generics ()) + { + for (auto &generic_param : struct_decl.get_generic_params ()) + { + switch (generic_param.get ()->get_kind ()) + { + case HIR::GenericParam::GenericKind::LIFETIME: + case HIR::GenericParam::GenericKind::CONST: + // FIXME: Skipping Lifetime and Const 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::StructFieldType *> fields; + for (auto &field : struct_decl.get_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 ()); + } + + // get the path + const CanonicalPath *canonical_path = nullptr; + bool ok = mappings->lookup_canonical_path ( + struct_decl.get_mappings ().get_nodeid (), &canonical_path); + rust_assert (ok); + RustIdent ident{*canonical_path, struct_decl.get_locus ()}; + + // 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 (), + ident, TyTy::VariantDef::VariantType::STRUCT, nullptr, std::move (fields))); + + // Process #[repr(...)] attribute, if any + const AST::AttrVec &attrs = struct_decl.get_outer_attrs (); + TyTy::ADTType::ReprOptions repr + = parse_repr_options (attrs, struct_decl.get_locus ()); + + TyTy::BaseType *type + = new TyTy::ADTType (struct_decl.get_mappings ().get_hirid (), + mappings->get_next_hir_id (), + struct_decl.get_identifier (), ident, + TyTy::ADTType::ADTKind::STRUCT_STRUCT, + std::move (variants), std::move (substitutions), repr); + + context->insert_type (struct_decl.get_mappings (), type); + infered = type; +} + +void +TypeCheckStmt::visit (HIR::Union &union_decl) +{ + std::vector<TyTy::SubstitutionParamMapping> substitutions; + if (union_decl.has_generics ()) + { + for (auto &generic_param : union_decl.get_generic_params ()) + { + switch (generic_param.get ()->get_kind ()) + { + case HIR::GenericParam::GenericKind::LIFETIME: + case HIR::GenericParam::GenericKind::CONST: + // FIXME: Skipping Lifetime and Const 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::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 ()); + } + + // get the path + const CanonicalPath *canonical_path = nullptr; + bool ok + = mappings->lookup_canonical_path (union_decl.get_mappings ().get_nodeid (), + &canonical_path); + rust_assert (ok); + RustIdent ident{*canonical_path, union_decl.get_locus ()}; + + // 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 (), + ident, TyTy::VariantDef::VariantType::STRUCT, nullptr, std::move (fields))); + + TyTy::BaseType *type + = new TyTy::ADTType (union_decl.get_mappings ().get_hirid (), + mappings->get_next_hir_id (), + union_decl.get_identifier (), ident, + TyTy::ADTType::ADTKind::UNION, std::move (variants), + std::move (substitutions)); + + context->insert_type (union_decl.get_mappings (), type); + infered = type; +} + +void +TypeCheckStmt::visit (HIR::Function &function) +{ + std::vector<TyTy::SubstitutionParamMapping> substitutions; + if (function.has_generics ()) + { + for (auto &generic_param : function.get_generic_params ()) + { + switch (generic_param.get ()->get_kind ()) + { + case HIR::GenericParam::GenericKind::LIFETIME: + case HIR::GenericParam::GenericKind::CONST: + // FIXME: Skipping Lifetime and Const 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; + } + } + } + + TyTy::BaseType *ret_type = nullptr; + if (!function.has_function_return_type ()) + ret_type + = TyTy::TupleType::get_unit_type (function.get_mappings ().get_hirid ()); + else + { + auto resolved + = TypeCheckType::Resolve (function.get_return_type ().get ()); + if (resolved == nullptr) + { + rust_error_at (function.get_locus (), + "failed to resolve return type"); + return; + } + + ret_type = resolved->clone (); + ret_type->set_ref ( + function.get_return_type ()->get_mappings ().get_hirid ()); + } + + std::vector<std::pair<HIR::Pattern *, TyTy::BaseType *> > params; + for (auto ¶m : function.get_function_params ()) + { + // get the name as well required for later on + auto param_tyty = TypeCheckType::Resolve (param.get_type ()); + params.push_back ( + std::pair<HIR::Pattern *, TyTy::BaseType *> (param.get_param_name (), + param_tyty)); + + context->insert_type (param.get_mappings (), param_tyty); + TypeCheckPattern::Resolve (param.get_param_name (), param_tyty); + } + + // get the path + const CanonicalPath *canonical_path = nullptr; + bool ok + = mappings->lookup_canonical_path (function.get_mappings ().get_nodeid (), + &canonical_path); + rust_assert (ok); + + RustIdent ident{*canonical_path, function.get_locus ()}; + auto fnType = new TyTy::FnType (function.get_mappings ().get_hirid (), + function.get_mappings ().get_defid (), + function.get_function_name (), ident, + TyTy::FnType::FNTYPE_DEFAULT_FLAGS, ABI::RUST, + std::move (params), ret_type, + std::move (substitutions)); + context->insert_type (function.get_mappings (), fnType); + + TyTy::FnType *resolved_fn_type = fnType; + auto expected_ret_tyty = resolved_fn_type->get_return_type (); + context->push_return_type (TypeCheckContextItem (&function), + expected_ret_tyty); + + auto block_expr_ty + = TypeCheckExpr::Resolve (function.get_definition ().get ()); + + context->pop_return_type (); + + if (block_expr_ty->get_kind () != TyTy::NEVER) + expected_ret_tyty->unify (block_expr_ty); + + infered = fnType; +} + +} // namespace Resolver +} // namespace Rust diff --git a/gcc/rust/typecheck/rust-hir-type-check-stmt.h b/gcc/rust/typecheck/rust-hir-type-check-stmt.h index f8bf6e0..a79f17a 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-stmt.h +++ b/gcc/rust/typecheck/rust-hir-type-check-stmt.h @@ -20,489 +20,68 @@ #define RUST_HIR_TYPE_CHECK_STMT #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" -#include "rust-hir-type-check-enumitem.h" -#include "rust-hir-type-check-implitem.h" namespace Rust { namespace Resolver { -class TypeCheckStmt : public TypeCheckBase +class TypeCheckStmt : private TypeCheckBase, private HIR::HIRStmtVisitor { - using Rust::Resolver::TypeCheckBase::visit; - public: - static TyTy::BaseType *Resolve (HIR::Stmt *stmt) - { - TypeCheckStmt resolver; - stmt->accept_vis (resolver); - return resolver.infered; + static TyTy::BaseType *Resolve (HIR::Stmt *stmt); + + void visit (HIR::ExprStmtWithBlock &stmt) override; + void visit (HIR::ExprStmtWithoutBlock &stmt) override; + void visit (HIR::EmptyStmt &stmt) override; + void visit (HIR::ExternBlock &extern_block) override; + void visit (HIR::ConstantItem &constant) override; + void visit (HIR::LetStmt &stmt) override; + void visit (HIR::TupleStruct &struct_decl) override; + void visit (HIR::Enum &enum_decl) override; + void visit (HIR::StructStruct &struct_decl) override; + void visit (HIR::Union &union_decl) override; + void visit (HIR::Function &function) override; + + void visit (HIR::EnumItemTuple &) override + { /* TODO? */ } - - void visit (HIR::ExprStmtWithBlock &stmt) override - { - infered = TypeCheckExpr::Resolve (stmt.get_expr ()); + void visit (HIR::EnumItemStruct &) override + { /* TODO? */ } - - void visit (HIR::ExprStmtWithoutBlock &stmt) override - { - infered = TypeCheckExpr::Resolve (stmt.get_expr ()); + void visit (HIR::EnumItem &item) override + { /* TODO? */ } - - void visit (HIR::EmptyStmt &stmt) override - { - infered - = TyTy::TupleType::get_unit_type (stmt.get_mappings ().get_hirid ()); + void visit (HIR::EnumItemDiscriminant &) override + { /* TODO? */ } - - void visit (HIR::ExternBlock &extern_block) override - { - for (auto &item : extern_block.get_extern_items ()) - { - TypeCheckTopLevelExternItem::Resolve (item.get (), extern_block); - } + void visit (HIR::TypePathSegmentFunction &segment) override + { /* TODO? */ } - - void visit (HIR::ConstantItem &constant) override - { - TyTy::BaseType *type = TypeCheckType::Resolve (constant.get_type ()); - TyTy::BaseType *expr_type = TypeCheckExpr::Resolve (constant.get_expr ()); - - infered = type->unify (expr_type); - context->insert_type (constant.get_mappings (), infered); + void visit (HIR::TypePath &path) override + { /* TODO? */ } - - void visit (HIR::LetStmt &stmt) override - { - infered - = TyTy::TupleType::get_unit_type (stmt.get_mappings ().get_hirid ()); - - const HIR::Pattern &stmt_pattern = *stmt.get_pattern (); - TyTy::BaseType *init_expr_ty = nullptr; - if (stmt.has_init_expr ()) - { - init_expr_ty = TypeCheckExpr::Resolve (stmt.get_init_expr ()); - if (init_expr_ty->get_kind () == TyTy::TypeKind::ERROR) - return; - - init_expr_ty->append_reference ( - stmt_pattern.get_pattern_mappings ().get_hirid ()); - } - - TyTy::BaseType *specified_ty = nullptr; - if (stmt.has_type ()) - specified_ty = TypeCheckType::Resolve (stmt.get_type ()); - - // let x:i32 = 123; - if (specified_ty != nullptr && init_expr_ty != nullptr) - { - // FIXME use this result and look at the regressions - coercion_site (stmt.get_mappings ().get_hirid (), specified_ty, - init_expr_ty, stmt.get_locus ()); - context->insert_type (stmt_pattern.get_pattern_mappings (), - specified_ty); - } - else - { - // let x:i32; - if (specified_ty != nullptr) - { - context->insert_type (stmt_pattern.get_pattern_mappings (), - specified_ty); - } - // let x = 123; - else if (init_expr_ty != nullptr) - { - context->insert_type (stmt_pattern.get_pattern_mappings (), - init_expr_ty); - } - // let x; - else - { - context->insert_type ( - stmt_pattern.get_pattern_mappings (), - new TyTy::InferType ( - stmt_pattern.get_pattern_mappings ().get_hirid (), - TyTy::InferType::InferTypeKind::GENERAL, stmt.get_locus ())); - } - } + void visit (HIR::QualifiedPathInType &path) override + { /* TODO? */ } - - void visit (HIR::TupleStruct &struct_decl) override - { - std::vector<TyTy::SubstitutionParamMapping> substitutions; - if (struct_decl.has_generics ()) - { - for (auto &generic_param : struct_decl.get_generic_params ()) - { - switch (generic_param.get ()->get_kind ()) - { - case HIR::GenericParam::GenericKind::LIFETIME: - case HIR::GenericParam::GenericKind::CONST: - // FIXME: Skipping Lifetime and Const 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::StructFieldType *> fields; - size_t idx = 0; - for (auto &field : struct_decl.get_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++; - } - - // get the path - const CanonicalPath *canonical_path = nullptr; - bool ok = mappings->lookup_canonical_path ( - struct_decl.get_mappings ().get_nodeid (), &canonical_path); - rust_assert (ok); - RustIdent ident{*canonical_path, struct_decl.get_locus ()}; - - // 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 (), ident, - TyTy::VariantDef::VariantType::TUPLE, nullptr, - std::move (fields))); - - // Process #[repr(...)] attribute, if any - const AST::AttrVec &attrs = struct_decl.get_outer_attrs (); - TyTy::ADTType::ReprOptions repr - = parse_repr_options (attrs, struct_decl.get_locus ()); - - TyTy::BaseType *type - = new TyTy::ADTType (struct_decl.get_mappings ().get_hirid (), - mappings->get_next_hir_id (), - struct_decl.get_identifier (), ident, - TyTy::ADTType::ADTKind::TUPLE_STRUCT, - std::move (variants), std::move (substitutions), - repr); - - context->insert_type (struct_decl.get_mappings (), type); - infered = type; + void visit (HIR::Module &module) override + { /* TODO? */ } - - 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: - case HIR::GenericParam::GenericKind::CONST: - // FIXME: Skipping Lifetime and Const 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); - - discriminant_value++; - variants.push_back (field_type); - } - - // get the path - const CanonicalPath *canonical_path = nullptr; - bool ok = mappings->lookup_canonical_path ( - enum_decl.get_mappings ().get_nodeid (), &canonical_path); - rust_assert (ok); - RustIdent ident{*canonical_path, enum_decl.get_locus ()}; - - TyTy::BaseType *type - = new TyTy::ADTType (enum_decl.get_mappings ().get_hirid (), - mappings->get_next_hir_id (), - enum_decl.get_identifier (), ident, - TyTy::ADTType::ADTKind::ENUM, std::move (variants), - std::move (substitutions)); - - context->insert_type (enum_decl.get_mappings (), type); - infered = type; + void visit (HIR::ExternCrate &crate) override + { /* TODO? */ } - - void visit (HIR::StructStruct &struct_decl) override - { - std::vector<TyTy::SubstitutionParamMapping> substitutions; - if (struct_decl.has_generics ()) - { - for (auto &generic_param : struct_decl.get_generic_params ()) - { - switch (generic_param.get ()->get_kind ()) - { - case HIR::GenericParam::GenericKind::LIFETIME: - case HIR::GenericParam::GenericKind::CONST: - // FIXME: Skipping Lifetime and Const 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::StructFieldType *> fields; - for (auto &field : struct_decl.get_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 ()); - } - - // get the path - const CanonicalPath *canonical_path = nullptr; - bool ok = mappings->lookup_canonical_path ( - struct_decl.get_mappings ().get_nodeid (), &canonical_path); - rust_assert (ok); - RustIdent ident{*canonical_path, struct_decl.get_locus ()}; - - // 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 (), ident, - TyTy::VariantDef::VariantType::STRUCT, nullptr, - std::move (fields))); - - // Process #[repr(...)] attribute, if any - const AST::AttrVec &attrs = struct_decl.get_outer_attrs (); - TyTy::ADTType::ReprOptions repr - = parse_repr_options (attrs, struct_decl.get_locus ()); - - TyTy::BaseType *type - = new TyTy::ADTType (struct_decl.get_mappings ().get_hirid (), - mappings->get_next_hir_id (), - struct_decl.get_identifier (), ident, - TyTy::ADTType::ADTKind::STRUCT_STRUCT, - std::move (variants), std::move (substitutions), - repr); - - context->insert_type (struct_decl.get_mappings (), type); - infered = type; + void visit (HIR::UseDeclaration &use_decl) override + { /* TODO? */ } - - void visit (HIR::Union &union_decl) override - { - std::vector<TyTy::SubstitutionParamMapping> substitutions; - if (union_decl.has_generics ()) - { - for (auto &generic_param : union_decl.get_generic_params ()) - { - switch (generic_param.get ()->get_kind ()) - { - case HIR::GenericParam::GenericKind::LIFETIME: - case HIR::GenericParam::GenericKind::CONST: - // FIXME: Skipping Lifetime and Const 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::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 ()); - } - - // get the path - const CanonicalPath *canonical_path = nullptr; - bool ok = mappings->lookup_canonical_path ( - union_decl.get_mappings ().get_nodeid (), &canonical_path); - rust_assert (ok); - RustIdent ident{*canonical_path, union_decl.get_locus ()}; - - // 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 (), ident, - TyTy::VariantDef::VariantType::STRUCT, nullptr, - std::move (fields))); - - TyTy::BaseType *type - = new TyTy::ADTType (union_decl.get_mappings ().get_hirid (), - mappings->get_next_hir_id (), - union_decl.get_identifier (), ident, - TyTy::ADTType::ADTKind::UNION, std::move (variants), - std::move (substitutions)); - - context->insert_type (union_decl.get_mappings (), type); - infered = type; + void visit (HIR::TypeAlias &type_alias) override + { /* TODO? */ } - - void visit (HIR::Function &function) override - { - std::vector<TyTy::SubstitutionParamMapping> substitutions; - if (function.has_generics ()) - { - for (auto &generic_param : function.get_generic_params ()) - { - switch (generic_param.get ()->get_kind ()) - { - case HIR::GenericParam::GenericKind::LIFETIME: - case HIR::GenericParam::GenericKind::CONST: - // FIXME: Skipping Lifetime and Const 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; - } - } - } - - TyTy::BaseType *ret_type = nullptr; - if (!function.has_function_return_type ()) - ret_type = TyTy::TupleType::get_unit_type ( - function.get_mappings ().get_hirid ()); - else - { - auto resolved - = TypeCheckType::Resolve (function.get_return_type ().get ()); - if (resolved == nullptr) - { - rust_error_at (function.get_locus (), - "failed to resolve return type"); - return; - } - - ret_type = resolved->clone (); - ret_type->set_ref ( - function.get_return_type ()->get_mappings ().get_hirid ()); - } - - std::vector<std::pair<HIR::Pattern *, TyTy::BaseType *> > params; - for (auto ¶m : function.get_function_params ()) - { - // get the name as well required for later on - auto param_tyty = TypeCheckType::Resolve (param.get_type ()); - params.push_back ( - std::pair<HIR::Pattern *, TyTy::BaseType *> (param.get_param_name (), - param_tyty)); - - context->insert_type (param.get_mappings (), param_tyty); - TypeCheckPattern::Resolve (param.get_param_name (), param_tyty); - } - - // get the path - const CanonicalPath *canonical_path = nullptr; - bool ok - = mappings->lookup_canonical_path (function.get_mappings ().get_nodeid (), - &canonical_path); - rust_assert (ok); - - RustIdent ident{*canonical_path, function.get_locus ()}; - auto fnType = new TyTy::FnType (function.get_mappings ().get_hirid (), - function.get_mappings ().get_defid (), - function.get_function_name (), ident, - TyTy::FnType::FNTYPE_DEFAULT_FLAGS, - ABI::RUST, std::move (params), ret_type, - std::move (substitutions)); - context->insert_type (function.get_mappings (), fnType); - - TyTy::FnType *resolved_fn_type = fnType; - auto expected_ret_tyty = resolved_fn_type->get_return_type (); - context->push_return_type (TypeCheckContextItem (&function), - expected_ret_tyty); - - auto block_expr_ty - = TypeCheckExpr::Resolve (function.get_definition ().get ()); - - context->pop_return_type (); - - if (block_expr_ty->get_kind () != TyTy::NEVER) - expected_ret_tyty->unify (block_expr_ty); - - infered = fnType; + void visit (HIR::StaticItem &static_item) override + { /* TODO? */ + } + void visit (HIR::Trait &trait) override + { /* TODO? */ + } + void visit (HIR::ImplBlock &impl) override + { /* TODO? */ } private: 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 014489d..22af1aa 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-struct-field.h +++ b/gcc/rust/typecheck/rust-hir-type-check-struct-field.h @@ -29,31 +29,18 @@ namespace Resolver { class TypeCheckStructExpr : public TypeCheckBase { - using Rust::Resolver::TypeCheckBase::visit; - public: - static TyTy::BaseType *Resolve (HIR::StructExprStructFields *expr) - { - TypeCheckStructExpr resolver (expr); - expr->accept_vis (resolver); - return resolver.resolved; - } - - void visit (HIR::StructExprStructFields &struct_expr) override; - - void visit (HIR::StructExprFieldIdentifierValue &field) override; + static TyTy::BaseType *Resolve (HIR::StructExprStructFields *expr); - void visit (HIR::StructExprFieldIndexValue &field) override; +protected: + void resolve (HIR::StructExprStructFields &struct_expr); - void visit (HIR::StructExprFieldIdentifier &field) override; + void visit (HIR::StructExprFieldIdentifierValue &field); + void visit (HIR::StructExprFieldIndexValue &field); + void visit (HIR::StructExprFieldIdentifier &field); private: - TypeCheckStructExpr (HIR::Expr *e) - : TypeCheckBase (), - resolved (new TyTy::ErrorType (e->get_mappings ().get_hirid ())), - struct_path_resolved (nullptr), - variant (&TyTy::VariantDef::get_error_node ()) - {} + TypeCheckStructExpr (HIR::Expr *e); // result TyTy::BaseType *resolved; diff --git a/gcc/rust/typecheck/rust-hir-type-check-struct.cc b/gcc/rust/typecheck/rust-hir-type-check-struct.cc index 5b52277..ec82442 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-struct.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-struct.cc @@ -24,8 +24,23 @@ namespace Rust { namespace Resolver { +TypeCheckStructExpr::TypeCheckStructExpr (HIR::Expr *e) + : TypeCheckBase (), + resolved (new TyTy::ErrorType (e->get_mappings ().get_hirid ())), + struct_path_resolved (nullptr), + variant (&TyTy::VariantDef::get_error_node ()) +{} + +TyTy::BaseType * +TypeCheckStructExpr::Resolve (HIR::StructExprStructFields *expr) +{ + TypeCheckStructExpr resolver (expr); + resolver.resolve (*expr); + return resolver.resolved; +} + void -TypeCheckStructExpr::visit (HIR::StructExprStructFields &struct_expr) +TypeCheckStructExpr::resolve (HIR::StructExprStructFields &struct_expr) { TyTy::BaseType *struct_path_ty = TypeCheckExpr::Resolve (&struct_expr.get_struct_name ()); @@ -77,7 +92,23 @@ TypeCheckStructExpr::visit (HIR::StructExprStructFields &struct_expr) for (auto &field : struct_expr.get_fields ()) { resolved_field_value_expr = nullptr; - field->accept_vis (*this); + + switch (field->get_kind ()) + { + case HIR::StructExprField::StructExprFieldKind::IDENTIFIER: + visit (static_cast<HIR::StructExprFieldIdentifier &> (*field.get ())); + break; + + case HIR::StructExprField::StructExprFieldKind::IDENTIFIER_VALUE: + visit ( + static_cast<HIR::StructExprFieldIdentifierValue &> (*field.get ())); + break; + + case HIR::StructExprField::StructExprFieldKind::INDEX_VALUE: + visit (static_cast<HIR::StructExprFieldIndexValue &> (*field.get ())); + break; + } + if (resolved_field_value_expr == nullptr) { rust_fatal_error (field->get_locus (), @@ -294,7 +325,7 @@ TypeCheckStructExpr::visit (HIR::StructExprFieldIdentifier &field) if (resolved_field_value_expr != nullptr) { - fields_assigned.insert (field.field_name); + fields_assigned.insert (field.get_field_name ()); adtFieldIndexToField[field_index] = &field; } } diff --git a/gcc/rust/typecheck/rust-hir-type-check-toplevel.cc b/gcc/rust/typecheck/rust-hir-type-check-toplevel.cc index d5270c9..27f36b6 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-toplevel.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-toplevel.cc @@ -17,15 +17,25 @@ // <http://www.gnu.org/licenses/>. #include "rust-hir-type-check-toplevel.h" +#include "rust-hir-type-check-enumitem.h" +#include "rust-hir-type-check-type.h" +#include "rust-hir-type-check-expr.h" +#include "rust-hir-type-check-pattern.h" +#include "rust-hir-type-check-implitem.h" namespace Rust { namespace Resolver { +TypeCheckTopLevel::TypeCheckTopLevel () : TypeCheckBase () {} + void -TypeCheckTopLevel::Resolve (HIR::Item *item) +TypeCheckTopLevel::Resolve (HIR::Item &item) { + rust_assert (item.get_hir_kind () == HIR::Node::BaseKind::VIS_ITEM); + HIR::VisItem &vis_item = static_cast<HIR::VisItem &> (item); + TypeCheckTopLevel resolver; - item->accept_vis (resolver); + vis_item.accept_vis (resolver); } void @@ -100,7 +110,7 @@ void TypeCheckTopLevel::visit (HIR::Module &module) { for (auto &item : module.get_items ()) - TypeCheckTopLevel::Resolve (item.get ()); + TypeCheckTopLevel::Resolve (*item.get ()); } void diff --git a/gcc/rust/typecheck/rust-hir-type-check-toplevel.h b/gcc/rust/typecheck/rust-hir-type-check-toplevel.h index d2785b1..d0db07d 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-toplevel.h +++ b/gcc/rust/typecheck/rust-hir-type-check-toplevel.h @@ -20,37 +20,34 @@ #define RUST_HIR_TYPE_CHECK_TOPLEVEL #include "rust-hir-type-check-base.h" -#include "rust-hir-full.h" -#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 { namespace Resolver { -class TypeCheckTopLevel : public TypeCheckBase +class TypeCheckTopLevel : private TypeCheckBase, public HIR::HIRVisItemVisitor { - using Rust::Resolver::TypeCheckBase::visit; - public: - static void Resolve (HIR::Item *item); + static void Resolve (HIR::Item &item); + void visit (HIR::Module &module) override; + void visit (HIR::Function &function) override; void visit (HIR::TypeAlias &alias) override; void visit (HIR::TupleStruct &struct_decl) override; - void visit (HIR::Module &module) override; void visit (HIR::StructStruct &struct_decl) override; void visit (HIR::Enum &enum_decl) override; void visit (HIR::Union &union_decl) override; void visit (HIR::StaticItem &var) override; void visit (HIR::ConstantItem &constant) override; - void visit (HIR::Function &function) override; void visit (HIR::ImplBlock &impl_block) override; void visit (HIR::ExternBlock &extern_block) override; + // nothing to do + void visit (HIR::Trait &trait_block) override {} + void visit (HIR::ExternCrate &crate) override {} + void visit (HIR::UseDeclaration &use_decl) override {} + private: - TypeCheckTopLevel () : TypeCheckBase () {} + TypeCheckTopLevel (); }; } // namespace Resolver diff --git a/gcc/rust/typecheck/rust-hir-type-check-type.cc b/gcc/rust/typecheck/rust-hir-type-check-type.cc index 3c2a7c5..3538d77 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-type.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-type.cc @@ -27,7 +27,15 @@ HIR::GenericArgs TypeCheckResolveGenericArguments::resolve (HIR::TypePathSegment *segment) { TypeCheckResolveGenericArguments resolver (segment->get_locus ()); - segment->accept_vis (resolver); + switch (segment->get_type ()) + { + case HIR::TypePathSegment::SegmentType::GENERIC: + resolver.visit (static_cast<HIR::TypePathSegmentGeneric &> (*segment)); + break; + + default: + break; + } return resolver.args; } @@ -674,18 +682,36 @@ TyTy::ParamType * TypeResolveGenericParam::Resolve (HIR::GenericParam *param) { TypeResolveGenericParam resolver; - param->accept_vis (resolver); - - if (resolver.resolved == nullptr) + switch (param->get_kind ()) { - rust_error_at (param->get_locus (), "failed to setup generic parameter"); - return nullptr; - } + case HIR::GenericParam::GenericKind::TYPE: + resolver.visit (static_cast<HIR::TypeParam &> (*param)); + break; + case HIR::GenericParam::GenericKind::CONST: + resolver.visit (static_cast<HIR::ConstGenericParam &> (*param)); + break; + + case HIR::GenericParam::GenericKind::LIFETIME: + resolver.visit (static_cast<HIR::LifetimeParam &> (*param)); + break; + } return resolver.resolved; } void +TypeResolveGenericParam::visit (HIR::LifetimeParam ¶m) +{ + // nothing to do +} + +void +TypeResolveGenericParam::visit (HIR::ConstGenericParam ¶m) +{ + // TODO +} + +void TypeResolveGenericParam::visit (HIR::TypeParam ¶m) { if (param.has_type ()) @@ -725,11 +751,20 @@ void ResolveWhereClauseItem::Resolve (HIR::WhereClauseItem &item) { ResolveWhereClauseItem resolver; - item.accept_vis (resolver); + switch (item.get_item_type ()) + { + case HIR::WhereClauseItem::LIFETIME: + resolver.visit (static_cast<HIR::LifetimeWhereClauseItem &> (item)); + break; + + case HIR::WhereClauseItem::TYPE_BOUND: + resolver.visit (static_cast<HIR::TypeBoundWhereClauseItem &> (item)); + break; + } } void -ResolveWhereClauseItem::visit (HIR::LifetimeWhereClauseItem &) +ResolveWhereClauseItem::visit (HIR::LifetimeWhereClauseItem &item) {} void diff --git a/gcc/rust/typecheck/rust-hir-type-check-type.h b/gcc/rust/typecheck/rust-hir-type-check-type.h index 151e87d..90d5ddb 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-type.h +++ b/gcc/rust/typecheck/rust-hir-type-check-type.h @@ -27,14 +27,15 @@ namespace Rust { namespace Resolver { +// FIXME +// This simply fetches the HIR:::GenericArgs from the base class. Check to see +// if we can get rid of this class class TypeCheckResolveGenericArguments : public TypeCheckBase { - using Rust::Resolver::TypeCheckBase::visit; - public: static HIR::GenericArgs resolve (HIR::TypePathSegment *segment); - void visit (HIR::TypePathSegmentGeneric &generic) override; + void visit (HIR::TypePathSegmentGeneric &generic); private: TypeCheckResolveGenericArguments (Location locus) @@ -44,10 +45,8 @@ private: HIR::GenericArgs args; }; -class TypeCheckType : public TypeCheckBase +class TypeCheckType : public TypeCheckBase, public HIR::HIRTypeVisitor { - using Rust::Resolver::TypeCheckBase::visit; - public: static TyTy::BaseType *Resolve (HIR::Type *type); @@ -63,6 +62,22 @@ public: void visit (HIR::NeverType &type) override; void visit (HIR::TraitObjectType &type) override; + void visit (HIR::TypePathSegmentFunction &segment) override + { /* TODO */ + } + void visit (HIR::TraitBound &bound) override + { /* TODO */ + } + void visit (HIR::ImplTraitType &type) override + { /* TODO */ + } + void visit (HIR::ParenthesisedType &type) override + { /* TODO */ + } + void visit (HIR::ImplTraitTypeOneBound &type) override + { /* TODO */ + } + private: TypeCheckType (HirId id) : TypeCheckBase (), translated (new TyTy::ErrorType (id)) @@ -82,12 +97,13 @@ private: class TypeResolveGenericParam : public TypeCheckBase { - using Rust::Resolver::TypeCheckBase::visit; - public: static TyTy::ParamType *Resolve (HIR::GenericParam *param); - void visit (HIR::TypeParam ¶m) override; +protected: + void visit (HIR::TypeParam ¶m); + void visit (HIR::LifetimeParam ¶m); + void visit (HIR::ConstGenericParam ¶m); private: TypeResolveGenericParam () : TypeCheckBase (), resolved (nullptr) {} @@ -97,13 +113,12 @@ private: class ResolveWhereClauseItem : public TypeCheckBase { - using Rust::Resolver::TypeCheckBase::visit; - public: static void Resolve (HIR::WhereClauseItem &item); - void visit (HIR::LifetimeWhereClauseItem &) override; - void visit (HIR::TypeBoundWhereClauseItem &item) override; +protected: + void visit (HIR::LifetimeWhereClauseItem &item); + void visit (HIR::TypeBoundWhereClauseItem &item); private: ResolveWhereClauseItem () : TypeCheckBase () {} diff --git a/gcc/rust/typecheck/rust-hir-type-check.cc b/gcc/rust/typecheck/rust-hir-type-check.cc index 37a085f..c314585 100644 --- a/gcc/rust/typecheck/rust-hir-type-check.cc +++ b/gcc/rust/typecheck/rust-hir-type-check.cc @@ -21,6 +21,7 @@ #include "rust-hir-type-check-toplevel.h" #include "rust-hir-type-check-item.h" #include "rust-hir-type-check-expr.h" +#include "rust-hir-type-check-pattern.h" #include "rust-hir-type-check-struct-field.h" #include "rust-hir-inherent-impl-overlap.h" @@ -34,7 +35,7 @@ void TypeResolution::Resolve (HIR::Crate &crate) { for (auto it = crate.items.begin (); it != crate.items.end (); it++) - TypeCheckTopLevel::Resolve (it->get ()); + TypeCheckTopLevel::Resolve (*it->get ()); if (saw_errors ()) return; @@ -44,7 +45,7 @@ TypeResolution::Resolve (HIR::Crate &crate) return; for (auto it = crate.items.begin (); it != crate.items.end (); it++) - TypeCheckItem::Resolve (it->get ()); + TypeCheckItem::Resolve (*it->get ()); if (saw_errors ()) return; @@ -81,47 +82,6 @@ TypeResolution::Resolve (HIR::Crate &crate) }); } -// RUST_HIR_TYPE_CHECK_EXPR -void -TypeCheckExpr::visit (HIR::BlockExpr &expr) -{ - for (auto &s : expr.get_statements ()) - { - if (!s->is_item ()) - continue; - - TypeCheckStmt::Resolve (s.get ()); - } - - for (auto &s : expr.get_statements ()) - { - if (s->is_item ()) - continue; - - auto resolved = TypeCheckStmt::Resolve (s.get ()); - if (resolved == nullptr) - { - rust_error_at (s->get_locus (), "failure to resolve type"); - return; - } - - if (s->is_unit_check_needed () && !resolved->is_unit ()) - { - auto unit - = TyTy::TupleType::get_unit_type (s->get_mappings ().get_hirid ()); - resolved = unit->unify (resolved); - } - } - - if (expr.has_expr ()) - infered = TypeCheckExpr::Resolve (expr.get_final_expr ().get ())->clone (); - else if (expr.is_tail_reachable ()) - infered - = TyTy::TupleType::get_unit_type (expr.get_mappings ().get_hirid ()); - else - infered = new TyTy::NeverType (expr.get_mappings ().get_hirid ()); -} - // rust-hir-trait-ref.h TraitItemReference::TraitItemReference ( diff --git a/gcc/rust/typecheck/rust-tycheck-dump.h b/gcc/rust/typecheck/rust-tycheck-dump.h index 36963e5..f66d7eb 100644 --- a/gcc/rust/typecheck/rust-tycheck-dump.h +++ b/gcc/rust/typecheck/rust-tycheck-dump.h @@ -25,9 +25,9 @@ namespace Rust { namespace Resolver { -class TypeResolverDump : public TypeCheckBase +class TypeResolverDump : private TypeCheckBase, private HIR::HIRFullVisitorBase { - using Rust::HIR::HIRFullVisitorBase::visit; + using HIR::HIRFullVisitorBase::visit; public: static void go (HIR::Crate &crate, std::ofstream &out) |