Skip to content

Add error checking for inference variables being used within function signitures #402

@philberty

Description

@philberty
fn square(num: i32) -> _ {
    num * num
}

fn main() {
    square(123);
}

gives:

[...]: error: type annotations needed
    6 |     square(123);
      |     ^

We should check for inference variables where they are not supported (ie behind a TvVar) rustc gives:

error[E0121]: the type placeholder `_` is not allowed within types on item signatures
 --> <source>:1:24
  |
1 | fn square(num: i32) -> _ {
  |                        ^
  |                        |
  |                        not allowed in type signatures
  |                        help: replace with the correct return type: `i32`

Guide

Check for inference variables on return types of Functions:

  • Add helper is_inference_var() which returns if the TypeKind == Infer
    class BaseType : public TypeBoundsMappings
  • Add is general inference variable helper which asserts it iis_inference_var casts over and checks the infer type kind
    class BaseType : public TypeBoundsMappings
  • TyTy::BaseType *ret_type = nullptr;
    if (!function.has_function_return_type ())
    ret_type = new TyTy::TupleType (function.get_mappings ().get_hirid ());
    else
    {
    auto resolved
    = TypeCheckType::Resolve (function.get_return_type ().get ());
    if (resolved == nullptr)
    {
    rust_error_at (function.get_locus (),
    "failed to resolve return type");
    return;
    }
    ret_type = resolved->clone ();
    ret_type->set_ref (
    function.get_return_type ()->get_mappings ().get_hirid ());
    }
    std::vector<std::pair<HIR::Pattern *, TyTy::BaseType *> > params;
    for (auto &param : function.get_function_params ())
    {
    // get the name as well required for later on
    auto param_tyty = TypeCheckType::Resolve (param.get_type ());
    params.push_back (
    std::pair<HIR::Pattern *, TyTy::BaseType *> (param.get_param_name (),
    param_tyty));
    context->insert_type (param.get_mappings (), param_tyty);
    }
    auto fnType
    = new TyTy::FnType (function.get_mappings ().get_hirid (),
    function.get_mappings ().get_defid (),
    function.get_function_name (), FNTYPE_DEFAULT_FLAGS,
    ABI::RUST, std::move (params), ret_type,
    std::move (substitutions));
    context->insert_type (function.get_mappings (), fnType);
  • TyTy::BaseType *ret_type = nullptr;
    if (!function.has_return_type ())
    ret_type = new TyTy::TupleType (function.get_mappings ().get_hirid ());
    else
    {
    auto resolved
    = TypeCheckType::Resolve (function.get_return_type ().get ());
    if (resolved == nullptr)
    {
    rust_error_at (function.get_locus (),
    "failed to resolve return type");
    return;
    }
    ret_type = resolved->clone ();
    ret_type->set_ref (
    function.get_return_type ()->get_mappings ().get_hirid ());
    }
    std::vector<std::pair<HIR::Pattern *, TyTy::BaseType *> > params;
    for (auto &param : function.get_function_params ())
    {
    // get the name as well required for later on
    auto param_tyty = TypeCheckType::Resolve (param.get_type ().get ());
    HIR::IdentifierPattern *param_pattern = new HIR::IdentifierPattern (
    param.get_param_name (), Location (), false, false,
    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);
    }
    uint8_t flags = FNTYPE_IS_EXTERN_FLAG;
    if (function.is_variadic ())
    flags |= FNTYPE_IS_VARADIC_FLAG;
    auto fnType = new TyTy::FnType (
    function.get_mappings ().get_hirid (),
    function.get_mappings ().get_defid (), function.get_item_name (), flags,
    ::Backend::get_abi_from_string (parent.get_abi (), parent.get_locus ()),
    std::move (params), ret_type, std::move (substitutions));
    context->insert_type (function.get_mappings (), fnType);
  • TyTy::BaseType *ret_type = nullptr;
    if (!function.has_function_return_type ())
    ret_type = new TyTy::TupleType (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 ());
    }

    You can check for an inference variable with:
TyTy::BaseType* return_type = ...;
bool is_inference_variable = return_type->get_kind() == TyTy::TypeKind::INFER;
TyTy::InferType* infer_var = static_cast<TyTy::InferType*>(infer_var);
bool is_general_inference_variable = infer_var->get_infer_kind() == TyTy::InferType::InferTypeKind::GENERAL;

Inference variables are of 3 kinds:

  • general which means it can be anything
  • integer the type is some kind of integer which will default to i32
  • float the type is some kind of decimal value default f64

We should error for any general inference variable, but maybe even if it is just any kind of inference variable.

Metadata

Metadata

Assignees

Labels

bugdiagnosticdiagnostic static analysis

Projects

Status

Done

Relationships

None yet

Development

No branches or pull requests

Issue actions