1458: Refactor type resolution pass to use fine grained visitors r=philberty a=philberty

Thanks for `@dkm` work on fine-grained HIR visitors this patch takes advantage of this
and moves most implementation into CC files and takes advantage of fine-grained visitors
this will help with the maintainability of the code and it also makes it clear what classes do
and don't do.

It's part of an incremental refactor to get rid of the awkward top-level scan pass in the
type resolution pass. This will allow us to move towards a more query-based model
like the code generation pass so that we can support the forward declared items.

The problem is that we our name resolution pass supports forward declared items but our
type resolution pass does not. We know the HIR nodes when type paths or path expressions
resolve to but when it comes to actually resolve this we just fail when we reuse our mappings
class to look up the item.

1463: Remove unused backend wrapper r=philberty a=philberty

This removes the unused switch statement wrapper

Co-authored-by: Philip Herron <philip.herron@embecosm.com>
This commit is contained in:
bors[bot] 2022-08-11 12:59:01 +00:00 committed by GitHub
commit e57bbcb241
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
31 changed files with 2717 additions and 2372 deletions

View File

@ -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 \

View File

@ -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 */

View File

@ -306,18 +306,6 @@ public:
// exit expressions
virtual tree exit_expression (tree condition, Location) = 0;
// Create a switch statement where the case values are constants.
// CASES and STATEMENTS must have the same number of entries. If
// VALUE matches any of the list in CASES[i], which will all be
// integers, then STATEMENTS[i] is executed. STATEMENTS[i] will
// either end with a goto statement or will fall through into
// STATEMENTS[i + 1]. CASES[i] is empty for the default clause,
// which need not be last. FUNCTION is the current function.
virtual tree switch_statement (tree function, tree value,
const std::vector<std::vector<tree> > &cases,
const std::vector<tree> &statements, Location)
= 0;
// Create a single statement from two statements.
virtual tree compound_statement (tree, tree) = 0;

View File

@ -264,10 +264,6 @@ public:
tree if_statement (tree, tree condition, tree then_block, tree else_block,
Location);
tree switch_statement (tree function, tree value,
const std::vector<std::vector<tree>> &cases,
const std::vector<tree> &statements, Location);
tree compound_statement (tree, tree);
tree statement_list (const std::vector<tree> &);
@ -327,10 +323,6 @@ public:
bool function_set_parameters (tree function,
const std::vector<Bvariable *> &);
tree lookup_gcc_builtin (const std::string &);
tree lookup_builtin_by_rust_name (const std::string &);
void write_global_definitions (const std::vector<tree> &,
const std::vector<tree> &,
const std::vector<tree> &,
@ -2057,67 +2049,6 @@ Gcc_backend::exit_expression (tree cond_tree, Location locus)
cond_tree);
}
// Switch.
tree
Gcc_backend::switch_statement (tree decl, tree value,
const std::vector<std::vector<tree>> &cases,
const std::vector<tree> &statements,
Location switch_location)
{
gcc_assert (cases.size () == statements.size ());
if (DECL_STRUCT_FUNCTION (decl) == NULL)
push_struct_function (decl);
else
push_cfun (DECL_STRUCT_FUNCTION (decl));
tree stmt_list = NULL_TREE;
std::vector<std::vector<tree>>::const_iterator pc = cases.begin ();
for (std::vector<tree>::const_iterator ps = statements.begin ();
ps != statements.end (); ++ps, ++pc)
{
if (pc->empty ())
{
location_t loc
= (*ps != NULL ? EXPR_LOCATION (*ps) : UNKNOWN_LOCATION);
tree label = create_artificial_label (loc);
tree c = build_case_label (NULL_TREE, NULL_TREE, label);
append_to_statement_list (c, &stmt_list);
}
else
{
for (std::vector<tree>::const_iterator pcv = pc->begin ();
pcv != pc->end (); ++pcv)
{
tree t = (*pcv);
if (t == error_mark_node)
return error_mark_node;
location_t loc = EXPR_LOCATION (t);
tree label = create_artificial_label (loc);
tree c = build_case_label ((*pcv), NULL_TREE, label);
append_to_statement_list (c, &stmt_list);
}
}
if (*ps != NULL)
{
tree t = (*ps);
if (t == error_mark_node)
return error_mark_node;
append_to_statement_list (t, &stmt_list);
}
}
pop_cfun ();
tree tv = value;
if (tv == error_mark_node)
return error_mark_node;
tree t = build2_loc (switch_location.gcc_location (), SWITCH_EXPR, NULL_TREE,
tv, stmt_list);
return t;
}
// Pair of statements.
tree

View File

@ -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 ()
{

View File

@ -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)

View File

@ -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);

View File

@ -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)

View File

