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:
commit
e57bbcb241
|
@ -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 \
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 ()
|
||||
{
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
|
@ -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;
|
||||
|
|
|
@ -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
|
@ -0,0 +1,583 @@
|
|||
// Copyright (C) 2020-2022 Free Software Foundation, Inc.
|
||||
|
||||
// This file is part of GCC.
|
||||
|
||||
// GCC is free software; you can redistribute it and/or modify it under
|
||||
// the terms of the GNU General Public License as published by the Free
|
||||
// Software Foundation; either version 3, or (at your option) any later
|
||||
// version.
|
||||
|
||||
// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
// for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with GCC; see the file COPYING3. If not see
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "rust-hir-type-check-implitem.h"
|
||||
#include "rust-hir-type-check-base.h"
|
||||
#include "rust-hir-full.h"
|
||||
#include "rust-hir-type-check-type.h"
|
||||
#include "rust-hir-type-check-expr.h"
|
||||
#include "rust-hir-type-check-pattern.h"
|
||||
#include "rust-tyty.h"
|
||||
|
||||
namespace Rust {
|
||||
namespace Resolver {
|
||||
|
||||
TypeCheckTopLevelExternItem::TypeCheckTopLevelExternItem (
|
||||
const HIR::ExternBlock &parent)
|
||||
: TypeCheckBase (), parent (parent)
|
||||
{}
|
||||
|
||||
void
|
||||
TypeCheckTopLevelExternItem::Resolve (HIR::ExternalItem *item,
|
||||
const HIR::ExternBlock &parent)
|
||||
{
|
||||
TypeCheckTopLevelExternItem resolver (parent);
|
||||
item->accept_vis (resolver);
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckTopLevelExternItem::visit (HIR::ExternalStaticItem &item)
|
||||
{
|
||||
TyTy::BaseType *actual_type
|
||||
= TypeCheckType::Resolve (item.get_item_type ().get ());
|
||||
|
||||
context->insert_type (item.get_mappings (), actual_type);
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckTopLevelExternItem::visit (HIR::ExternalFunctionItem &function)
|
||||
{
|
||||
std::vector<TyTy::SubstitutionParamMapping> substitutions;
|
||||
if (function.has_generics ())
|
||||
{
|
||||
for (auto &generic_param : function.get_generic_params ())
|
||||
{
|
||||
switch (generic_param.get ()->get_kind ())
|
||||
{
|
||||
case HIR::GenericParam::GenericKind::LIFETIME:
|
||||
case HIR::GenericParam::GenericKind::CONST:
|
||||
// FIXME: Skipping Lifetime and Const completely until better
|
||||
// handling.
|
||||
break;
|
||||
|
||||
case HIR::GenericParam::GenericKind::TYPE: {
|
||||
auto param_type
|
||||
= TypeResolveGenericParam::Resolve (generic_param.get ());
|
||||
context->insert_type (generic_param->get_mappings (),
|
||||
param_type);
|
||||
|
||||
substitutions.push_back (TyTy::SubstitutionParamMapping (
|
||||
static_cast<HIR::TypeParam &> (*generic_param), param_type));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TyTy::BaseType *ret_type = nullptr;
|
||||
if (!function.has_return_type ())
|
||||
ret_type
|
||||
= TyTy::TupleType::get_unit_type (function.get_mappings ().get_hirid ());
|
||||
else
|
||||
{
|
||||
auto resolved
|
||||
= TypeCheckType::Resolve (function.get_return_type ().get ());
|
||||
if (resolved == nullptr)
|
||||
{
|
||||
rust_error_at (function.get_locus (),
|
||||
"failed to resolve return type");
|
||||
return;
|
||||
}
|
||||
|
||||
ret_type = resolved->clone ();
|
||||
ret_type->set_ref (
|
||||
function.get_return_type ()->get_mappings ().get_hirid ());
|
||||
}
|
||||
|
||||
std::vector<std::pair<HIR::Pattern *, TyTy::BaseType *> > params;
|
||||
for (auto ¶m : function.get_function_params ())
|
||||
{
|
||||
// get the name as well required for later on
|
||||
auto param_tyty = TypeCheckType::Resolve (param.get_type ().get ());
|
||||
|
||||
// these are implicit mappings and not used
|
||||
auto crate_num = mappings->get_current_crate ();
|
||||
Analysis::NodeMapping mapping (crate_num, mappings->get_next_node_id (),
|
||||
mappings->get_next_hir_id (crate_num),
|
||||
UNKNOWN_LOCAL_DEFID);
|
||||
|
||||
HIR::IdentifierPattern *param_pattern
|
||||
= new HIR::IdentifierPattern (mapping, param.get_param_name (),
|
||||
Location (), false, Mutability::Imm,
|
||||
std::unique_ptr<HIR::Pattern> (nullptr));
|
||||
|
||||
params.push_back (
|
||||
std::pair<HIR::Pattern *, TyTy::BaseType *> (param_pattern,
|
||||
param_tyty));
|
||||
|
||||
context->insert_type (param.get_mappings (), param_tyty);
|
||||
|
||||
// FIXME do we need error checking for patterns here?
|
||||
// see https://github.com/Rust-GCC/gccrs/issues/995
|
||||
}
|
||||
|
||||
uint8_t flags = TyTy::FnType::FNTYPE_IS_EXTERN_FLAG;
|
||||
if (function.is_variadic ())
|
||||
flags |= TyTy::FnType::FNTYPE_IS_VARADIC_FLAG;
|
||||
|
||||
RustIdent ident{
|
||||
CanonicalPath::new_seg (function.get_mappings ().get_nodeid (),
|
||||
function.get_item_name ()),
|
||||
function.get_locus ()};
|
||||
|
||||
auto fnType = new TyTy::FnType (function.get_mappings ().get_hirid (),
|
||||
function.get_mappings ().get_defid (),
|
||||
function.get_item_name (), ident, flags,
|
||||
parent.get_abi (), std::move (params),
|
||||
ret_type, std::move (substitutions));
|
||||
|
||||
context->insert_type (function.get_mappings (), fnType);
|
||||
}
|
||||
|
||||
TypeCheckTopLevelImplItem::TypeCheckTopLevelImplItem (
|
||||
TyTy::BaseType *self,
|
||||
std::vector<TyTy::SubstitutionParamMapping> substitutions)
|
||||
: TypeCheckBase (), self (self), substitutions (substitutions)
|
||||
{}
|
||||
|
||||
void
|
||||
TypeCheckTopLevelImplItem::Resolve (
|
||||
HIR::ImplItem *item, TyTy::BaseType *self,
|
||||
std::vector<TyTy::SubstitutionParamMapping> substitutions)
|
||||
{
|
||||
TypeCheckTopLevelImplItem resolver (self, substitutions);
|
||||
item->accept_vis (resolver);
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckTopLevelImplItem::visit (HIR::TypeAlias &alias)
|
||||
{
|
||||
TyTy::BaseType *actual_type
|
||||
= TypeCheckType::Resolve (alias.get_type_aliased ().get ());
|
||||
|
||||
context->insert_type (alias.get_mappings (), actual_type);
|
||||
|
||||
for (auto &where_clause_item : alias.get_where_clause ().get_items ())
|
||||
{
|
||||
ResolveWhereClauseItem::Resolve (*where_clause_item.get ());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckTopLevelImplItem::visit (HIR::ConstantItem &constant)
|
||||
{
|
||||
TyTy::BaseType *type = TypeCheckType::Resolve (constant.get_type ());
|
||||
TyTy::BaseType *expr_type = TypeCheckExpr::Resolve (constant.get_expr ());
|
||||
|
||||
context->insert_type (constant.get_mappings (), type->unify (expr_type));
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckTopLevelImplItem::visit (HIR::Function &function)
|
||||
{
|
||||
if (function.has_generics ())
|
||||
{
|
||||
for (auto &generic_param : function.get_generic_params ())
|
||||
{
|
||||
switch (generic_param.get ()->get_kind ())
|
||||
{
|
||||
case HIR::GenericParam::GenericKind::LIFETIME:
|
||||
case HIR::GenericParam::GenericKind::CONST:
|
||||
// FIXME: Skipping Lifetime and Const completely until better
|
||||
// handling.
|
||||
break;
|
||||
|
||||
case HIR::GenericParam::GenericKind::TYPE: {
|
||||
auto param_type
|
||||
= TypeResolveGenericParam::Resolve (generic_param.get ());
|
||||
context->insert_type (generic_param->get_mappings (),
|
||||
param_type);
|
||||
|
||||
substitutions.push_back (TyTy::SubstitutionParamMapping (
|
||||
static_cast<HIR::TypeParam &> (*generic_param), param_type));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &where_clause_item : function.get_where_clause ().get_items ())
|
||||
{
|
||||
ResolveWhereClauseItem::Resolve (*where_clause_item.get ());
|
||||
}
|
||||
|
||||
TyTy::BaseType *ret_type = nullptr;
|
||||
if (!function.has_function_return_type ())
|
||||
ret_type
|
||||
= TyTy::TupleType::get_unit_type (function.get_mappings ().get_hirid ());
|
||||
else
|
||||
{
|
||||
auto resolved
|
||||
= TypeCheckType::Resolve (function.get_return_type ().get ());
|
||||
if (resolved == nullptr)
|
||||
{
|
||||
rust_error_at (function.get_locus (),
|
||||
"failed to resolve return type");
|
||||
return;
|
||||
}
|
||||
|
||||
ret_type = resolved->clone ();
|
||||
ret_type->set_ref (
|
||||
function.get_return_type ()->get_mappings ().get_hirid ());
|
||||
}
|
||||
|
||||
std::vector<std::pair<HIR::Pattern *, TyTy::BaseType *> > params;
|
||||
if (function.is_method ())
|
||||
{
|
||||
// these are implicit mappings and not used
|
||||
auto crate_num = mappings->get_current_crate ();
|
||||
Analysis::NodeMapping mapping (crate_num, mappings->get_next_node_id (),
|
||||
mappings->get_next_hir_id (crate_num),
|
||||
UNKNOWN_LOCAL_DEFID);
|
||||
|
||||
// add the synthetic self param at the front, this is a placeholder for
|
||||
// compilation to know parameter names. The types are ignored but we
|
||||
// reuse the HIR identifier pattern which requires it
|
||||
HIR::SelfParam &self_param = function.get_self_param ();
|
||||
HIR::IdentifierPattern *self_pattern
|
||||
= new HIR::IdentifierPattern (mapping, "self", self_param.get_locus (),
|
||||
self_param.is_ref (),
|
||||
self_param.get_mut (),
|
||||
std::unique_ptr<HIR::Pattern> (nullptr));
|
||||
|
||||
// might have a specified type
|
||||
TyTy::BaseType *self_type = nullptr;
|
||||
if (self_param.has_type ())
|
||||
{
|
||||
std::unique_ptr<HIR::Type> &specified_type = self_param.get_type ();
|
||||
self_type = TypeCheckType::Resolve (specified_type.get ());
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (self_param.get_self_kind ())
|
||||
{
|
||||
case HIR::SelfParam::IMM:
|
||||
case HIR::SelfParam::MUT:
|
||||
self_type = self->clone ();
|
||||
break;
|
||||
|
||||
case HIR::SelfParam::IMM_REF:
|
||||
self_type = new TyTy::ReferenceType (
|
||||
self_param.get_mappings ().get_hirid (),
|
||||
TyTy::TyVar (self->get_ref ()), Mutability::Imm);
|
||||
break;
|
||||
|
||||
case HIR::SelfParam::MUT_REF:
|
||||
self_type = new TyTy::ReferenceType (
|
||||
self_param.get_mappings ().get_hirid (),
|
||||
TyTy::TyVar (self->get_ref ()), Mutability::Mut);
|
||||
break;
|
||||
|
||||
default:
|
||||
gcc_unreachable ();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
context->insert_type (self_param.get_mappings (), self_type);
|
||||
params.push_back (
|
||||
std::pair<HIR::Pattern *, TyTy::BaseType *> (self_pattern, self_type));
|
||||
}
|
||||
|
||||
for (auto ¶m : function.get_function_params ())
|
||||
{
|
||||
// get the name as well required for later on
|
||||
auto param_tyty = TypeCheckType::Resolve (param.get_type ());
|
||||
params.push_back (
|
||||
std::pair<HIR::Pattern *, TyTy::BaseType *> (param.get_param_name (),
|
||||
param_tyty));
|
||||
|
||||
context->insert_type (param.get_mappings (), param_tyty);
|
||||
TypeCheckPattern::Resolve (param.get_param_name (), param_tyty);
|
||||
}
|
||||
|
||||
const CanonicalPath *canonical_path = nullptr;
|
||||
bool ok
|
||||
= mappings->lookup_canonical_path (function.get_mappings ().get_nodeid (),
|
||||
&canonical_path);
|
||||
rust_assert (ok);
|
||||
|
||||
RustIdent ident{*canonical_path, function.get_locus ()};
|
||||
auto fnType = new TyTy::FnType (function.get_mappings ().get_hirid (),
|
||||
function.get_mappings ().get_defid (),
|
||||
function.get_function_name (), ident,
|
||||
function.is_method ()
|
||||
? TyTy::FnType::FNTYPE_IS_METHOD_FLAG
|
||||
: TyTy::FnType::FNTYPE_DEFAULT_FLAGS,
|
||||
ABI::RUST, std::move (params), ret_type,
|
||||
std::move (substitutions));
|
||||
|
||||
context->insert_type (function.get_mappings (), fnType);
|
||||
}
|
||||
|
||||
TypeCheckImplItem::TypeCheckImplItem (HIR::ImplBlock *parent,
|
||||
TyTy::BaseType *self)
|
||||
: TypeCheckBase (), parent (parent), self (self)
|
||||
{}
|
||||
|
||||
void
|
||||
TypeCheckImplItem::Resolve (HIR::ImplBlock *parent, HIR::ImplItem *item,
|
||||
TyTy::BaseType *self)
|
||||
{
|
||||
TypeCheckImplItem resolver (parent, self);
|
||||
item->accept_vis (resolver);
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckImplItem::visit (HIR::Function &function)
|
||||
{
|
||||
TyTy::BaseType *lookup;
|
||||
if (!context->lookup_type (function.get_mappings ().get_hirid (), &lookup))
|
||||
{
|
||||
rust_error_at (function.get_locus (), "failed to lookup function type");
|
||||
return;
|
||||
}
|
||||
|
||||
if (lookup->get_kind () != TyTy::TypeKind::FNDEF)
|
||||
{
|
||||
rust_error_at (function.get_locus (),
|
||||
"found invalid type for function [%s]",
|
||||
lookup->as_string ().c_str ());
|
||||
return;
|
||||
}
|
||||
|
||||
// need to get the return type from this
|
||||
TyTy::FnType *resolve_fn_type = static_cast<TyTy::FnType *> (lookup);
|
||||
auto expected_ret_tyty = resolve_fn_type->get_return_type ();
|
||||
context->push_return_type (TypeCheckContextItem (parent, &function),
|
||||
expected_ret_tyty);
|
||||
|
||||
auto block_expr_ty
|
||||
= TypeCheckExpr::Resolve (function.get_definition ().get ());
|
||||
|
||||
context->pop_return_type ();
|
||||
expected_ret_tyty->unify (block_expr_ty);
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckImplItem::visit (HIR::ConstantItem &const_item)
|
||||
{}
|
||||
|
||||
void
|
||||
TypeCheckImplItem::visit (HIR::TypeAlias &type_alias)
|
||||
{}
|
||||
|
||||
TypeCheckImplItemWithTrait::TypeCheckImplItemWithTrait (
|
||||
HIR::ImplBlock *parent, TyTy::BaseType *self,
|
||||
TyTy::TypeBoundPredicate &trait_reference,
|
||||
std::vector<TyTy::SubstitutionParamMapping> substitutions)
|
||||
: TypeCheckImplItem (parent, self), trait_reference (trait_reference),
|
||||
resolved_trait_item (TyTy::TypeBoundPredicateItem::error ()),
|
||||
substitutions (substitutions)
|
||||
{
|
||||
rust_assert (is_trait_impl_block ());
|
||||
}
|
||||
|
||||
TyTy::TypeBoundPredicateItem
|
||||
TypeCheckImplItemWithTrait::Resolve (
|
||||
HIR::ImplBlock *parent, HIR::ImplItem *item, TyTy::BaseType *self,
|
||||
TyTy::TypeBoundPredicate &trait_reference,
|
||||
std::vector<TyTy::SubstitutionParamMapping> substitutions)
|
||||
{
|
||||
TypeCheckImplItemWithTrait resolver (parent, self, trait_reference,
|
||||
substitutions);
|
||||
item->accept_vis (resolver);
|
||||
return resolver.resolved_trait_item;
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckImplItemWithTrait::visit (HIR::ConstantItem &constant)
|
||||
{
|
||||
// normal resolution of the item
|
||||
TypeCheckImplItem::visit (constant);
|
||||
TyTy::BaseType *lookup;
|
||||
if (!context->lookup_type (constant.get_mappings ().get_hirid (), &lookup))
|
||||
return;
|
||||
|
||||
// map the impl item to the associated trait item
|
||||
const auto tref = trait_reference.get ();
|
||||
const TraitItemReference *raw_trait_item = nullptr;
|
||||
bool found
|
||||
= tref->lookup_trait_item_by_type (constant.get_identifier (),
|
||||
TraitItemReference::TraitItemType::CONST,
|
||||
&raw_trait_item);
|
||||
|
||||
// unknown trait item
|
||||
if (!found || raw_trait_item->is_error ())
|
||||
{
|
||||
RichLocation r (constant.get_locus ());
|
||||
r.add_range (trait_reference.get_locus ());
|
||||
rust_error_at (r, "constant %<%s%> is not a member of trait %<%s%>",
|
||||
constant.get_identifier ().c_str (),
|
||||
trait_reference.get_name ().c_str ());
|
||||
return;
|
||||
}
|
||||
|
||||
// get the item from the predicate
|
||||
resolved_trait_item = trait_reference.lookup_associated_item (raw_trait_item);
|
||||
rust_assert (!resolved_trait_item.is_error ());
|
||||
|
||||
// merge the attributes
|
||||
const HIR::TraitItem *hir_trait_item
|
||||
= resolved_trait_item.get_raw_item ()->get_hir_trait_item ();
|
||||
merge_attributes (constant.get_outer_attrs (), *hir_trait_item);
|
||||
|
||||
// check the types are compatible
|
||||
auto trait_item_type = resolved_trait_item.get_tyty_for_receiver (self);
|
||||
if (!trait_item_type->can_eq (lookup, true))
|
||||
{
|
||||
RichLocation r (constant.get_locus ());
|
||||
r.add_range (resolved_trait_item.get_locus ());
|
||||
|
||||
rust_error_at (
|
||||
r, "constant %<%s%> has an incompatible type for trait %<%s%>",
|
||||
constant.get_identifier ().c_str (),
|
||||
trait_reference.get_name ().c_str ());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckImplItemWithTrait::visit (HIR::TypeAlias &type)
|
||||
{
|
||||
// normal resolution of the item
|
||||
TypeCheckImplItem::visit (type);
|
||||
TyTy::BaseType *lookup;
|
||||
if (!context->lookup_type (type.get_mappings ().get_hirid (), &lookup))
|
||||
return;
|
||||
|
||||
// map the impl item to the associated trait item
|
||||
const auto tref = trait_reference.get ();
|
||||
const TraitItemReference *raw_trait_item = nullptr;
|
||||
bool found
|
||||
= tref->lookup_trait_item_by_type (type.get_new_type_name (),
|
||||
TraitItemReference::TraitItemType::TYPE,
|
||||
&raw_trait_item);
|
||||
|
||||
// unknown trait item
|
||||
if (!found || raw_trait_item->is_error ())
|
||||
{
|
||||
RichLocation r (type.get_locus ());
|
||||
r.add_range (trait_reference.get_locus ());
|
||||
rust_error_at (r, "type alias %<%s%> is not a member of trait %<%s%>",
|
||||
type.get_new_type_name ().c_str (),
|
||||
trait_reference.get_name ().c_str ());
|
||||
return;
|
||||
}
|
||||
|
||||
// get the item from the predicate
|
||||
resolved_trait_item = trait_reference.lookup_associated_item (raw_trait_item);
|
||||
rust_assert (!resolved_trait_item.is_error ());
|
||||
|
||||
// merge the attributes
|
||||
const HIR::TraitItem *hir_trait_item
|
||||
= resolved_trait_item.get_raw_item ()->get_hir_trait_item ();
|
||||
merge_attributes (type.get_outer_attrs (), *hir_trait_item);
|
||||
|
||||
// check the types are compatible
|
||||
auto trait_item_type = resolved_trait_item.get_tyty_for_receiver (self);
|
||||
if (!trait_item_type->can_eq (lookup, true))
|
||||
{
|
||||
RichLocation r (type.get_locus ());
|
||||
r.add_range (resolved_trait_item.get_locus ());
|
||||
|
||||
rust_error_at (
|
||||
r, "type alias %<%s%> has an incompatible type for trait %<%s%>",
|
||||
type.get_new_type_name ().c_str (),
|
||||
trait_reference.get_name ().c_str ());
|
||||
}
|
||||
|
||||
// its actually a projection, since we need a way to actually bind the
|
||||
// generic substitutions to the type itself
|
||||
TyTy::ProjectionType *projection
|
||||
= new TyTy::ProjectionType (type.get_mappings ().get_hirid (), lookup, tref,
|
||||
raw_trait_item->get_mappings ().get_defid (),
|
||||
substitutions);
|
||||
|
||||
context->insert_type (type.get_mappings (), projection);
|
||||
raw_trait_item->associated_type_set (projection);
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckImplItemWithTrait::visit (HIR::Function &function)
|
||||
{
|
||||
// we get the error checking from the base method here
|
||||
TypeCheckImplItem::visit (function);
|
||||
TyTy::BaseType *lookup;
|
||||
if (!context->lookup_type (function.get_mappings ().get_hirid (), &lookup))
|
||||
return;
|
||||
|
||||
// map the impl item to the associated trait item
|
||||
const auto tref = trait_reference.get ();
|
||||
const TraitItemReference *raw_trait_item = nullptr;
|
||||
bool found
|
||||
= tref->lookup_trait_item_by_type (function.get_function_name (),
|
||||
TraitItemReference::TraitItemType::FN,
|
||||
&raw_trait_item);
|
||||
|
||||
// unknown trait item
|
||||
if (!found || raw_trait_item->is_error ())
|
||||
{
|
||||
RichLocation r (function.get_locus ());
|
||||
r.add_range (trait_reference.get_locus ());
|
||||
rust_error_at (r, "method %<%s%> is not a member of trait %<%s%>",
|
||||
function.get_function_name ().c_str (),
|
||||
trait_reference.get_name ().c_str ());
|
||||
return;
|
||||
}
|
||||
|
||||
// get the item from the predicate
|
||||
resolved_trait_item = trait_reference.lookup_associated_item (raw_trait_item);
|
||||
rust_assert (!resolved_trait_item.is_error ());
|
||||
|
||||
// merge the attributes
|
||||
const HIR::TraitItem *hir_trait_item
|
||||
= resolved_trait_item.get_raw_item ()->get_hir_trait_item ();
|
||||
merge_attributes (function.get_outer_attrs (), *hir_trait_item);
|
||||
|
||||
// check the types are compatible
|
||||
auto trait_item_type = resolved_trait_item.get_tyty_for_receiver (self);
|
||||
if (!trait_item_type->can_eq (lookup, true))
|
||||
{
|
||||
RichLocation r (function.get_locus ());
|
||||
r.add_range (resolved_trait_item.get_locus ());
|
||||
|
||||
rust_error_at (r,
|
||||
"method %<%s%> has an incompatible type for trait %<%s%>",
|
||||
function.get_function_name ().c_str (),
|
||||
trait_reference.get_name ().c_str ());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckImplItemWithTrait::merge_attributes (AST::AttrVec &impl_item_attrs,
|
||||
const HIR::TraitItem &trait_item)
|
||||
{
|
||||
for (const auto &attr : trait_item.get_outer_attrs ())
|
||||
{
|
||||
impl_item_attrs.push_back (attr);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
TypeCheckImplItemWithTrait::is_trait_impl_block () const
|
||||
{
|
||||
return !trait_reference.is_error ();
|
||||
}
|
||||
|
||||
} // namespace Resolver
|
||||
} // namespace Rust
|
|
@ -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 ¶m : function.get_function_params ())
|
||||
{
|
||||
// get the name as well required for later on
|
||||
auto param_tyty = TypeCheckType::Resolve (param.get_type ().get ());
|
||||
|
||||
// these are implicit mappings and not used
|
||||
auto crate_num = mappings->get_current_crate ();
|
||||
Analysis::NodeMapping mapping (crate_num, mappings->get_next_node_id (),
|
||||
mappings->get_next_hir_id (crate_num),
|
||||
UNKNOWN_LOCAL_DEFID);
|
||||
|
||||
HIR::IdentifierPattern *param_pattern = new HIR::IdentifierPattern (
|
||||
mapping, param.get_param_name (), Location (), false, Mutability::Imm,
|
||||
std::unique_ptr<HIR::Pattern> (nullptr));
|
||||
|
||||
params.push_back (
|
||||
std::pair<HIR::Pattern *, TyTy::BaseType *> (param_pattern,
|
||||
param_tyty));
|
||||
|
||||
context->insert_type (param.get_mappings (), param_tyty);
|
||||
|
||||
// FIXME do we need error checking for patterns here?
|
||||
// see https://github.com/Rust-GCC/gccrs/issues/995
|
||||
}
|
||||
|
||||
uint8_t flags = TyTy::FnType::FNTYPE_IS_EXTERN_FLAG;
|
||||
if (function.is_variadic ())
|
||||
flags |= TyTy::FnType::FNTYPE_IS_VARADIC_FLAG;
|
||||
|
||||
RustIdent ident{
|
||||
CanonicalPath::new_seg (function.get_mappings ().get_nodeid (),
|
||||
function.get_item_name ()),
|
||||
function.get_locus ()};
|
||||
|
||||
auto fnType = new TyTy::FnType (function.get_mappings ().get_hirid (),
|
||||
function.get_mappings ().get_defid (),
|
||||
function.get_item_name (), ident, flags,
|
||||
parent.get_abi (), std::move (params),
|
||||
ret_type, std::move (substitutions));
|
||||
|
||||
context->insert_type (function.get_mappings (), fnType);
|
||||
}
|
||||
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 ¶m : function.get_function_params ())
|
||||
{
|
||||
// get the name as well required for later on
|
||||
auto param_tyty = TypeCheckType::Resolve (param.get_type ());
|
||||
params.push_back (
|
||||
std::pair<HIR::Pattern *, TyTy::BaseType *> (param.get_param_name (),
|
||||
param_tyty));
|
||||
|
||||
context->insert_type (param.get_mappings (), param_tyty);
|
||||
TypeCheckPattern::Resolve (param.get_param_name (), param_tyty);
|
||||
}
|
||||
|
||||
const CanonicalPath *canonical_path = nullptr;
|
||||
bool ok
|
||||
= mappings->lookup_canonical_path (function.get_mappings ().get_nodeid (),
|
||||
&canonical_path);
|
||||
rust_assert (ok);
|
||||
|
||||
RustIdent ident{*canonical_path, function.get_locus ()};
|
||||
auto fnType = new TyTy::FnType (function.get_mappings ().get_hirid (),
|
||||
function.get_mappings ().get_defid (),
|
||||
function.get_function_name (), ident,
|
||||
function.is_method ()
|
||||
? TyTy::FnType::FNTYPE_IS_METHOD_FLAG
|
||||
: TyTy::FnType::FNTYPE_DEFAULT_FLAGS,
|
||||
ABI::RUST, std::move (params), ret_type,
|
||||
std::move (substitutions));
|
||||
|
||||
context->insert_type (function.get_mappings (), fnType);
|
||||
}
|
||||
void visit (HIR::TypeAlias &alias) override;
|
||||
void visit (HIR::ConstantItem &constant) override;
|
||||
void visit (HIR::Function &function) override;
|
||||
|
||||
private:
|
||||
TypeCheckTopLevelImplItem (
|
||||
TyTy::BaseType *self,
|
||||
std::vector<TyTy::SubstitutionParamMapping> substitutions)
|
||||
: TypeCheckBase (), self (self), substitutions (substitutions)
|
||||
{}
|
||||
std::vector<TyTy::SubstitutionParamMapping> substitutions);
|
||||
|
||||
TyTy::BaseType *self;
|
||||
std::vector<TyTy::SubstitutionParamMapping> substitutions;
|
||||
};
|
||||
|
||||
class TypeCheckImplItem : public TypeCheckBase
|
||||
class TypeCheckImplItem : public TypeCheckBase, public HIR::HIRImplVisitor
|
||||
{
|
||||
public:
|
||||
using Rust::Resolver::TypeCheckBase::visit;
|
||||
|
||||
static void Resolve (HIR::ImplBlock *parent, HIR::ImplItem *item,
|
||||
TyTy::BaseType *self)
|
||||
{
|
||||
TypeCheckImplItem resolver (parent, self);
|
||||
item->accept_vis (resolver);
|
||||
}
|
||||
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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -0,0 +1,498 @@
|
|||
// Copyright (C) 2020-2022 Free Software Foundation, Inc.
|
||||
|
||||
// This file is part of GCC.
|
||||
|
||||
// GCC is free software; you can redistribute it and/or modify it under
|
||||
// the terms of the GNU General Public License as published by the Free
|
||||
// Software Foundation; either version 3, or (at your option) any later
|
||||
// version.
|
||||
|
||||
// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
// for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with GCC; see the file COPYING3. If not see
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "rust-hir-type-check-stmt.h"
|
||||
#include "rust-hir-full.h"
|
||||
#include "rust-hir-type-check-type.h"
|
||||
#include "rust-hir-type-check-expr.h"
|
||||
#include "rust-hir-type-check-enumitem.h"
|
||||
#include "rust-hir-type-check-implitem.h"
|
||||
#include "rust-hir-type-check-pattern.h"
|
||||
|
||||
namespace Rust {
|
||||
namespace Resolver {
|
||||
|
||||
TyTy::BaseType *
|
||||
TypeCheckStmt::Resolve (HIR::Stmt *stmt)
|
||||
{
|
||||
TypeCheckStmt resolver;
|
||||
stmt->accept_vis (resolver);
|
||||
return resolver.infered;
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckStmt::visit (HIR::ExprStmtWithBlock &stmt)
|
||||
{
|
||||
infered = TypeCheckExpr::Resolve (stmt.get_expr ());
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckStmt::visit (HIR::ExprStmtWithoutBlock &stmt)
|
||||
{
|
||||
infered = TypeCheckExpr::Resolve (stmt.get_expr ());
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckStmt::visit (HIR::EmptyStmt &stmt)
|
||||
{
|
||||
infered = TyTy::TupleType::get_unit_type (stmt.get_mappings ().get_hirid ());
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckStmt::visit (HIR::ExternBlock &extern_block)
|
||||
{
|
||||
for (auto &item : extern_block.get_extern_items ())
|
||||
{
|
||||
TypeCheckTopLevelExternItem::Resolve (item.get (), extern_block);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckStmt::visit (HIR::ConstantItem &constant)
|
||||
{
|
||||
TyTy::BaseType *type = TypeCheckType::Resolve (constant.get_type ());
|
||||
TyTy::BaseType *expr_type = TypeCheckExpr::Resolve (constant.get_expr ());
|
||||
|
||||
infered = type->unify (expr_type);
|
||||
context->insert_type (constant.get_mappings (), infered);
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckStmt::visit (HIR::LetStmt &stmt)
|
||||
{
|
||||
infered = TyTy::TupleType::get_unit_type (stmt.get_mappings ().get_hirid ());
|
||||
|
||||
const HIR::Pattern &stmt_pattern = *stmt.get_pattern ();
|
||||
TyTy::BaseType *init_expr_ty = nullptr;
|
||||
if (stmt.has_init_expr ())
|
||||
{
|
||||
init_expr_ty = TypeCheckExpr::Resolve (stmt.get_init_expr ());
|
||||
if (init_expr_ty->get_kind () == TyTy::TypeKind::ERROR)
|
||||
return;
|
||||
|
||||
init_expr_ty->append_reference (
|
||||
stmt_pattern.get_pattern_mappings ().get_hirid ());
|
||||
}
|
||||
|
||||
TyTy::BaseType *specified_ty = nullptr;
|
||||
if (stmt.has_type ())
|
||||
specified_ty = TypeCheckType::Resolve (stmt.get_type ());
|
||||
|
||||
// let x:i32 = 123;
|
||||
if (specified_ty != nullptr && init_expr_ty != nullptr)
|
||||
{
|
||||
// FIXME use this result and look at the regressions
|
||||
coercion_site (stmt.get_mappings ().get_hirid (), specified_ty,
|
||||
init_expr_ty, stmt.get_locus ());
|
||||
context->insert_type (stmt_pattern.get_pattern_mappings (), specified_ty);
|
||||
}
|
||||
else
|
||||
{
|
||||
// let x:i32;
|
||||
if (specified_ty != nullptr)
|
||||
{
|
||||
context->insert_type (stmt_pattern.get_pattern_mappings (),
|
||||
specified_ty);
|
||||
}
|
||||
// let x = 123;
|
||||
else if (init_expr_ty != nullptr)
|
||||
{
|
||||
context->insert_type (stmt_pattern.get_pattern_mappings (),
|
||||
init_expr_ty);
|
||||
}
|
||||
// let x;
|
||||
else
|
||||
{
|
||||
context->insert_type (
|
||||
stmt_pattern.get_pattern_mappings (),
|
||||
new TyTy::InferType (
|
||||
stmt_pattern.get_pattern_mappings ().get_hirid (),
|
||||
TyTy::InferType::InferTypeKind::GENERAL, stmt.get_locus ()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckStmt::visit (HIR::TupleStruct &struct_decl)
|
||||
{
|
||||
std::vector<TyTy::SubstitutionParamMapping> substitutions;
|
||||
if (struct_decl.has_generics ())
|
||||
{
|
||||
for (auto &generic_param : struct_decl.get_generic_params ())
|
||||
{
|
||||
switch (generic_param.get ()->get_kind ())
|
||||
{
|
||||
case HIR::GenericParam::GenericKind::LIFETIME:
|
||||
case HIR::GenericParam::GenericKind::CONST:
|
||||
// FIXME: Skipping Lifetime and Const completely until better
|
||||
// handling.
|
||||
break;
|
||||
|
||||
case HIR::GenericParam::GenericKind::TYPE: {
|
||||
auto param_type
|
||||
= TypeResolveGenericParam::Resolve (generic_param.get ());
|
||||
context->insert_type (generic_param->get_mappings (),
|
||||
param_type);
|
||||
|
||||
substitutions.push_back (TyTy::SubstitutionParamMapping (
|
||||
static_cast<HIR::TypeParam &> (*generic_param), param_type));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<TyTy::StructFieldType *> fields;
|
||||
size_t idx = 0;
|
||||
for (auto &field : struct_decl.get_fields ())
|
||||
{
|
||||
TyTy::BaseType *field_type
|
||||
= TypeCheckType::Resolve (field.get_field_type ().get ());
|
||||
TyTy::StructFieldType *ty_field
|
||||
= new TyTy::StructFieldType (field.get_mappings ().get_hirid (),
|
||||
std::to_string (idx), field_type);
|
||||
fields.push_back (ty_field);
|
||||
context->insert_type (field.get_mappings (), ty_field->get_field_type ());
|
||||
idx++;
|
||||
}
|
||||
|
||||
// get the path
|
||||
const CanonicalPath *canonical_path = nullptr;
|
||||
bool ok = mappings->lookup_canonical_path (
|
||||
struct_decl.get_mappings ().get_nodeid (), &canonical_path);
|
||||
rust_assert (ok);
|
||||
RustIdent ident{*canonical_path, struct_decl.get_locus ()};
|
||||
|
||||
// there is only a single variant
|
||||
std::vector<TyTy::VariantDef *> variants;
|
||||
variants.push_back (new TyTy::VariantDef (
|
||||
struct_decl.get_mappings ().get_hirid (), struct_decl.get_identifier (),
|
||||
ident, TyTy::VariantDef::VariantType::TUPLE, nullptr, std::move (fields)));
|
||||
|
||||
// Process #[repr(...)] attribute, if any
|
||||
const AST::AttrVec &attrs = struct_decl.get_outer_attrs ();
|
||||
TyTy::ADTType::ReprOptions repr
|
||||
= parse_repr_options (attrs, struct_decl.get_locus ());
|
||||
|
||||
TyTy::BaseType *type
|
||||
= new TyTy::ADTType (struct_decl.get_mappings ().get_hirid (),
|
||||
mappings->get_next_hir_id (),
|
||||
struct_decl.get_identifier (), ident,
|
||||
TyTy::ADTType::ADTKind::TUPLE_STRUCT,
|
||||
std::move (variants), std::move (substitutions), repr);
|
||||
|
||||
context->insert_type (struct_decl.get_mappings (), type);
|
||||
infered = type;
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckStmt::visit (HIR::Enum &enum_decl)
|
||||
{
|
||||
std::vector<TyTy::SubstitutionParamMapping> substitutions;
|
||||
if (enum_decl.has_generics ())
|
||||
{
|
||||
for (auto &generic_param : enum_decl.get_generic_params ())
|
||||
{
|
||||
switch (generic_param.get ()->get_kind ())
|
||||
{
|
||||
case HIR::GenericParam::GenericKind::LIFETIME:
|
||||
case HIR::GenericParam::GenericKind::CONST:
|
||||
// FIXME: Skipping Lifetime and Const completely until better
|
||||
// handling.
|
||||
break;
|
||||
|
||||
case HIR::GenericParam::GenericKind::TYPE: {
|
||||
auto param_type
|
||||
= TypeResolveGenericParam::Resolve (generic_param.get ());
|
||||
context->insert_type (generic_param->get_mappings (),
|
||||
param_type);
|
||||
|
||||
substitutions.push_back (TyTy::SubstitutionParamMapping (
|
||||
static_cast<HIR::TypeParam &> (*generic_param), param_type));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<TyTy::VariantDef *> variants;
|
||||
int64_t discriminant_value = 0;
|
||||
for (auto &variant : enum_decl.get_variants ())
|
||||
{
|
||||
TyTy::VariantDef *field_type
|
||||
= TypeCheckEnumItem::Resolve (variant.get (), discriminant_value);
|
||||
|
||||
discriminant_value++;
|
||||
variants.push_back (field_type);
|
||||
}
|
||||
|
||||
// get the path
|
||||
const CanonicalPath *canonical_path = nullptr;
|
||||
bool ok
|
||||
= mappings->lookup_canonical_path (enum_decl.get_mappings ().get_nodeid (),
|
||||
&canonical_path);
|
||||
rust_assert (ok);
|
||||
RustIdent ident{*canonical_path, enum_decl.get_locus ()};
|
||||
|
||||
TyTy::BaseType *type
|
||||
= new TyTy::ADTType (enum_decl.get_mappings ().get_hirid (),
|
||||
mappings->get_next_hir_id (),
|
||||
enum_decl.get_identifier (), ident,
|
||||
TyTy::ADTType::ADTKind::ENUM, std::move (variants),
|
||||
std::move (substitutions));
|
||||
|
||||
context->insert_type (enum_decl.get_mappings (), type);
|
||||
infered = type;
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckStmt::visit (HIR::StructStruct &struct_decl)
|
||||
{
|
||||
std::vector<TyTy::SubstitutionParamMapping> substitutions;
|
||||
if (struct_decl.has_generics ())
|
||||
{
|
||||
for (auto &generic_param : struct_decl.get_generic_params ())
|
||||
{
|
||||
switch (generic_param.get ()->get_kind ())
|
||||
{
|
||||
case HIR::GenericParam::GenericKind::LIFETIME:
|
||||
case HIR::GenericParam::GenericKind::CONST:
|
||||
// FIXME: Skipping Lifetime and Const completely until better
|
||||
// handling.
|
||||
break;
|
||||
|
||||
case HIR::GenericParam::GenericKind::TYPE: {
|
||||
auto param_type
|
||||
= TypeResolveGenericParam::Resolve (generic_param.get ());
|
||||
context->insert_type (generic_param->get_mappings (),
|
||||
param_type);
|
||||
|
||||
substitutions.push_back (TyTy::SubstitutionParamMapping (
|
||||
static_cast<HIR::TypeParam &> (*generic_param), param_type));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<TyTy::StructFieldType *> fields;
|
||||
for (auto &field : struct_decl.get_fields ())
|
||||
{
|
||||
TyTy::BaseType *field_type
|
||||
= TypeCheckType::Resolve (field.get_field_type ().get ());
|
||||
TyTy::StructFieldType *ty_field
|
||||
= new TyTy::StructFieldType (field.get_mappings ().get_hirid (),
|
||||
field.get_field_name (), field_type);
|
||||
fields.push_back (ty_field);
|
||||
context->insert_type (field.get_mappings (), ty_field->get_field_type ());
|
||||
}
|
||||
|
||||
// get the path
|
||||
const CanonicalPath *canonical_path = nullptr;
|
||||
bool ok = mappings->lookup_canonical_path (
|
||||
struct_decl.get_mappings ().get_nodeid (), &canonical_path);
|
||||
rust_assert (ok);
|
||||
RustIdent ident{*canonical_path, struct_decl.get_locus ()};
|
||||
|
||||
// there is only a single variant
|
||||
std::vector<TyTy::VariantDef *> variants;
|
||||
variants.push_back (new TyTy::VariantDef (
|
||||
struct_decl.get_mappings ().get_hirid (), struct_decl.get_identifier (),
|
||||
ident, TyTy::VariantDef::VariantType::STRUCT, nullptr, std::move (fields)));
|
||||
|
||||
// Process #[repr(...)] attribute, if any
|
||||
const AST::AttrVec &attrs = struct_decl.get_outer_attrs ();
|
||||
TyTy::ADTType::ReprOptions repr
|
||||
= parse_repr_options (attrs, struct_decl.get_locus ());
|
||||
|
||||
TyTy::BaseType *type
|
||||
= new TyTy::ADTType (struct_decl.get_mappings ().get_hirid (),
|
||||
mappings->get_next_hir_id (),
|
||||
struct_decl.get_identifier (), ident,
|
||||
TyTy::ADTType::ADTKind::STRUCT_STRUCT,
|
||||
std::move (variants), std::move (substitutions), repr);
|
||||
|
||||
context->insert_type (struct_decl.get_mappings (), type);
|
||||
infered = type;
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckStmt::visit (HIR::Union &union_decl)
|
||||
{
|
||||
std::vector<TyTy::SubstitutionParamMapping> substitutions;
|
||||
if (union_decl.has_generics ())
|
||||
{
|
||||
for (auto &generic_param : union_decl.get_generic_params ())
|
||||
{
|
||||
switch (generic_param.get ()->get_kind ())
|
||||
{
|
||||
case HIR::GenericParam::GenericKind::LIFETIME:
|
||||
case HIR::GenericParam::GenericKind::CONST:
|
||||
// FIXME: Skipping Lifetime and Const completely until better
|
||||
// handling.
|
||||
break;
|
||||
|
||||
case HIR::GenericParam::GenericKind::TYPE: {
|
||||
auto param_type
|
||||
= TypeResolveGenericParam::Resolve (generic_param.get ());
|
||||
context->insert_type (generic_param->get_mappings (),
|
||||
param_type);
|
||||
|
||||
substitutions.push_back (TyTy::SubstitutionParamMapping (
|
||||
static_cast<HIR::TypeParam &> (*generic_param), param_type));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<TyTy::StructFieldType *> fields;
|
||||
for (auto &variant : union_decl.get_variants ())
|
||||
{
|
||||
TyTy::BaseType *variant_type
|
||||
= TypeCheckType::Resolve (variant.get_field_type ().get ());
|
||||
TyTy::StructFieldType *ty_variant
|
||||
= new TyTy::StructFieldType (variant.get_mappings ().get_hirid (),
|
||||
variant.get_field_name (), variant_type);
|
||||
fields.push_back (ty_variant);
|
||||
context->insert_type (variant.get_mappings (),
|
||||
ty_variant->get_field_type ());
|
||||
}
|
||||
|
||||
// get the path
|
||||
const CanonicalPath *canonical_path = nullptr;
|
||||
bool ok
|
||||
= mappings->lookup_canonical_path (union_decl.get_mappings ().get_nodeid (),
|
||||
&canonical_path);
|
||||
rust_assert (ok);
|
||||
RustIdent ident{*canonical_path, union_decl.get_locus ()};
|
||||
|
||||
// there is only a single variant
|
||||
std::vector<TyTy::VariantDef *> variants;
|
||||
variants.push_back (new TyTy::VariantDef (
|
||||
union_decl.get_mappings ().get_hirid (), union_decl.get_identifier (),
|
||||
ident, TyTy::VariantDef::VariantType::STRUCT, nullptr, std::move (fields)));
|
||||
|
||||
TyTy::BaseType *type
|
||||
= new TyTy::ADTType (union_decl.get_mappings ().get_hirid (),
|
||||
mappings->get_next_hir_id (),
|
||||
union_decl.get_identifier (), ident,
|
||||
TyTy::ADTType::ADTKind::UNION, std::move (variants),
|
||||
std::move (substitutions));
|
||||
|
||||
context->insert_type (union_decl.get_mappings (), type);
|
||||
infered = type;
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckStmt::visit (HIR::Function &function)
|
||||
{
|
||||
std::vector<TyTy::SubstitutionParamMapping> substitutions;
|
||||
if (function.has_generics ())
|
||||
{
|
||||
for (auto &generic_param : function.get_generic_params ())
|
||||
{
|
||||
switch (generic_param.get ()->get_kind ())
|
||||
{
|
||||
case HIR::GenericParam::GenericKind::LIFETIME:
|
||||
case HIR::GenericParam::GenericKind::CONST:
|
||||
// FIXME: Skipping Lifetime and Const completely until better
|
||||
// handling.
|
||||
break;
|
||||
|
||||
case HIR::GenericParam::GenericKind::TYPE: {
|
||||
auto param_type
|
||||
= TypeResolveGenericParam::Resolve (generic_param.get ());
|
||||
context->insert_type (generic_param->get_mappings (),
|
||||
param_type);
|
||||
|
||||
substitutions.push_back (TyTy::SubstitutionParamMapping (
|
||||
static_cast<HIR::TypeParam &> (*generic_param), param_type));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TyTy::BaseType *ret_type = nullptr;
|
||||
if (!function.has_function_return_type ())
|
||||
ret_type
|
||||
= TyTy::TupleType::get_unit_type (function.get_mappings ().get_hirid ());
|
||||
else
|
||||
{
|
||||
auto resolved
|
||||
= TypeCheckType::Resolve (function.get_return_type ().get ());
|
||||
if (resolved == nullptr)
|
||||
{
|
||||
rust_error_at (function.get_locus (),
|
||||
"failed to resolve return type");
|
||||
return;
|
||||
}
|
||||
|
||||
ret_type = resolved->clone ();
|
||||
ret_type->set_ref (
|
||||
function.get_return_type ()->get_mappings ().get_hirid ());
|
||||
}
|
||||
|
||||
std::vector<std::pair<HIR::Pattern *, TyTy::BaseType *> > params;
|
||||
for (auto ¶m : function.get_function_params ())
|
||||
{
|
||||
// get the name as well required for later on
|
||||
auto param_tyty = TypeCheckType::Resolve (param.get_type ());
|
||||
params.push_back (
|
||||
std::pair<HIR::Pattern *, TyTy::BaseType *> (param.get_param_name (),
|
||||
param_tyty));
|
||||
|
||||
context->insert_type (param.get_mappings (), param_tyty);
|
||||
TypeCheckPattern::Resolve (param.get_param_name (), param_tyty);
|
||||
}
|
||||
|
||||
// get the path
|
||||
const CanonicalPath *canonical_path = nullptr;
|
||||
bool ok
|
||||
= mappings->lookup_canonical_path (function.get_mappings ().get_nodeid (),
|
||||
&canonical_path);
|
||||
rust_assert (ok);
|
||||
|
||||
RustIdent ident{*canonical_path, function.get_locus ()};
|
||||
auto fnType = new TyTy::FnType (function.get_mappings ().get_hirid (),
|
||||
function.get_mappings ().get_defid (),
|
||||
function.get_function_name (), ident,
|
||||
TyTy::FnType::FNTYPE_DEFAULT_FLAGS, ABI::RUST,
|
||||
std::move (params), ret_type,
|
||||
std::move (substitutions));
|
||||
context->insert_type (function.get_mappings (), fnType);
|
||||
|
||||
TyTy::FnType *resolved_fn_type = fnType;
|
||||
auto expected_ret_tyty = resolved_fn_type->get_return_type ();
|
||||
context->push_return_type (TypeCheckContextItem (&function),
|
||||
expected_ret_tyty);
|
||||
|
||||
auto block_expr_ty
|
||||
= TypeCheckExpr::Resolve (function.get_definition ().get ());
|
||||
|
||||
context->pop_return_type ();
|
||||
|
||||
if (block_expr_ty->get_kind () != TyTy::NEVER)
|
||||
expected_ret_tyty->unify (block_expr_ty);
|
||||
|
||||
infered = fnType;
|
||||
}
|
||||
|
||||
} // namespace Resolver
|
||||
} // namespace Rust
|
|
@ -20,489 +20,68 @@
|
|||
#define RUST_HIR_TYPE_CHECK_STMT
|
||||
|
||||
#include "rust-hir-type-check-base.h"
|
||||
#include "rust-hir-full.h"
|
||||
#include "rust-hir-type-check-type.h"
|
||||
#include "rust-hir-type-check-expr.h"
|
||||
#include "rust-hir-type-check-enumitem.h"
|
||||
#include "rust-hir-type-check-implitem.h"
|
||||
|
||||
namespace Rust {
|
||||
namespace Resolver {
|
||||
|
||||
class TypeCheckStmt : public TypeCheckBase
|
||||
class TypeCheckStmt : private TypeCheckBase, private HIR::HIRStmtVisitor
|
||||
{
|
||||
using Rust::Resolver::TypeCheckBase::visit;
|
||||
|
||||
public:
|
||||
static TyTy::BaseType *Resolve (HIR::Stmt *stmt)
|
||||
{
|
||||
TypeCheckStmt resolver;
|
||||
stmt->accept_vis (resolver);
|
||||
return resolver.infered;
|
||||
static TyTy::BaseType *Resolve (HIR::Stmt *stmt);
|
||||
|
||||
void visit (HIR::ExprStmtWithBlock &stmt) override;
|
||||
void visit (HIR::ExprStmtWithoutBlock &stmt) override;
|
||||
void visit (HIR::EmptyStmt &stmt) override;
|
||||
void visit (HIR::ExternBlock &extern_block) override;
|
||||
void visit (HIR::ConstantItem &constant) override;
|
||||
void visit (HIR::LetStmt &stmt) override;
|
||||
void visit (HIR::TupleStruct &struct_decl) override;
|
||||
void visit (HIR::Enum &enum_decl) override;
|
||||
void visit (HIR::StructStruct &struct_decl) override;
|
||||
void visit (HIR::Union &union_decl) override;
|
||||
void visit (HIR::Function &function) override;
|
||||
|
||||
void visit (HIR::EnumItemTuple &) override
|
||||
{ /* TODO? */
|
||||
}
|
||||
|
||||
void visit (HIR::ExprStmtWithBlock &stmt) override
|
||||
{
|
||||
infered = TypeCheckExpr::Resolve (stmt.get_expr ());
|
||||
void visit (HIR::EnumItemStruct &) override
|
||||
{ /* TODO? */
|
||||
}
|
||||
|
||||
void visit (HIR::ExprStmtWithoutBlock &stmt) override
|
||||
{
|
||||
infered = TypeCheckExpr::Resolve (stmt.get_expr ());
|
||||
void visit (HIR::EnumItem &item) override
|
||||
{ /* TODO? */
|
||||
}
|
||||
|
||||
void visit (HIR::EmptyStmt &stmt) override
|
||||
{
|
||||
infered
|
||||
= TyTy::TupleType::get_unit_type (stmt.get_mappings ().get_hirid ());
|
||||
void visit (HIR::EnumItemDiscriminant &) override
|
||||
{ /* TODO? */
|
||||
}
|
||||
|
||||
void visit (HIR::ExternBlock &extern_block) override
|
||||
{
|
||||
for (auto &item : extern_block.get_extern_items ())
|
||||
{
|
||||
TypeCheckTopLevelExternItem::Resolve (item.get (), extern_block);
|
||||
}
|
||||
void visit (HIR::TypePathSegmentFunction &segment) override
|
||||
{ /* TODO? */
|
||||
}
|
||||
|
||||
void visit (HIR::ConstantItem &constant) override
|
||||
{
|
||||
TyTy::BaseType *type = TypeCheckType::Resolve (constant.get_type ());
|
||||
TyTy::BaseType *expr_type = TypeCheckExpr::Resolve (constant.get_expr ());
|
||||
|
||||
infered = type->unify (expr_type);
|
||||
context->insert_type (constant.get_mappings (), infered);
|
||||
void visit (HIR::TypePath &path) override
|
||||
{ /* TODO? */
|
||||
}
|
||||
|
||||
void visit (HIR::LetStmt &stmt) override
|
||||
{
|
||||
infered
|
||||
= TyTy::TupleType::get_unit_type (stmt.get_mappings ().get_hirid ());
|
||||
|
||||
const HIR::Pattern &stmt_pattern = *stmt.get_pattern ();
|
||||
TyTy::BaseType *init_expr_ty = nullptr;
|
||||
if (stmt.has_init_expr ())
|
||||
{
|
||||
init_expr_ty = TypeCheckExpr::Resolve (stmt.get_init_expr ());
|
||||
if (init_expr_ty->get_kind () == TyTy::TypeKind::ERROR)
|
||||
return;
|
||||
|
||||
init_expr_ty->append_reference (
|
||||
stmt_pattern.get_pattern_mappings ().get_hirid ());
|
||||
}
|
||||
|
||||
TyTy::BaseType *specified_ty = nullptr;
|
||||
if (stmt.has_type ())
|
||||
specified_ty = TypeCheckType::Resolve (stmt.get_type ());
|
||||
|
||||
// let x:i32 = 123;
|
||||
if (specified_ty != nullptr && init_expr_ty != nullptr)
|
||||
{
|
||||
// FIXME use this result and look at the regressions
|
||||
coercion_site (stmt.get_mappings ().get_hirid (), specified_ty,
|
||||
init_expr_ty, stmt.get_locus ());
|
||||
context->insert_type (stmt_pattern.get_pattern_mappings (),
|
||||
specified_ty);
|
||||
}
|
||||
else
|
||||
{
|
||||
// let x:i32;
|
||||
if (specified_ty != nullptr)
|
||||
{
|
||||
context->insert_type (stmt_pattern.get_pattern_mappings (),
|
||||
specified_ty);
|
||||
}
|
||||
// let x = 123;
|
||||
else if (init_expr_ty != nullptr)
|
||||
{
|
||||
context->insert_type (stmt_pattern.get_pattern_mappings (),
|
||||
init_expr_ty);
|
||||
}
|
||||
// let x;
|
||||
else
|
||||
{
|
||||
context->insert_type (
|
||||
stmt_pattern.get_pattern_mappings (),
|
||||
new TyTy::InferType (
|
||||
stmt_pattern.get_pattern_mappings ().get_hirid (),
|
||||
TyTy::InferType::InferTypeKind::GENERAL, stmt.get_locus ()));
|
||||
}
|
||||
}
|
||||
void visit (HIR::QualifiedPathInType &path) override
|
||||
{ /* TODO? */
|
||||
}
|
||||
|
||||
void visit (HIR::TupleStruct &struct_decl) override
|
||||
{
|
||||
std::vector<TyTy::SubstitutionParamMapping> substitutions;
|
||||
if (struct_decl.has_generics ())
|
||||
{
|
||||
for (auto &generic_param : struct_decl.get_generic_params ())
|
||||
{
|
||||
switch (generic_param.get ()->get_kind ())
|
||||
{
|
||||
case HIR::GenericParam::GenericKind::LIFETIME:
|
||||
case HIR::GenericParam::GenericKind::CONST:
|
||||
// FIXME: Skipping Lifetime and Const completely until better
|
||||
// handling.
|
||||
break;
|
||||
|
||||
case HIR::GenericParam::GenericKind::TYPE: {
|
||||
auto param_type
|
||||
= TypeResolveGenericParam::Resolve (generic_param.get ());
|
||||
context->insert_type (generic_param->get_mappings (),
|
||||
param_type);
|
||||
|
||||
substitutions.push_back (TyTy::SubstitutionParamMapping (
|
||||
static_cast<HIR::TypeParam &> (*generic_param),
|
||||
param_type));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<TyTy::StructFieldType *> fields;
|
||||
size_t idx = 0;
|
||||
for (auto &field : struct_decl.get_fields ())
|
||||
{
|
||||
TyTy::BaseType *field_type
|
||||
= TypeCheckType::Resolve (field.get_field_type ().get ());
|
||||
TyTy::StructFieldType *ty_field
|
||||
= new TyTy::StructFieldType (field.get_mappings ().get_hirid (),
|
||||
std::to_string (idx), field_type);
|
||||
fields.push_back (ty_field);
|
||||
context->insert_type (field.get_mappings (),
|
||||
ty_field->get_field_type ());
|
||||
idx++;
|
||||
}
|
||||
|
||||
// get the path
|
||||
const CanonicalPath *canonical_path = nullptr;
|
||||
bool ok = mappings->lookup_canonical_path (
|
||||
struct_decl.get_mappings ().get_nodeid (), &canonical_path);
|
||||
rust_assert (ok);
|
||||
RustIdent ident{*canonical_path, struct_decl.get_locus ()};
|
||||
|
||||
// there is only a single variant
|
||||
std::vector<TyTy::VariantDef *> variants;
|
||||
variants.push_back (
|
||||
new TyTy::VariantDef (struct_decl.get_mappings ().get_hirid (),
|
||||
struct_decl.get_identifier (), ident,
|
||||
TyTy::VariantDef::VariantType::TUPLE, nullptr,
|
||||
std::move (fields)));
|
||||
|
||||
// Process #[repr(...)] attribute, if any
|
||||
const AST::AttrVec &attrs = struct_decl.get_outer_attrs ();
|
||||
TyTy::ADTType::ReprOptions repr
|
||||
= parse_repr_options (attrs, struct_decl.get_locus ());
|
||||
|
||||
TyTy::BaseType *type
|
||||
= new TyTy::ADTType (struct_decl.get_mappings ().get_hirid (),
|
||||
mappings->get_next_hir_id (),
|
||||
struct_decl.get_identifier (), ident,
|
||||
TyTy::ADTType::ADTKind::TUPLE_STRUCT,
|
||||
std::move (variants), std::move (substitutions),
|
||||
repr);
|
||||
|
||||
context->insert_type (struct_decl.get_mappings (), type);
|
||||
infered = type;
|
||||
void visit (HIR::Module &module) override
|
||||
{ /* TODO? */
|
||||
}
|
||||
|
||||
void visit (HIR::Enum &enum_decl) override
|
||||
{
|
||||
std::vector<TyTy::SubstitutionParamMapping> substitutions;
|
||||
if (enum_decl.has_generics ())
|
||||
{
|
||||
for (auto &generic_param : enum_decl.get_generic_params ())
|
||||
{
|
||||
switch (generic_param.get ()->get_kind ())
|
||||
{
|
||||
case HIR::GenericParam::GenericKind::LIFETIME:
|
||||
case HIR::GenericParam::GenericKind::CONST:
|
||||
// FIXME: Skipping Lifetime and Const completely until better
|
||||
// handling.
|
||||
break;
|
||||
|
||||
case HIR::GenericParam::GenericKind::TYPE: {
|
||||
auto param_type
|
||||
= TypeResolveGenericParam::Resolve (generic_param.get ());
|
||||
context->insert_type (generic_param->get_mappings (),
|
||||
param_type);
|
||||
|
||||
substitutions.push_back (TyTy::SubstitutionParamMapping (
|
||||
static_cast<HIR::TypeParam &> (*generic_param),
|
||||
param_type));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<TyTy::VariantDef *> variants;
|
||||
int64_t discriminant_value = 0;
|
||||
for (auto &variant : enum_decl.get_variants ())
|
||||
{
|
||||
TyTy::VariantDef *field_type
|
||||
= TypeCheckEnumItem::Resolve (variant.get (), discriminant_value);
|
||||
|
||||
discriminant_value++;
|
||||
variants.push_back (field_type);
|
||||
}
|
||||
|
||||
// get the path
|
||||
const CanonicalPath *canonical_path = nullptr;
|
||||
bool ok = mappings->lookup_canonical_path (
|
||||
enum_decl.get_mappings ().get_nodeid (), &canonical_path);
|
||||
rust_assert (ok);
|
||||
RustIdent ident{*canonical_path, enum_decl.get_locus ()};
|
||||
|
||||
TyTy::BaseType *type
|
||||
= new TyTy::ADTType (enum_decl.get_mappings ().get_hirid (),
|
||||
mappings->get_next_hir_id (),
|
||||
enum_decl.get_identifier (), ident,
|
||||
TyTy::ADTType::ADTKind::ENUM, std::move (variants),
|
||||
std::move (substitutions));
|
||||
|
||||
context->insert_type (enum_decl.get_mappings (), type);
|
||||
infered = type;
|
||||
void visit (HIR::ExternCrate &crate) override
|
||||
{ /* TODO? */
|
||||
}
|
||||
|
||||
void visit (HIR::StructStruct &struct_decl) override
|
||||
{
|
||||
std::vector<TyTy::SubstitutionParamMapping> substitutions;
|
||||
if (struct_decl.has_generics ())
|
||||
{
|
||||
for (auto &generic_param : struct_decl.get_generic_params ())
|
||||
{
|
||||
switch (generic_param.get ()->get_kind ())
|
||||
{
|
||||
case HIR::GenericParam::GenericKind::LIFETIME:
|
||||
case HIR::GenericParam::GenericKind::CONST:
|
||||
// FIXME: Skipping Lifetime and Const completely until better
|
||||
// handling.
|
||||
break;
|
||||
|
||||
case HIR::GenericParam::GenericKind::TYPE: {
|
||||
auto param_type
|
||||
= TypeResolveGenericParam::Resolve (generic_param.get ());
|
||||
context->insert_type (generic_param->get_mappings (),
|
||||
param_type);
|
||||
|
||||
substitutions.push_back (TyTy::SubstitutionParamMapping (
|
||||
static_cast<HIR::TypeParam &> (*generic_param),
|
||||
param_type));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<TyTy::StructFieldType *> fields;
|
||||
for (auto &field : struct_decl.get_fields ())
|
||||
{
|
||||
TyTy::BaseType *field_type
|
||||
= TypeCheckType::Resolve (field.get_field_type ().get ());
|
||||
TyTy::StructFieldType *ty_field
|
||||
= new TyTy::StructFieldType (field.get_mappings ().get_hirid (),
|
||||
field.get_field_name (), field_type);
|
||||
fields.push_back (ty_field);
|
||||
context->insert_type (field.get_mappings (),
|
||||
ty_field->get_field_type ());
|
||||
}
|
||||
|
||||
// get the path
|
||||
const CanonicalPath *canonical_path = nullptr;
|
||||
bool ok = mappings->lookup_canonical_path (
|
||||
struct_decl.get_mappings ().get_nodeid (), &canonical_path);
|
||||
rust_assert (ok);
|
||||
RustIdent ident{*canonical_path, struct_decl.get_locus ()};
|
||||
|
||||
// there is only a single variant
|
||||
std::vector<TyTy::VariantDef *> variants;
|
||||
variants.push_back (
|
||||
new TyTy::VariantDef (struct_decl.get_mappings ().get_hirid (),
|
||||
struct_decl.get_identifier (), ident,
|
||||
TyTy::VariantDef::VariantType::STRUCT, nullptr,
|
||||
std::move (fields)));
|
||||
|
||||
// Process #[repr(...)] attribute, if any
|
||||
const AST::AttrVec &attrs = struct_decl.get_outer_attrs ();
|
||||
TyTy::ADTType::ReprOptions repr
|
||||
= parse_repr_options (attrs, struct_decl.get_locus ());
|
||||
|
||||
TyTy::BaseType *type
|
||||
= new TyTy::ADTType (struct_decl.get_mappings ().get_hirid (),
|
||||
mappings->get_next_hir_id (),
|
||||
struct_decl.get_identifier (), ident,
|
||||
TyTy::ADTType::ADTKind::STRUCT_STRUCT,
|
||||
std::move (variants), std::move (substitutions),
|
||||
repr);
|
||||
|
||||
context->insert_type (struct_decl.get_mappings (), type);
|
||||
infered = type;
|
||||
void visit (HIR::UseDeclaration &use_decl) override
|
||||
{ /* TODO? */
|
||||
}
|
||||
|
||||
void visit (HIR::Union &union_decl) override
|
||||
{
|
||||
std::vector<TyTy::SubstitutionParamMapping> substitutions;
|
||||
if (union_decl.has_generics ())
|
||||
{
|
||||
for (auto &generic_param : union_decl.get_generic_params ())
|
||||
{
|
||||
switch (generic_param.get ()->get_kind ())
|
||||
{
|
||||
case HIR::GenericParam::GenericKind::LIFETIME:
|
||||
case HIR::GenericParam::GenericKind::CONST:
|
||||
// FIXME: Skipping Lifetime and Const completely until better
|
||||
// handling.
|
||||
break;
|
||||
|
||||
case HIR::GenericParam::GenericKind::TYPE: {
|
||||
auto param_type
|
||||
= TypeResolveGenericParam::Resolve (generic_param.get ());
|
||||
context->insert_type (generic_param->get_mappings (),
|
||||
param_type);
|
||||
|
||||
substitutions.push_back (TyTy::SubstitutionParamMapping (
|
||||
static_cast<HIR::TypeParam &> (*generic_param),
|
||||
param_type));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<TyTy::StructFieldType *> fields;
|
||||
for (auto &variant : union_decl.get_variants ())
|
||||
{
|
||||
TyTy::BaseType *variant_type
|
||||
= TypeCheckType::Resolve (variant.get_field_type ().get ());
|
||||
TyTy::StructFieldType *ty_variant
|
||||
= new TyTy::StructFieldType (variant.get_mappings ().get_hirid (),
|
||||
variant.get_field_name (), variant_type);
|
||||
fields.push_back (ty_variant);
|
||||
context->insert_type (variant.get_mappings (),
|
||||
ty_variant->get_field_type ());
|
||||
}
|
||||
|
||||
// get the path
|
||||
const CanonicalPath *canonical_path = nullptr;
|
||||
bool ok = mappings->lookup_canonical_path (
|
||||
union_decl.get_mappings ().get_nodeid (), &canonical_path);
|
||||
rust_assert (ok);
|
||||
RustIdent ident{*canonical_path, union_decl.get_locus ()};
|
||||
|
||||
// there is only a single variant
|
||||
std::vector<TyTy::VariantDef *> variants;
|
||||
variants.push_back (
|
||||
new TyTy::VariantDef (union_decl.get_mappings ().get_hirid (),
|
||||
union_decl.get_identifier (), ident,
|
||||
TyTy::VariantDef::VariantType::STRUCT, nullptr,
|
||||
std::move (fields)));
|
||||
|
||||
TyTy::BaseType *type
|
||||
= new TyTy::ADTType (union_decl.get_mappings ().get_hirid (),
|
||||
mappings->get_next_hir_id (),
|
||||
union_decl.get_identifier (), ident,
|
||||
TyTy::ADTType::ADTKind::UNION, std::move (variants),
|
||||
std::move (substitutions));
|
||||
|
||||
context->insert_type (union_decl.get_mappings (), type);
|
||||
infered = type;
|
||||
void visit (HIR::TypeAlias &type_alias) override
|
||||
{ /* TODO? */
|
||||
}
|
||||
|
||||
void visit (HIR::Function &function) override
|
||||
{
|
||||
std::vector<TyTy::SubstitutionParamMapping> substitutions;
|
||||
if (function.has_generics ())
|
||||
{
|
||||
for (auto &generic_param : function.get_generic_params ())
|
||||
{
|
||||
switch (generic_param.get ()->get_kind ())
|
||||
{
|
||||
case HIR::GenericParam::GenericKind::LIFETIME:
|
||||
case HIR::GenericParam::GenericKind::CONST:
|
||||
// FIXME: Skipping Lifetime and Const completely until better
|
||||
// handling.
|
||||
break;
|
||||
|
||||
case HIR::GenericParam::GenericKind::TYPE: {
|
||||
auto param_type
|
||||
= TypeResolveGenericParam::Resolve (generic_param.get ());
|
||||
context->insert_type (generic_param->get_mappings (),
|
||||
param_type);
|
||||
|
||||
substitutions.push_back (TyTy::SubstitutionParamMapping (
|
||||
static_cast<HIR::TypeParam &> (*generic_param),
|
||||
param_type));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TyTy::BaseType *ret_type = nullptr;
|
||||
if (!function.has_function_return_type ())
|
||||
ret_type = TyTy::TupleType::get_unit_type (
|
||||
function.get_mappings ().get_hirid ());
|
||||
else
|
||||
{
|
||||
auto resolved
|
||||
= TypeCheckType::Resolve (function.get_return_type ().get ());
|
||||
if (resolved == nullptr)
|
||||
{
|
||||
rust_error_at (function.get_locus (),
|
||||
"failed to resolve return type");
|
||||
return;
|
||||
}
|
||||
|
||||
ret_type = resolved->clone ();
|
||||
ret_type->set_ref (
|
||||
function.get_return_type ()->get_mappings ().get_hirid ());
|
||||
}
|
||||
|
||||
std::vector<std::pair<HIR::Pattern *, TyTy::BaseType *> > params;
|
||||
for (auto ¶m : function.get_function_params ())
|
||||
{
|
||||
// get the name as well required for later on
|
||||
auto param_tyty = TypeCheckType::Resolve (param.get_type ());
|
||||
params.push_back (
|
||||
std::pair<HIR::Pattern *, TyTy::BaseType *> (param.get_param_name (),
|
||||
param_tyty));
|
||||
|
||||
context->insert_type (param.get_mappings (), param_tyty);
|
||||
TypeCheckPattern::Resolve (param.get_param_name (), param_tyty);
|
||||
}
|
||||
|
||||
// get the path
|
||||
const CanonicalPath *canonical_path = nullptr;
|
||||
bool ok
|
||||
= mappings->lookup_canonical_path (function.get_mappings ().get_nodeid (),
|
||||
&canonical_path);
|
||||
rust_assert (ok);
|
||||
|
||||
RustIdent ident{*canonical_path, function.get_locus ()};
|
||||
auto fnType = new TyTy::FnType (function.get_mappings ().get_hirid (),
|
||||
function.get_mappings ().get_defid (),
|
||||
function.get_function_name (), ident,
|
||||
TyTy::FnType::FNTYPE_DEFAULT_FLAGS,
|
||||
ABI::RUST, std::move (params), ret_type,
|
||||
std::move (substitutions));
|
||||
context->insert_type (function.get_mappings (), fnType);
|
||||
|
||||
TyTy::FnType *resolved_fn_type = fnType;
|
||||
auto expected_ret_tyty = resolved_fn_type->get_return_type ();
|
||||
context->push_return_type (TypeCheckContextItem (&function),
|
||||
expected_ret_tyty);
|
||||
|
||||
auto block_expr_ty
|
||||
= TypeCheckExpr::Resolve (function.get_definition ().get ());
|
||||
|
||||
context->pop_return_type ();
|
||||
|
||||
if (block_expr_ty->get_kind () != TyTy::NEVER)
|
||||
expected_ret_tyty->unify (block_expr_ty);
|
||||
|
||||
infered = fnType;
|
||||
void visit (HIR::StaticItem &static_item) override
|
||||
{ /* TODO? */
|
||||
}
|
||||
void visit (HIR::Trait &trait) override
|
||||
{ /* TODO? */
|
||||
}
|
||||
void visit (HIR::ImplBlock &impl) override
|
||||
{ /* TODO? */
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 ¶m)
|
||||
{
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
void
|
||||
TypeResolveGenericParam::visit (HIR::ConstGenericParam ¶m)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
void
|
||||
TypeResolveGenericParam::visit (HIR::TypeParam ¶m)
|
||||
{
|
||||
|
@ -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
|
||||
|
|
|
@ -27,14 +27,15 @@
|
|||
namespace Rust {
|
||||
namespace Resolver {
|
||||
|
||||
// FIXME
|
||||
// This simply fetches the HIR:::GenericArgs from the base class. Check to see
|
||||
// if we can get rid of this class
|
||||
class TypeCheckResolveGenericArguments : public TypeCheckBase
|
||||
{
|
||||
using Rust::Resolver::TypeCheckBase::visit;
|
||||
|
||||
public:
|
||||
static HIR::GenericArgs resolve (HIR::TypePathSegment *segment);
|
||||
|
||||
void visit (HIR::TypePathSegmentGeneric &generic) override;
|
||||
void visit (HIR::TypePathSegmentGeneric &generic);
|
||||
|
||||
private:
|
||||
TypeCheckResolveGenericArguments (Location locus)
|
||||
|
@ -44,10 +45,8 @@ private:
|
|||
HIR::GenericArgs args;
|
||||
};
|
||||
|
||||
class TypeCheckType : public TypeCheckBase
|
||||
class TypeCheckType : public TypeCheckBase, public HIR::HIRTypeVisitor
|
||||
{
|
||||
using Rust::Resolver::TypeCheckBase::visit;
|
||||
|
||||
public:
|
||||
static TyTy::BaseType *Resolve (HIR::Type *type);
|
||||
|
||||
|
@ -63,6 +62,22 @@ public:
|
|||
void visit (HIR::NeverType &type) override;
|
||||
void visit (HIR::TraitObjectType &type) override;
|
||||
|
||||
void visit (HIR::TypePathSegmentFunction &segment) override
|
||||
{ /* TODO */
|
||||
}
|
||||
void visit (HIR::TraitBound &bound) override
|
||||
{ /* TODO */
|
||||
}
|
||||
void visit (HIR::ImplTraitType &type) override
|
||||
{ /* TODO */
|
||||
}
|
||||
void visit (HIR::ParenthesisedType &type) override
|
||||
{ /* TODO */
|
||||
}
|
||||
void visit (HIR::ImplTraitTypeOneBound &type) override
|
||||
{ /* TODO */
|
||||
}
|
||||
|
||||
private:
|
||||
TypeCheckType (HirId id)
|
||||
: TypeCheckBase (), translated (new TyTy::ErrorType (id))
|
||||
|
@ -82,12 +97,13 @@ private:
|
|||
|
||||
class TypeResolveGenericParam : public TypeCheckBase
|
||||
{
|
||||
using Rust::Resolver::TypeCheckBase::visit;
|
||||
|
||||
public:
|
||||
static TyTy::ParamType *Resolve (HIR::GenericParam *param);
|
||||
|
||||
void visit (HIR::TypeParam ¶m) override;
|
||||
protected:
|
||||
void visit (HIR::TypeParam ¶m);
|
||||
void visit (HIR::LifetimeParam ¶m);
|
||||
void visit (HIR::ConstGenericParam ¶m);
|
||||
|
||||
private:
|
||||
TypeResolveGenericParam () : TypeCheckBase (), resolved (nullptr) {}
|
||||
|
@ -97,13 +113,12 @@ private:
|
|||
|
||||
class ResolveWhereClauseItem : public TypeCheckBase
|
||||
{
|
||||
using Rust::Resolver::TypeCheckBase::visit;
|
||||
|
||||
public:
|
||||
static void Resolve (HIR::WhereClauseItem &item);
|
||||
|
||||
void visit (HIR::LifetimeWhereClauseItem &) override;
|
||||
void visit (HIR::TypeBoundWhereClauseItem &item) override;
|
||||
protected:
|
||||
void visit (HIR::LifetimeWhereClauseItem &item);
|
||||
void visit (HIR::TypeBoundWhereClauseItem &item);
|
||||
|
||||
private:
|
||||
ResolveWhereClauseItem () : TypeCheckBase () {}
|
||||
|
|
|
@ -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 (
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue