Skip to content

Commit

Permalink
Add Type resolution to Array expressions
Browse files Browse the repository at this point in the history
This adds type inferencing and validation for arrays such as:

  let x: [i32, 5] = [1,2,3,4,5]
  ley y = [1,2,3];

It checks that each element is of a valid type and they line up correctly.
There needs to be some refactoring of the type resolution to handle the
array index expressions so this is a good save point for now.

Addresses: #27 #55
  • Loading branch information
philberty committed Dec 1, 2020
1 parent 37560f9 commit 886b230
Show file tree
Hide file tree
Showing 3 changed files with 180 additions and 14 deletions.
164 changes: 156 additions & 8 deletions gcc/rust/analysis/rust-type-resolution.cc
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,13 @@ TypeResolution::typesAreCompatible (AST::Type *lhs, AST::Type *rhs,
}

AST::Type *val = NULL;
return scope.LookupType (lhsTypeStr, &val);
if (!scope.LookupType (lhsTypeStr, &val))
{
rust_error_at (locus, "Unknown type: %s", lhsTypeStr.c_str ());
return false;
}

return true;
}

bool
Expand Down Expand Up @@ -395,19 +401,112 @@ TypeResolution::visit (AST::CompoundAssignmentExpr &expr)
void
TypeResolution::visit (AST::GroupedExpr &expr)
{}
// void TypeResolution::visit(ArrayElems& elems) {}

void
TypeResolution::visit (AST::ArrayElemsValues &elems)
{}
{
// we need to generate the AST::ArrayType for this array init_expression
// we can get the size via get_num_values() but we need to ensure each element
// are type compatible

bool failed = false;
AST::Type *last_inferred_type = nullptr;
elems.iterate ([&] (AST::Expr *expr) mutable -> bool {
size_t before;
before = typeBuffer.size ();
expr->accept_vis (*this);
if (typeBuffer.size () <= before)
{
rust_error_at (expr->get_locus_slow (),
"unable to determine element type");
return false;
}

AST::Type *inferedType = typeBuffer.back ();
typeBuffer.pop_back ();

if (last_inferred_type == nullptr)
last_inferred_type = inferedType;
else
{
if (!typesAreCompatible (last_inferred_type, inferedType,
expr->get_locus_slow ()))
{
failed = true;
return false;
}
}

return true;
});

// nothing to do when its failed
if (failed)
return;

auto capacity
= new AST::LiteralExpr (std::to_string (elems.get_num_values ()),
AST::Literal::INT,
Linemap::predeclared_location ());
auto arrayType = new AST::ArrayType (last_inferred_type->clone_type (),
std::unique_ptr<AST::Expr> (capacity),
Linemap::predeclared_location ());
typeBuffer.push_back (arrayType);
}

void
TypeResolution::visit (AST::ArrayElemsCopied &elems)
{}
{
printf ("ArrayElemsCopied: %s\n", elems.as_string ().c_str ());
}

void
TypeResolution::visit (AST::ArrayExpr &expr)
{}
{
auto elements = expr.get_internal_elements ();
elements->accept_vis (*this);
}

void
TypeResolution::visit (AST::ArrayIndexExpr &expr)
{}
{
printf ("ArrayIndexExpr: %s\n", expr.as_string ().c_str ());

auto before = typeBuffer.size ();
expr.get_array_expr ()->accept_vis (*this);
if (typeBuffer.size () <= before)
{
rust_error_at (expr.get_locus_slow (),
"unable to determine type for array index expression");
return;
}
AST::Type *array_expr_type = typeBuffer.back ();
typeBuffer.pop_back ();

before = typeBuffer.size ();
expr.get_index_expr ()->accept_vis (*this);
if (typeBuffer.size () <= before)
{
rust_error_at (expr.get_index_expr ()->get_locus_slow (),
"unable to determine type for index expression");
return;
}

AST::Type *array_index_type = typeBuffer.back ();
typeBuffer.pop_back ();

printf ("Array expr type %s array index expr type: [%s]\n",
array_expr_type->as_string ().c_str (),
array_index_type->as_string ().c_str ());

// the the element type from the array_expr_type and it _must_ be an array
// TODO

// check the index_type should be an i32 which should really be
// more permissive
// TODO
}

void
TypeResolution::visit (AST::TupleExpr &expr)
{}
Expand Down Expand Up @@ -1015,7 +1114,7 @@ TypeResolution::visit (AST::LetStmt &stmt)
return;
}

