Refactor all coercion type calls into a single coercion_site function

In order to fully support coercion sites we need a single place in order to
implement the logic. This refactors all the coercion calls to have a single
TypeCheckBase::coercion_site(lhs, rhs, location). Eventually we will do
something similar for unifications and casts so we can improve our
diagnostics.
This commit is contained in:
Philip Herron 2022-07-29 16:21:33 +01:00
parent ffb419d6a4
commit 2dc902baa1
8 changed files with 288 additions and 245 deletions

View File

@ -106,6 +106,7 @@ GRS_OBJS = \
rust/rust-pub-restricted-visitor.o \
rust/rust-privacy-reporter.o \
rust/rust-tyty.o \
rust/rust-tyty-call.o \
rust/rust-tyctx.o \
rust/rust-tyty-bounds.o \
rust/rust-hir-type-check-util.o \

View File

@ -327,5 +327,12 @@ TypeCheckBase::parse_repr_options (const AST::AttrVec &attrs, Location locus)
return repr;
}
TyTy::BaseType *
TypeCheckBase::coercion_site (TyTy::BaseType *lhs, TyTy::BaseType *rhs,
Location)
{
return lhs->coerce (rhs);
}
} // namespace Resolver
} // namespace Rust

View File

@ -39,6 +39,9 @@ public:
virtual ~TypeCheckBase () {}
static TyTy::BaseType *coercion_site (TyTy::BaseType *lhs,
TyTy::BaseType *rhs, Location locus);
protected:
TypeCheckBase ()
: mappings (Analysis::Mappings::get ()), resolver (Resolver::get ()),

View File

@ -380,7 +380,7 @@ public:
auto lhs = TypeCheckExpr::Resolve (expr.get_lhs ());
auto rhs = TypeCheckExpr::Resolve (expr.get_rhs ());
lhs->coerce (rhs);
coercion_site (lhs, rhs, expr.get_locus ());
}
void visit (HIR::CompoundAssignmentExpr &expr) override

View File

@ -99,7 +99,7 @@ public:
if (specified_ty != nullptr && init_expr_ty != nullptr)
{
// FIXME use this result and look at the regressions
specified_ty->coerce (init_expr_ty);
coercion_site (specified_ty, init_expr_ty, stmt.get_locus ());
context->insert_type (stmt_pattern.get_pattern_mappings (),
specified_ty);
}

View File

@ -42,8 +42,8 @@ TypeCheckStructExpr::visit (HIR::StructExprStructFields &struct_expr)
{
TyTy::BaseType *base_resolved
= TypeCheckExpr::Resolve (struct_expr.struct_base->base_struct.get ());
struct_def
= (TyTy::ADTType *) struct_path_resolved->coerce (base_resolved);
struct_def = static_cast<TyTy::ADTType *> (
struct_path_resolved->coerce (base_resolved));
if (struct_def == nullptr)
{
rust_fatal_error (struct_expr.struct_base->base_struct->get_locus (),
@ -221,7 +221,8 @@ TypeCheckStructExpr::visit (HIR::StructExprFieldIdentifierValue &field)
}
TyTy::BaseType *value = TypeCheckExpr::Resolve (field.get_value ());
resolved_field_value_expr = field_type->get_field_type ()->coerce (value);
resolved_field_value_expr
= coercion_site (field_type->get_field_type (), value, field.get_locus ());
if (resolved_field_value_expr != nullptr)
{
fields_assigned.insert (field.field_name);
@ -250,7 +251,8 @@ TypeCheckStructExpr::visit (HIR::StructExprFieldIndexValue &field)
}
TyTy::BaseType *value = TypeCheckExpr::Resolve (field.get_value ());
resolved_field_value_expr = field_type->get_field_type ()->coerce (value);
resolved_field_value_expr
= coercion_site (field_type->get_field_type (), value, field.get_locus ());
if (resolved_field_value_expr != nullptr)
{
fields_assigned.insert (field_name);
@ -284,7 +286,8 @@ TypeCheckStructExpr::visit (HIR::StructExprFieldIdentifier &field)
field.get_locus ());
TyTy::BaseType *value = TypeCheckExpr::Resolve (&expr);
resolved_field_value_expr = field_type->get_field_type ()->coerce (value);
resolved_field_value_expr
= coercion_site (field_type->get_field_type (), value, field.get_locus ());
if (resolved_field_value_expr != nullptr)
{

View File

@ -0,0 +1,267 @@
// 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-tyty-call.h"
#include "rust-hir-type-check-expr.h"
namespace Rust {
namespace TyTy {
void
TypeCheckCallExpr::visit (ADTType &type)
{
rust_assert (!variant.is_error ());
if (variant.get_variant_type () != TyTy::VariantDef::VariantType::TUPLE)
{
rust_error_at (
call.get_locus (),
"expected function, tuple struct or tuple variant, found struct %<%s%>",
type.get_name ().c_str ());
return;
}
if (call.num_params () != variant.num_fields ())
{
rust_error_at (call.get_locus (),
"unexpected number of arguments %lu expected %lu",
(unsigned long) call.num_params (),
(unsigned long) variant.num_fields ());
return;
}
size_t i = 0;
for (auto &argument : call.get_arguments ())
{
StructFieldType *field = variant.get_field_at_index (i);
BaseType *field_tyty = field->get_field_type ();
BaseType *arg = Resolver::TypeCheckExpr::Resolve (argument.get ());
if (arg->get_kind () == TyTy::TypeKind::ERROR)
{
rust_error_at (argument->get_locus (),
"failed to resolve argument type");
return;
}
auto res = field_tyty->coerce (arg);
if (res->get_kind () == TyTy::TypeKind::ERROR)
{
return;
}
delete res;
i++;
}
if (i != call.num_params ())
{
rust_error_at (call.get_locus (),
"unexpected number of arguments %lu expected %lu",
(unsigned long) i, (unsigned long) call.num_params ());
return;
}
resolved = type.clone ();
}
void
TypeCheckCallExpr::visit (FnType &type)
{
type.monomorphize ();
if (call.num_params () != type.num_params ())
{
if (type.is_varadic ())
{
if (call.num_params () < type.num_params ())
{
rust_error_at (call.get_locus (),
"unexpected number of arguments %lu expected %lu",
(unsigned long) call.num_params (),
(unsigned long) type.num_params ());
return;
}
}
else
{
rust_error_at (call.get_locus (),
"unexpected number of arguments %lu expected %lu",
(unsigned long) call.num_params (),
(unsigned long) type.num_params ());
return;
}
}
size_t i = 0;
for (auto &argument : call.get_arguments ())
{
auto argument_expr_tyty
= Resolver::TypeCheckExpr::Resolve (argument.get ());
if (argument_expr_tyty->get_kind () == TyTy::TypeKind::ERROR)
{
rust_error_at (
argument->get_locus (),
"failed to resolve type for argument expr in CallExpr");
return;
}
// it might be a varadic function
if (i < type.num_params ())
{
auto fnparam = type.param_at (i);
auto resolved_argument_type
= fnparam.second->coerce (argument_expr_tyty);
if (resolved_argument_type->get_kind () == TyTy::TypeKind::ERROR)
{
rust_error_at (argument->get_locus (),
"Type Resolution failure on parameter");
return;
}
}
context->insert_type (argument->get_mappings (), argument_expr_tyty);
i++;
}
if (i < call.num_params ())
{
rust_error_at (call.get_locus (),
"unexpected number of arguments %lu expected %lu",
(unsigned long) i, (unsigned long) call.num_params ());
return;
}
type.monomorphize ();
resolved = type.get_return_type ()->clone ();
}
void
TypeCheckCallExpr::visit (FnPtr &type)
{
if (call.num_params () != type.num_params ())
{
rust_error_at (call.get_locus (),
"unexpected number of arguments %lu expected %lu",
(unsigned long) call.num_params (),
(unsigned long) type.num_params ());
return;
}
size_t i = 0;
for (auto &argument : call.get_arguments ())
{
auto fnparam = type.param_at (i);
auto argument_expr_tyty
= Resolver::TypeCheckExpr::Resolve (argument.get ());
if (argument_expr_tyty->get_kind () == TyTy::TypeKind::ERROR)
{
rust_error_at (
argument->get_locus (),
"failed to resolve type for argument expr in CallExpr");
return;
}
auto resolved_argument_type
= Resolver::TypeCheckBase::coercion_site (fnparam, argument_expr_tyty,
argument->get_locus ());
if (resolved_argument_type->get_kind () == TyTy::TypeKind::ERROR)
{
rust_error_at (argument->get_locus (),
"Type Resolution failure on parameter");
return;
}
context->insert_type (argument->get_mappings (), argument_expr_tyty);
i++;
}
if (i != call.num_params ())
{
rust_error_at (call.get_locus (),
"unexpected number of arguments %lu expected %lu",
(unsigned long) i, (unsigned long) call.num_params ());
return;
}
resolved = type.get_return_type ()->monomorphized_clone ();
}
// method call checker
void
TypeCheckMethodCallExpr::visit (FnType &type)
{
type.get_self_type ()->unify (adjusted_self);
// +1 for the receiver self
size_t num_args_to_call = call.num_params () + 1;
if (num_args_to_call != type.num_params ())
{
rust_error_at (call.get_locus (),
"unexpected number of arguments %lu expected %lu",
(unsigned long) call.num_params (),
(unsigned long) type.num_params ());
return;
}
size_t i = 1;
for (auto &argument : call.get_arguments ())
{
auto fnparam = type.param_at (i);
auto argument_expr_tyty
= Resolver::TypeCheckExpr::Resolve (argument.get ());
if (argument_expr_tyty->get_kind () == TyTy::TypeKind::ERROR)
{
rust_error_at (
argument->get_locus (),
"failed to resolve type for argument expr in CallExpr");
return;
}
auto resolved_argument_type
= Resolver::TypeCheckBase::coercion_site (fnparam.second,
argument_expr_tyty,
argument->get_locus ());
if (resolved_argument_type->get_kind () == TyTy::TypeKind::ERROR)
{
rust_error_at (argument->get_locus (),
"Type Resolution failure on parameter");
return;
}
context->insert_type (argument->get_mappings (), argument_expr_tyty);
i++;
}
if (i != num_args_to_call)
{
rust_error_at (call.get_locus (),
"unexpected number of arguments %lu expected %lu",
(unsigned long) i, (unsigned long) call.num_params ());
return;
}
type.monomorphize ();
resolved = type.get_return_type ()->monomorphized_clone ();
}
} // namespace TyTy
} // namespace Rust

View File

@ -3205,243 +3205,5 @@ DynamicObjectType::get_object_items () const
return items;
}
// rust-tyty-call.h
void
TypeCheckCallExpr::visit (ADTType &type)
{
rust_assert (!variant.is_error ());
if (variant.get_variant_type () != TyTy::VariantDef::VariantType::TUPLE)
{
rust_error_at (
call.get_locus (),
"expected function, tuple struct or tuple variant, found struct %<%s%>",
type.get_name ().c_str ());
return;
}
if (call.num_params () != variant.num_fields ())
{
rust_error_at (call.get_locus (),
"unexpected number of arguments %lu expected %lu",
(unsigned long) call.num_params (),
(unsigned long) variant.num_fields ());
return;
}
size_t i = 0;
for (auto &argument : call.get_arguments ())
{
StructFieldType *field = variant.get_field_at_index (i);
BaseType *field_tyty = field->get_field_type ();
BaseType *arg = Resolver::TypeCheckExpr::Resolve (argument.get ());
if (arg->get_kind () == TyTy::TypeKind::ERROR)
{
rust_error_at (argument->get_locus (),
"failed to resolve argument type");
return;
}
auto res = field_tyty->coerce (arg);
if (res->get_kind () == TyTy::TypeKind::ERROR)
{
return;
}
delete res;
i++;
}
if (i != call.num_params ())
{
rust_error_at (call.get_locus (),
"unexpected number of arguments %lu expected %lu",
(unsigned long) i, (unsigned long) call.num_params ());
return;
}
resolved = type.clone ();
}
void
TypeCheckCallExpr::visit (FnType &type)
{
type.monomorphize ();
if (call.num_params () != type.num_params ())
{
if (type.is_varadic ())
{
if (call.num_params () < type.num_params ())
{
rust_error_at (call.get_locus (),
"unexpected number of arguments %lu expected %lu",
(unsigned long) call.num_params (),
(unsigned long) type.num_params ());
return;
}
}
else
{
rust_error_at (call.get_locus (),
"unexpected number of arguments %lu expected %lu",
(unsigned long) call.num_params (),
(unsigned long) type.num_params ());
return;
}
}
size_t i = 0;
for (auto &argument : call.get_arguments ())
{
auto argument_expr_tyty
= Resolver::TypeCheckExpr::Resolve (argument.get ());
if (argument_expr_tyty->get_kind () == TyTy::TypeKind::ERROR)
{
rust_error_at (
argument->get_locus (),
"failed to resolve type for argument expr in CallExpr");
return;
}
// it might be a varadic function
if (i < type.num_params ())
{
auto fnparam = type.param_at (i);
auto resolved_argument_type
= fnparam.second->coerce (argument_expr_tyty);
if (resolved_argument_type->get_kind () == TyTy::TypeKind::ERROR)
{
rust_error_at (argument->get_locus (),
"Type Resolution failure on parameter");
return;
}
}
context->insert_type (argument->get_mappings (), argument_expr_tyty);
i++;
}
if (i < call.num_params ())
{
rust_error_at (call.get_locus (),
"unexpected number of arguments %lu expected %lu",
(unsigned long) i, (unsigned long) call.num_params ());
return;
}
type.monomorphize ();
resolved = type.get_return_type ()->clone ();
}
void
TypeCheckCallExpr::visit (FnPtr &type)
{
if (call.num_params () != type.num_params ())
{
rust_error_at (call.get_locus (),
"unexpected number of arguments %lu expected %lu",
(unsigned long) call.num_params (),
(unsigned long) type.num_params ());
return;
}
size_t i = 0;
for (auto &argument : call.get_arguments ())
{
auto fnparam = type.param_at (i);
auto argument_expr_tyty
= Resolver::TypeCheckExpr::Resolve (argument.get ());
if (argument_expr_tyty->get_kind () == TyTy::TypeKind::ERROR)
{
rust_error_at (
argument->get_locus (),
"failed to resolve type for argument expr in CallExpr");
return;
}
auto resolved_argument_type = fnparam->coerce (argument_expr_tyty);
if (resolved_argument_type->get_kind () == TyTy::TypeKind::ERROR)
{
rust_error_at (argument->get_locus (),
"Type Resolution failure on parameter");
return;
}
context->insert_type (argument->get_mappings (), argument_expr_tyty);
i++;
}
if (i != call.num_params ())
{
rust_error_at (call.get_locus (),
"unexpected number of arguments %lu expected %lu",
(unsigned long) i, (unsigned long) call.num_params ());
return;
}
resolved = type.get_return_type ()->monomorphized_clone ();
}
// method call checker
void
TypeCheckMethodCallExpr::visit (FnType &type)
{
type.get_self_type ()->unify (adjusted_self);
// +1 for the receiver self
size_t num_args_to_call = call.num_params () + 1;
if (num_args_to_call != type.num_params ())
{
rust_error_at (call.get_locus (),
"unexpected number of arguments %lu expected %lu",
(unsigned long) call.num_params (),
(unsigned long) type.num_params ());
return;
}
size_t i = 1;
for (auto &argument : call.get_arguments ())
{
auto fnparam = type.param_at (i);
auto argument_expr_tyty
= Resolver::TypeCheckExpr::Resolve (argument.get ());
if (argument_expr_tyty->get_kind () == TyTy::TypeKind::ERROR)
{
rust_error_at (
argument->get_locus (),
"failed to resolve type for argument expr in CallExpr");
return;
}
auto resolved_argument_type = fnparam.second->coerce (argument_expr_tyty);
if (resolved_argument_type->get_kind () == TyTy::TypeKind::ERROR)
{
rust_error_at (argument->get_locus (),
"Type Resolution failure on parameter");
return;
}
context->insert_type (argument->get_mappings (), argument_expr_tyty);
i++;
}
if (i != num_args_to_call)
{
rust_error_at (call.get_locus (),
"unexpected number of arguments %lu expected %lu",
(unsigned long) i, (unsigned long) call.num_params ());
return;
}
type.monomorphize ();
resolved = type.get_return_type ()->monomorphized_clone ();
}
} // namespace TyTy
} // namespace Rust