@ -17,6 +17,8 @@
// <http://www.gnu.org/licenses/>.
#include "rust-hir-type-check-base.h"
#include "rust-hir-type-check-type.h"
#include "rust-hir-type-check-expr.h"
#include "rust-coercion.h"
namespace Rust {
@ -349,5 +351,49 @@ TypeCheckBase::coercion_site (HirId id, TyTy::BaseType *expected,
return expected->coerce (expr);
}
void
TypeCheckBase::resolve_generic_params (
const std::vector<std::unique_ptr<HIR::GenericParam>> &generic_params,
std::vector<TyTy::SubstitutionParamMapping> &substitutions)
{
for (auto &generic_param : generic_params)
{
switch (generic_param.get ()->get_kind ())
{
case HIR::GenericParam::GenericKind::LIFETIME:
// FIXME: Skipping Lifetime completely until better
// handling.
break;
case HIR::GenericParam::GenericKind::CONST: {
auto param
= static_cast<HIR::ConstGenericParam *> (generic_param.get ());
auto specified_type
= TypeCheckType::Resolve (param->get_type ().get ());
if (param->has_default_expression ())
{
auto expr_type = TypeCheckExpr::Resolve (
param->get_default_expression ().get ());
specified_type->coerce (expr_type);
}
context->insert_type (generic_param->get_mappings (),
specified_type);
}
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;
}
}
}
} // namespace Resolver
} // namespace Rust

View File

@ -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,
@ -64,6 +60,10 @@ protected:
TyTy::ADTType::ReprOptions parse_repr_options (const AST::AttrVec &attrs,
Location locus);
void resolve_generic_params (
const std::vector<std::unique_ptr<HIR::GenericParam>> &generic_params,
std::vector<TyTy::SubstitutionParamMapping> &substitutions);
Analysis::Mappings *mappings;
Resolver *resolver;
TypeCheckContext *context;

View File

@ -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

View File

@ -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;
}
int64_t last_discriminant);
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);
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;

View File

@ -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)
{
@ -304,6 +848,146 @@ TypeCheckExpr::visit (HIR::ArrayIndexExpr &expr)
index_expr_ty->get_name ().c_str ());
}
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)
{
@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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 &param : 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 &param : 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

View File

@ -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);
}
static void Resolve (HIR::ExternalItem *item, const HIR::ExternBlock &parent);
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 &param : 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);
}
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);
}
std::vector<TyTy::SubstitutionParamMapping> substitutions);
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;
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 &param : 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);
}
TyTy::BaseType *self);
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;
}
// 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;
}
std::vector<TyTy::SubstitutionParamMapping> substitutions);
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 ());
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;

View File

@ -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

View File

@ -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

View File

@ -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 {

View File

@ -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

View File

@ -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,

View File

@ -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 &param : 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

View File

@ -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 &param : 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:

View File

@ -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;
}
static TyTy::BaseType *Resolve (HIR::StructExprStructFields *expr);
void visit (HIR::StructExprStructFields &struct_expr) override;
protected:
void resolve (HIR::StructExprStructFields &struct_expr);
void visit (HIR::StructExprFieldIdentifierValue &field) override;
void visit (HIR::StructExprFieldIndexValue &field) override;
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;

View File

@ -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;
}
}

View File

@ -17,59 +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);
}
void
TypeCheckTopLevel::resolve_generic_params (
const std::vector<std::unique_ptr<HIR::GenericParam>> &generic_params,
std::vector<TyTy::SubstitutionParamMapping> &substitutions)
{
for (auto &generic_param : generic_params)
{
switch (generic_param.get ()->get_kind ())
{
case HIR::GenericParam::GenericKind::LIFETIME:
// FIXME: Skipping Lifetime completely until better
// handling.
break;
case HIR::GenericParam::GenericKind::CONST: {
auto param
= static_cast<HIR::ConstGenericParam *> (generic_param.get ());
auto specified_type
= TypeCheckType::Resolve (param->get_type ().get ());
if (param->has_default_expression ())
{
auto expr_type = TypeCheckExpr::Resolve (
param->get_default_expression ().get ());
specified_type->coerce (expr_type);
}
context->insert_type (generic_param->get_mappings (),
specified_type);
}
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;
}
}
vis_item.accept_vis (resolver);
}
void
@ -144,7 +110,7 @@ void
TypeCheckTopLevel::visit (HIR::Module &module)
{
for (auto &item : module.get_items ())
TypeCheckTopLevel::Resolve (item.get ());
TypeCheckTopLevel::Resolve (*item.get ());
}
void

View File

@ -20,41 +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;
private:
TypeCheckTopLevel () : TypeCheckBase () {}
// nothing to do
void visit (HIR::Trait &trait_block) override {}
void visit (HIR::ExternCrate &crate) override {}
void visit (HIR::UseDeclaration &use_decl) override {}
void resolve_generic_params (
const std::vector<std::unique_ptr<HIR::GenericParam>> &generic_params,
std::vector<TyTy::SubstitutionParamMapping> &substitutions);
private:
TypeCheckTopLevel ();
};
} // namespace Resolver

View File

@ -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,17 +682,35 @@ 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 &param)
{
// nothing to do
}
void
TypeResolveGenericParam::visit (HIR::ConstGenericParam &param)
{
// TODO
}
void
TypeResolveGenericParam::visit (HIR::TypeParam &param)
{
@ -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

View File

@ -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 &param) override;
protected:
void visit (HIR::TypeParam &param);
void visit (HIR::LifetimeParam &param);
void visit (HIR::ConstGenericParam &param);
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 () {}

View File

@ -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 (

View File

@ -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)