AST::Type *inferedType = NULL;
AST::Type *inferedType = nullptr;
if (stmt.has_init_expr ())
{
auto before = typeBuffer.size ();
Expand Down Expand Up @@ -1048,6 +1147,51 @@ TypeResolution::visit (AST::LetStmt &stmt)
return;
}
}
else if (stmt.has_type ())
{
auto before = typeComparisonBuffer.size ();
stmt.type->accept_vis (*this);
if (typeComparisonBuffer.size () <= before)
{
rust_error_at (stmt.locus, "failed to understand type for lhs");
return;
}
auto typeString = typeComparisonBuffer.back ();
typeComparisonBuffer.pop_back ();

AST::Type *val = NULL;
if (!scope.LookupType (typeString, &val))
{
rust_error_at (stmt.locus, "LetStmt has unknown type: %s",
stmt.type->as_string ().c_str ());
return;
}
}
else if (inferedType != nullptr)
{
auto before = typeComparisonBuffer.size ();
inferedType->accept_vis (*this);
if (typeComparisonBuffer.size () <= before)
{
rust_error_at (stmt.locus, "failed to understand type for lhs");
return;
}
auto typeString = typeComparisonBuffer.back ();
typeComparisonBuffer.pop_back ();

AST::Type *val = NULL;
if (!scope.LookupType (typeString, &val))
{
rust_error_at (stmt.locus, "Inferred unknown type: %s",
inferedType->as_string ().c_str ());
return;
}
}
else
{
rust_fatal_error (stmt.locus, "Failed to determine any type for LetStmt");
return;
}

// ensure the decl has the type set for compilation later on
if (!stmt.has_type ())
Expand Down Expand Up @@ -1115,9 +1259,13 @@ TypeResolution::visit (AST::RawPointerType &type)
void
TypeResolution::visit (AST::ReferenceType &type)
{}

void
TypeResolution::visit (AST::ArrayType &type)
{}
{
typeComparisonBuffer.push_back (type.get_element_type ()->as_string ());
}

void
TypeResolution::visit (AST::SliceType &type)
{}
Expand Down
16 changes: 16 additions & 0 deletions gcc/rust/ast/rust-expr.h
Original file line number Diff line number Diff line change
Expand Up @@ -928,6 +928,17 @@ class ArrayElemsValues : public ArrayElems

void accept_vis (ASTVisitor &vis) override;

size_t get_num_values () const { return values.size (); }

void iterate (std::function<bool (Expr *)> cb)
{
for (auto it = values.begin (); it != values.end (); it++)
{
if (!cb ((*it).get ()))
return;
}
}

protected:
ArrayElemsValues *clone_array_elems_impl () const override
{
Expand Down Expand Up @@ -1037,6 +1048,8 @@ class ArrayExpr : public ExprWithoutBlock

void accept_vis (ASTVisitor &vis) override;

ArrayElems *get_internal_elements () { return internal_elements.get (); };

protected:
/* Use covariance to implement clone function as returning this object rather
* than base */
Expand Down Expand Up @@ -1100,6 +1113,9 @@ class ArrayIndexExpr : public ExprWithoutBlock

void accept_vis (ASTVisitor &vis) override;

Expr *get_array_expr () { return array_expr.get (); }
Expr *get_index_expr () { return index_expr.get (); }

protected:
/* Use covariance to implement clone function as returning this object rather
* than base */
Expand Down
14 changes: 8 additions & 6 deletions gcc/rust/ast/rust-type.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ class ImplTraitType : public Type
{
// TypeParamBounds type_param_bounds;
// inlined form
std::vector<std::unique_ptr<TypeParamBound>> type_param_bounds;
std::vector<std::unique_ptr<TypeParamBound> > type_param_bounds;

Location locus;

Expand All @@ -74,7 +74,7 @@ class ImplTraitType : public Type

public:
ImplTraitType (
std::vector<std::unique_ptr<TypeParamBound>> type_param_bounds,
std::vector<std::unique_ptr<TypeParamBound> > type_param_bounds,
Location locus)
: type_param_bounds (std::move (type_param_bounds)), locus (locus)
{}
Expand Down Expand Up @@ -115,7 +115,7 @@ class TraitObjectType : public Type
{
bool has_dyn;
// TypeParamBounds type_param_bounds;
std::vector<std::unique_ptr<TypeParamBound>>
std::vector<std::unique_ptr<TypeParamBound> >
type_param_bounds; // inlined form

Location locus;
Expand All @@ -130,7 +130,7 @@ class TraitObjectType : public Type

public:
TraitObjectType (
std::vector<std::unique_ptr<TypeParamBound>> type_param_bounds,
std::vector<std::unique_ptr<TypeParamBound> > type_param_bounds,
Location locus, bool is_dyn_dispatch = false)
: has_dyn (is_dyn_dispatch),
type_param_bounds (std::move (type_param_bounds)), locus (locus)
Expand Down Expand Up @@ -318,14 +318,14 @@ class TypePath; // definition moved to "rust-path.h"
* specific order */
class TupleType : public TypeNoBounds
{
std::vector<std::unique_ptr<Type>> elems;
std::vector<std::unique_ptr<Type> > elems;
Location locus;

public:
// Returns whether the tuple type is the unit type, i.e. has no elements.
bool is_unit_type () const { return elems.empty (); }

TupleType (std::vector<std::unique_ptr<Type>> elems, Location locus)
TupleType (std::vector<std::unique_ptr<Type> > elems, Location locus)
: elems (std::move (elems)), locus (locus)
{}

Expand Down Expand Up @@ -574,6 +574,8 @@ class ArrayType : public TypeNoBounds

void accept_vis (ASTVisitor &vis) override;

Type *get_element_type () { return elem_type.get (); }

protected:
/* Use covariance to implement clone function as returning this object rather
* than base */
Expand Down

0 comments on commit 886b230

Please sign in to comment.