blob: cbbff8c44204670f075dd305ce015ce83e2cc17e [file] [log] [blame]
// Copyright (C) 2020-2023 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-unify.h"
namespace Rust {
namespace Resolver {
UnifyRules::UnifyRules (TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs,
Location locus, bool commit_flag, bool emit_error)
: lhs (lhs), rhs (rhs), locus (locus), commit_flag (commit_flag),
emit_error (emit_error), mappings (*Analysis::Mappings::get ()),
context (*TypeCheckContext::get ())
{}
TyTy::BaseType *
UnifyRules::Resolve (TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs,
Location locus, bool commit_flag, bool emit_error)
{
UnifyRules r (lhs, rhs, locus, commit_flag, emit_error);
TyTy::BaseType *result = r.go ();
if (r.commit_flag)
r.commit (result);
bool failed = result->get_kind () == TyTy::TypeKind::ERROR;
if (failed && r.emit_error)
r.emit_type_mismatch ();
return result;
}
TyTy::BaseType *
UnifyRules::get_base ()
{
return lhs.get_ty ()->destructure ();
}
TyTy::BaseType *
UnifyRules::get_other ()
{
return rhs.get_ty ()->destructure ();
}
void
UnifyRules::commit (TyTy::BaseType *resolved)
{
resolved->append_reference (get_base ()->get_ref ());
resolved->append_reference (get_other ()->get_ref ());
for (auto ref : get_base ()->get_combined_refs ())
resolved->append_reference (ref);
for (auto ref : get_other ()->get_combined_refs ())
resolved->append_reference (ref);
get_other ()->append_reference (resolved->get_ref ());
get_other ()->append_reference (get_base ()->get_ref ());
get_base ()->append_reference (resolved->get_ref ());
get_base ()->append_reference (get_other ()->get_ref ());
bool result_resolved = resolved->get_kind () != TyTy::TypeKind::INFER;
bool result_is_infer_var = resolved->get_kind () == TyTy::TypeKind::INFER;
bool results_is_non_general_infer_var
= (result_is_infer_var
&& (static_cast<TyTy::InferType *> (resolved))->get_infer_kind ()
!= TyTy::InferType::GENERAL);
if (result_resolved || results_is_non_general_infer_var)
{
for (auto &ref : resolved->get_combined_refs ())
{
TyTy::BaseType *ref_tyty = nullptr;
bool ok = context.lookup_type (ref, &ref_tyty);
if (!ok)
continue;
// if any of the types are inference variables lets fix them
if (ref_tyty->get_kind () == TyTy::TypeKind::INFER)
{
auto node = Analysis::NodeMapping (mappings.get_current_crate (),
UNKNOWN_NODEID, ref,
UNKNOWN_LOCAL_DEFID);
context.insert_type (node, resolved->clone ());
}
}
}
}
void
UnifyRules::emit_type_mismatch () const
{
TyTy::BaseType *expected = lhs.get_ty ();
TyTy::BaseType *expr = rhs.get_ty ();
RichLocation r (locus);
r.add_range (lhs.get_locus ());
r.add_range (rhs.get_locus ());
rust_error_at (r, "expected %<%s%> got %<%s%>",
expected->get_name ().c_str (), expr->get_name ().c_str ());
}
TyTy::BaseType *
UnifyRules::go ()
{
TyTy::BaseType *ltype = lhs.get_ty ();
TyTy::BaseType *rtype = rhs.get_ty ();
ltype = lhs.get_ty ()->destructure ();
rtype = rhs.get_ty ()->destructure ();
rust_debug ("unify::go ltype={%s} rtype={%s}", ltype->debug_str ().c_str (),
rtype->debug_str ().c_str ());
// check bounds
if (ltype->num_specified_bounds () > 0)
{
if (!ltype->bounds_compatible (*rtype, locus, true))
{
// already emitted an error
emit_error = false;
return new TyTy::ErrorType (0);
}
}
switch (ltype->get_kind ())
{
case TyTy::INFER:
return expect_inference_variable (static_cast<TyTy::InferType *> (ltype),
rtype);
case TyTy::ADT:
return expect_adt (static_cast<TyTy::ADTType *> (ltype), rtype);
case TyTy::STR:
return expect_str (static_cast<TyTy::StrType *> (ltype), rtype);
case TyTy::REF:
return expect_reference (static_cast<TyTy::ReferenceType *> (ltype),
rtype);
case TyTy::POINTER:
return expect_pointer (static_cast<TyTy::PointerType *> (ltype), rtype);
case TyTy::PARAM:
return expect_param (static_cast<TyTy::ParamType *> (ltype), rtype);
case TyTy::ARRAY:
return expect_array (static_cast<TyTy::ArrayType *> (ltype), rtype);
case TyTy::SLICE:
return expect_slice (static_cast<TyTy::SliceType *> (ltype), rtype);
case TyTy::FNDEF:
return expect_fndef (static_cast<TyTy::FnType *> (ltype), rtype);
case TyTy::FNPTR:
return expect_fnptr (static_cast<TyTy::FnPtr *> (ltype), rtype);
case TyTy::TUPLE:
return expect_tuple (static_cast<TyTy::TupleType *> (ltype), rtype);
case TyTy::BOOL:
return expect_bool (static_cast<TyTy::BoolType *> (ltype), rtype);
case TyTy::CHAR:
return expect_char (static_cast<TyTy::CharType *> (ltype), rtype);
case TyTy::INT:
return expect_int (static_cast<TyTy::IntType *> (ltype), rtype);
case TyTy::UINT:
return expect_uint (static_cast<TyTy::UintType *> (ltype), rtype);
case TyTy::FLOAT:
return expect_float (static_cast<TyTy::FloatType *> (ltype), rtype);
case TyTy::USIZE:
return expect_usize (static_cast<TyTy::USizeType *> (ltype), rtype);
case TyTy::ISIZE:
return expect_isize (static_cast<TyTy::ISizeType *> (ltype), rtype);
case TyTy::NEVER:
return expect_never (static_cast<TyTy::NeverType *> (ltype), rtype);
case TyTy::PLACEHOLDER:
return expect_placeholder (static_cast<TyTy::PlaceholderType *> (ltype),
rtype);
case TyTy::PROJECTION:
return expect_projection (static_cast<TyTy::ProjectionType *> (ltype),
rtype);
case TyTy::DYNAMIC:
return expect_dyn (static_cast<TyTy::DynamicObjectType *> (ltype), rtype);
case TyTy::CLOSURE:
return expect_closure (static_cast<TyTy::ClosureType *> (ltype), rtype);
case TyTy::ERROR:
return new TyTy::ErrorType (0);
}
return new TyTy::ErrorType (0);
}
TyTy::BaseType *
UnifyRules::expect_inference_variable (TyTy::InferType *ltype,
TyTy::BaseType *rtype)
{
switch (rtype->get_kind ())
{
case TyTy::INFER: {
TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype);
switch (ltype->get_infer_kind ())
{
case TyTy::InferType::InferTypeKind::GENERAL:
return rtype->clone ();
case TyTy::InferType::InferTypeKind::INTEGRAL: {
bool is_valid = r->get_infer_kind ()
== TyTy::InferType::InferTypeKind::INTEGRAL
|| r->get_infer_kind ()
== TyTy::InferType::InferTypeKind::GENERAL;
if (is_valid)
return rtype->clone ();
}
break;
case TyTy::InferType::InferTypeKind::FLOAT: {
bool is_valid
= r->get_infer_kind () == TyTy::InferType::InferTypeKind::FLOAT
|| r->get_infer_kind ()
== TyTy::InferType::InferTypeKind::GENERAL;
if (is_valid)
return rtype->clone ();
}
break;
}
}
break;
case TyTy::INT:
case TyTy::UINT:
case TyTy::USIZE:
case TyTy::ISIZE: {
bool is_valid = (ltype->get_infer_kind ()
== TyTy::InferType::InferTypeKind::GENERAL)
|| (ltype->get_infer_kind ()
== TyTy::InferType::InferTypeKind::INTEGRAL);
if (is_valid)
return rtype->clone ();
}
break;
case TyTy::FLOAT: {
bool is_valid = (ltype->get_infer_kind ()
== TyTy::InferType::InferTypeKind::GENERAL)
|| (ltype->get_infer_kind ()
== TyTy::InferType::InferTypeKind::FLOAT);
if (is_valid)
return rtype->clone ();
}
break;
case TyTy::ADT:
case TyTy::STR:
case TyTy::REF:
case TyTy::POINTER:
case TyTy::PARAM:
case TyTy::ARRAY:
case TyTy::SLICE:
case TyTy::FNDEF:
case TyTy::FNPTR:
case TyTy::TUPLE:
case TyTy::BOOL:
case TyTy::CHAR:
case TyTy::NEVER:
case TyTy::PLACEHOLDER:
case TyTy::PROJECTION:
case TyTy::DYNAMIC:
case TyTy::CLOSURE: {
bool is_valid = (ltype->get_infer_kind ()
== TyTy::InferType::InferTypeKind::GENERAL);
if (is_valid)
return rtype->clone ();
}
break;
case TyTy::ERROR:
return new TyTy::ErrorType (0);
}
return new TyTy::ErrorType (0);
}
TyTy::BaseType *
UnifyRules::expect_adt (TyTy::ADTType *ltype, TyTy::BaseType *rtype)
{
switch (rtype->get_kind ())
{
case TyTy::INFER: {
TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype);
bool is_valid
= r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL;
if (is_valid)
return ltype->clone ();
}
break;
case TyTy::ADT: {
TyTy::ADTType &type = *static_cast<TyTy::ADTType *> (rtype);
if (ltype->get_adt_kind () != type.get_adt_kind ())
{
return new TyTy::ErrorType (0);
}
if (ltype->get_identifier ().compare (type.get_identifier ()) != 0)
{
return new TyTy::ErrorType (0);
}
if (ltype->number_of_variants () != type.number_of_variants ())
{
return new TyTy::ErrorType (0);
}
for (size_t i = 0; i < type.number_of_variants (); ++i)
{
TyTy::VariantDef *a = ltype->get_variants ().at (i);
TyTy::VariantDef *b = type.get_variants ().at (i);
if (a->num_fields () != b->num_fields ())
{
return new TyTy::ErrorType (0);
}
for (size_t j = 0; j < a->num_fields (); j++)
{
TyTy::StructFieldType *base_field = a->get_field_at_index (j);
TyTy::StructFieldType *other_field = b->get_field_at_index (j);
TyTy::BaseType *this_field_ty = base_field->get_field_type ();
TyTy::BaseType *other_field_ty = other_field->get_field_type ();
TyTy::BaseType *unified_ty
= UnifyRules::Resolve (TyTy::TyWithLocation (this_field_ty),
TyTy::TyWithLocation (other_field_ty),
locus, commit_flag,
false /* emit_error */);
if (unified_ty->get_kind () == TyTy::TypeKind::ERROR)
{
return new TyTy::ErrorType (0);
}
}
}
// generic args for the unit-struct case
if (type.is_unit () && ltype->is_unit ())
{
rust_assert (type.get_num_substitutions ()
== ltype->get_num_substitutions ());
for (size_t i = 0; i < type.get_num_substitutions (); i++)
{
auto &a = ltype->get_substs ().at (i);
auto &b = type.get_substs ().at (i);
auto pa = a.get_param_ty ();
auto pb = b.get_param_ty ();
auto res
= UnifyRules::Resolve (TyTy::TyWithLocation (pa),
TyTy::TyWithLocation (pb), locus,
commit_flag, false /* emit_error */);
if (res->get_kind () == TyTy::TypeKind::ERROR)
{
return new TyTy::ErrorType (0);
}
}
}
return type.clone ();
}
break;
case TyTy::STR:
case TyTy::REF:
case TyTy::POINTER:
case TyTy::PARAM:
case TyTy::ARRAY:
case TyTy::SLICE:
case TyTy::FNDEF:
case TyTy::FNPTR:
case TyTy::TUPLE:
case TyTy::BOOL:
case TyTy::CHAR:
case TyTy::INT:
case TyTy::UINT:
case TyTy::FLOAT:
case TyTy::USIZE:
case TyTy::ISIZE:
case TyTy::NEVER:
case TyTy::PLACEHOLDER:
case TyTy::PROJECTION:
case TyTy::DYNAMIC:
case TyTy::CLOSURE:
case TyTy::ERROR:
return new TyTy::ErrorType (0);
}
return new TyTy::ErrorType (0);
}
TyTy::BaseType *
UnifyRules::expect_str (TyTy::StrType *ltype, TyTy::BaseType *rtype)
{
switch (rtype->get_kind ())
{
case TyTy::INFER: {
TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype);
bool is_valid
= r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL;
if (is_valid)
return ltype->clone ();
}
break;
case TyTy::STR:
return rtype->clone ();
case TyTy::ADT:
case TyTy::REF:
case TyTy::POINTER:
case TyTy::PARAM:
case TyTy::ARRAY:
case TyTy::SLICE:
case TyTy::FNDEF:
case TyTy::FNPTR:
case TyTy::TUPLE:
case TyTy::BOOL:
case TyTy::CHAR:
case TyTy::INT:
case TyTy::UINT:
case TyTy::FLOAT:
case TyTy::USIZE:
case TyTy::ISIZE:
case TyTy::NEVER:
case TyTy::PLACEHOLDER:
case TyTy::PROJECTION:
case TyTy::DYNAMIC:
case TyTy::CLOSURE:
case TyTy::ERROR:
return new TyTy::ErrorType (0);
}
return new TyTy::ErrorType (0);
}
TyTy::BaseType *
UnifyRules::expect_reference (TyTy::ReferenceType *ltype, TyTy::BaseType *rtype)
{
switch (rtype->get_kind ())
{
case TyTy::INFER: {
TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype);
bool is_valid
= r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL;
if (is_valid)
return ltype->clone ();
}
break;
case TyTy::REF: {
TyTy::ReferenceType &type = *static_cast<TyTy::ReferenceType *> (rtype);
auto base_type = ltype->get_base ();
auto other_base_type = type.get_base ();
TyTy::BaseType *base_resolved
= UnifyRules::Resolve (TyTy::TyWithLocation (base_type),
TyTy::TyWithLocation (other_base_type), locus,
commit_flag, false /* emit_error */);
if (base_resolved->get_kind () == TyTy::TypeKind::ERROR)
{
return new TyTy::ErrorType (0);
}
// rust is permissive about mutablity here you can always go from
// mutable to immutable but not the otherway round
bool mutability_ok = ltype->is_mutable () ? type.is_mutable () : true;
if (!mutability_ok)
{
return new TyTy::ErrorType (0);
}
return new TyTy::ReferenceType (ltype->get_ref (), ltype->get_ty_ref (),
TyTy::TyVar (base_resolved->get_ref ()),
ltype->mutability ());
}
break;
case TyTy::STR:
case TyTy::ADT:
case TyTy::POINTER:
case TyTy::PARAM:
case TyTy::ARRAY:
case TyTy::SLICE:
case TyTy::FNDEF:
case TyTy::FNPTR:
case TyTy::TUPLE:
case TyTy::BOOL:
case TyTy::CHAR:
case TyTy::INT:
case TyTy::UINT:
case TyTy::FLOAT:
case TyTy::USIZE:
case TyTy::ISIZE:
case TyTy::NEVER:
case TyTy::PLACEHOLDER:
case TyTy::PROJECTION:
case TyTy::DYNAMIC:
case TyTy::CLOSURE:
case TyTy::ERROR:
return new TyTy::ErrorType (0);
}
return new TyTy::ErrorType (0);
}
TyTy::BaseType *
UnifyRules::expect_pointer (TyTy::PointerType *ltype, TyTy::BaseType *rtype)
{
switch (rtype->get_kind ())
{
case TyTy::INFER: {
TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype);
bool is_valid
= r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL;
if (is_valid)
return ltype->clone ();
}
break;
case TyTy::POINTER: {
TyTy::PointerType &type = *static_cast<TyTy::PointerType *> (rtype);
auto base_type = ltype->get_base ();
auto other_base_type = type.get_base ();
TyTy::BaseType *base_resolved
= UnifyRules::Resolve (TyTy::TyWithLocation (base_type),
TyTy::TyWithLocation (other_base_type), locus,
commit_flag, false /* emit_error */);
if (base_resolved->get_kind () == TyTy::TypeKind::ERROR)
{
return new TyTy::ErrorType (0);
}
// rust is permissive about mutablity here you can always go from
// mutable to immutable but not the otherway round
bool mutability_ok = ltype->is_mutable () ? type.is_mutable () : true;
if (!mutability_ok)
{
return new TyTy::ErrorType (0);
}
return new TyTy::PointerType (ltype->get_ref (), ltype->get_ty_ref (),
TyTy::TyVar (base_resolved->get_ref ()),
ltype->mutability ());
}
break;
case TyTy::STR:
case TyTy::ADT:
case TyTy::REF:
case TyTy::PARAM:
case TyTy::ARRAY:
case TyTy::SLICE:
case TyTy::FNDEF:
case TyTy::FNPTR:
case TyTy::TUPLE:
case TyTy::BOOL:
case TyTy::CHAR:
case TyTy::INT:
case TyTy::UINT:
case TyTy::FLOAT:
case TyTy::USIZE:
case TyTy::ISIZE:
case TyTy::NEVER:
case TyTy::PLACEHOLDER:
case TyTy::PROJECTION:
case TyTy::DYNAMIC:
case TyTy::CLOSURE:
case TyTy::ERROR:
return new TyTy::ErrorType (0);
}
return new TyTy::ErrorType (0);
}
TyTy::BaseType *
UnifyRules::expect_param (TyTy::ParamType *ltype, TyTy::BaseType *rtype)
{
switch (rtype->get_kind ())
{
case TyTy::INFER: {
TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype);
bool is_valid
= r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL;
if (is_valid)
return ltype->clone ();
}
break;
case TyTy::PARAM: {
TyTy::ParamType &type = *static_cast<TyTy::ParamType *> (rtype);
// bool symbol_matches
// = ltype->get_symbol ().compare (type.get_symbol ()) == 0;
// // TODO
// // I think rustc checks a debruinj index
// if (symbol_matches)
// {
// return type.clone ();
// }
// matching symbol is not going to work when we mix symbol's and have
// nested generics
// bounds match? FIXME
return type.clone ();
}
break;
case TyTy::POINTER:
case TyTy::STR:
case TyTy::ADT:
case TyTy::REF:
case TyTy::ARRAY:
case TyTy::SLICE:
case TyTy::FNDEF:
case TyTy::FNPTR:
case TyTy::TUPLE:
case TyTy::BOOL:
case TyTy::CHAR:
case TyTy::INT:
case TyTy::UINT:
case TyTy::FLOAT:
case TyTy::USIZE:
case TyTy::ISIZE:
case TyTy::NEVER:
case TyTy::PLACEHOLDER:
case TyTy::PROJECTION:
case TyTy::DYNAMIC:
case TyTy::CLOSURE:
case TyTy::ERROR:
return new TyTy::ErrorType (0);
}
return new TyTy::ErrorType (0);
}
TyTy::BaseType *
UnifyRules::expect_array (TyTy::ArrayType *ltype, TyTy::BaseType *rtype)
{
switch (rtype->get_kind ())
{
case TyTy::INFER: {
TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype);
bool is_valid
= r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL;
if (is_valid)
return ltype->clone ();
}
break;
case TyTy::ARRAY: {
TyTy::ArrayType &type = *static_cast<TyTy::ArrayType *> (rtype);
TyTy::BaseType *element_unify = UnifyRules::Resolve (
TyTy::TyWithLocation (ltype->get_element_type ()),
TyTy::TyWithLocation (type.get_element_type ()), locus, commit_flag,
false /* emit_error*/);
if (element_unify->get_kind () != TyTy::TypeKind::ERROR)
{
return new TyTy::ArrayType (type.get_ref (), type.get_ty_ref (),
type.get_ident ().locus,
type.get_capacity_expr (),
TyTy::TyVar (
element_unify->get_ref ()));
}
}
break;
case TyTy::PARAM:
case TyTy::POINTER:
case TyTy::STR:
case TyTy::ADT:
case TyTy::REF:
case TyTy::SLICE:
case TyTy::FNDEF:
case TyTy::FNPTR:
case TyTy::TUPLE:
case TyTy::BOOL:
case TyTy::CHAR:
case TyTy::INT:
case TyTy::UINT:
case TyTy::FLOAT:
case TyTy::USIZE:
case TyTy::ISIZE:
case TyTy::NEVER:
case TyTy::PLACEHOLDER:
case TyTy::PROJECTION:
case TyTy::DYNAMIC:
case TyTy::CLOSURE:
case TyTy::ERROR:
return new TyTy::ErrorType (0);
}
return new TyTy::ErrorType (0);
}
TyTy::BaseType *
UnifyRules::expect_slice (TyTy::SliceType *ltype, TyTy::BaseType *rtype)
{
switch (rtype->get_kind ())
{
case TyTy::INFER: {
TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype);
bool is_valid
= r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL;
if (is_valid)
return ltype->clone ();
}
break;
case TyTy::SLICE: {
TyTy::SliceType &type = *static_cast<TyTy::SliceType *> (rtype);
TyTy::BaseType *element_unify = UnifyRules::Resolve (
TyTy::TyWithLocation (ltype->get_element_type ()),
TyTy::TyWithLocation (type.get_element_type ()), locus, commit_flag,
false /* emit_error*/);
if (element_unify->get_kind () != TyTy::TypeKind::ERROR)
{
return new TyTy::SliceType (type.get_ref (), type.get_ty_ref (),
type.get_ident ().locus,
TyTy::TyVar (
element_unify->get_ref ()));
}
}
break;
case TyTy::PARAM:
case TyTy::POINTER:
case TyTy::STR:
case TyTy::ADT:
case TyTy::REF:
case TyTy::ARRAY:
case TyTy::FNDEF:
case TyTy::FNPTR:
case TyTy::TUPLE:
case TyTy::BOOL:
case TyTy::CHAR:
case TyTy::INT:
case TyTy::UINT:
case TyTy::FLOAT:
case TyTy::USIZE:
case TyTy::ISIZE:
case TyTy::NEVER:
case TyTy::PLACEHOLDER:
case TyTy::PROJECTION:
case TyTy::DYNAMIC:
case TyTy::CLOSURE:
case TyTy::ERROR:
return new TyTy::ErrorType (0);
}
return new TyTy::ErrorType (0);
}
TyTy::BaseType *
UnifyRules::expect_fndef (TyTy::FnType *ltype, TyTy::BaseType *rtype)
{
switch (rtype->get_kind ())
{
case TyTy::INFER: {
TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype);
bool is_valid
= r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL;
if (is_valid)
return ltype->clone ();
}
break;
case TyTy::FNDEF: {
TyTy::FnType &type = *static_cast<TyTy::FnType *> (rtype);
if (ltype->num_params () != type.num_params ())
{
return new TyTy::ErrorType (0);
}
for (size_t i = 0; i < ltype->num_params (); i++)
{
auto a = ltype->param_at (i).second;
auto b = type.param_at (i).second;
auto unified_param
= UnifyRules::Resolve (TyTy::TyWithLocation (a),
TyTy::TyWithLocation (b), locus,
commit_flag, false /* emit_errors */);
if (unified_param->get_kind () == TyTy::TypeKind::ERROR)
{
return new TyTy::ErrorType (0);
}
}
auto unified_return
= UnifyRules::Resolve (TyTy::TyWithLocation (
ltype->get_return_type ()),
TyTy::TyWithLocation (type.get_return_type ()),
locus, commit_flag, false /* emit_errors */);
if (unified_return->get_kind () == TyTy::TypeKind::ERROR)
{
return new TyTy::ErrorType (0);
}
return ltype->clone ();
}
break;
case TyTy::TUPLE:
case TyTy::BOOL:
case TyTy::CHAR:
case TyTy::INT:
case TyTy::FLOAT:
case TyTy::ISIZE:
case TyTy::ADT:
case TyTy::STR:
case TyTy::REF:
case TyTy::POINTER:
case TyTy::PARAM:
case TyTy::ARRAY:
case TyTy::SLICE:
case TyTy::FNPTR:
case TyTy::UINT:
case TyTy::USIZE:
case TyTy::NEVER:
case TyTy::PLACEHOLDER:
case TyTy::PROJECTION:
case TyTy::DYNAMIC:
case TyTy::CLOSURE:
case TyTy::ERROR:
return new TyTy::ErrorType (0);
}
return new TyTy::ErrorType (0);
}
TyTy::BaseType *
UnifyRules::expect_fnptr (TyTy::FnPtr *ltype, TyTy::BaseType *rtype)
{
switch (rtype->get_kind ())
{
case TyTy::INFER: {
TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype);
bool is_valid
= r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL;
if (is_valid)
return ltype->clone ();
}
break;
case TyTy::FNPTR: {
TyTy::FnPtr &type = *static_cast<TyTy::FnPtr *> (rtype);
if (ltype->num_params () != type.num_params ())
{
return new TyTy::ErrorType (0);
}
for (size_t i = 0; i < ltype->num_params (); i++)
{
auto a = ltype->param_at (i);
auto b = type.param_at (i);
auto unified_param
= UnifyRules::Resolve (TyTy::TyWithLocation (a),
TyTy::TyWithLocation (b), locus,
commit_flag, false /* emit_errors */);
if (unified_param->get_kind () == TyTy::TypeKind::ERROR)
{
return new TyTy::ErrorType (0);
}
}
auto unified_return
= UnifyRules::Resolve (TyTy::TyWithLocation (
ltype->get_return_type ()),
TyTy::TyWithLocation (type.get_return_type ()),
locus, commit_flag, false /* emit_errors */);
if (unified_return->get_kind () == TyTy::TypeKind::ERROR)
{
return new TyTy::ErrorType (0);
}
return ltype->clone ();
}
break;
case TyTy::FNDEF: {
TyTy::FnType &type = *static_cast<TyTy::FnType *> (rtype);
auto this_ret_type = ltype->get_return_type ();
auto other_ret_type = type.get_return_type ();
auto unified_result
= UnifyRules::Resolve (TyTy::TyWithLocation (this_ret_type),
TyTy::TyWithLocation (other_ret_type), locus,
commit_flag, false /*emit_errors*/);
if (unified_result->get_kind () == TyTy::TypeKind::ERROR)
{
return new TyTy::ErrorType (0);
}
if (ltype->num_params () != type.num_params ())
{
return new TyTy::ErrorType (0);
}
for (size_t i = 0; i < ltype->num_params (); i++)
{
auto this_param = ltype->param_at (i);
auto other_param = type.param_at (i).second;
auto unified_param
= UnifyRules::Resolve (TyTy::TyWithLocation (this_param),
TyTy::TyWithLocation (other_param), locus,
commit_flag, false /* emit_errors */);
if (unified_param->get_kind () == TyTy::TypeKind::ERROR)
{
return new TyTy::ErrorType (0);
}
}
return ltype->clone ();
}
break;
case TyTy::TUPLE:
case TyTy::BOOL:
case TyTy::CHAR:
case TyTy::INT:
case TyTy::FLOAT:
case TyTy::ISIZE:
case TyTy::ADT:
case TyTy::STR:
case TyTy::REF:
case TyTy::POINTER:
case TyTy::PARAM:
case TyTy::ARRAY:
case TyTy::SLICE:
case TyTy::UINT:
case TyTy::USIZE:
case TyTy::NEVER:
case TyTy::PLACEHOLDER:
case TyTy::PROJECTION:
case TyTy::DYNAMIC:
case TyTy::CLOSURE:
case TyTy::ERROR:
return new TyTy::ErrorType (0);
}
return new TyTy::ErrorType (0);
}
TyTy::BaseType *
UnifyRules::expect_tuple (TyTy::TupleType *ltype, TyTy::BaseType *rtype)
{
switch (rtype->get_kind ())
{
case TyTy::INFER: {
TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype);
bool is_valid
= r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL;
if (is_valid)
return ltype->clone ();
}
break;
case TyTy::TUPLE: {
TyTy::TupleType &type = *static_cast<TyTy::TupleType *> (rtype);
if (ltype->num_fields () != type.num_fields ())
{
return new TyTy::ErrorType (0);
}
std::vector<TyTy::TyVar> fields;
for (size_t i = 0; i < ltype->num_fields (); i++)
{
TyTy::BaseType *bo = ltype->get_field (i);
TyTy::BaseType *fo = type.get_field (i);
TyTy::BaseType *unified_ty
= UnifyRules::Resolve (TyTy::TyWithLocation (bo),
TyTy::TyWithLocation (fo), locus,
commit_flag, false /* emit_errors */);
if (unified_ty->get_kind () == TyTy::TypeKind::ERROR)
return new TyTy::ErrorType (0);
fields.push_back (TyTy::TyVar (unified_ty->get_ref ()));
}
return new TyTy::TupleType (type.get_ref (), type.get_ty_ref (),
type.get_ident ().locus, fields);
}
break;
case TyTy::BOOL:
case TyTy::CHAR:
case TyTy::INT:
case TyTy::FLOAT:
case TyTy::ISIZE:
case TyTy::ADT:
case TyTy::STR:
case TyTy::REF:
case TyTy::POINTER:
case TyTy::PARAM:
case TyTy::ARRAY:
case TyTy::SLICE:
case TyTy::FNDEF:
case TyTy::FNPTR:
case TyTy::UINT:
case TyTy::USIZE:
case TyTy::NEVER:
case TyTy::PLACEHOLDER:
case TyTy::PROJECTION:
case TyTy::DYNAMIC:
case TyTy::CLOSURE:
case TyTy::ERROR:
return new TyTy::ErrorType (0);
}
return new TyTy::ErrorType (0);
}
TyTy::BaseType *
UnifyRules::expect_bool (TyTy::BoolType *ltype, TyTy::BaseType *rtype)
{
switch (rtype->get_kind ())
{
case TyTy::INFER: {
TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype);
bool is_valid
= r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL;
if (is_valid)
return ltype->clone ();
}
break;
case TyTy::BOOL:
return rtype->clone ();
case TyTy::CHAR:
case TyTy::INT:
case TyTy::FLOAT:
case TyTy::ISIZE:
case TyTy::ADT:
case TyTy::STR:
case TyTy::REF:
case TyTy::POINTER:
case TyTy::PARAM:
case TyTy::ARRAY:
case TyTy::SLICE:
case TyTy::FNDEF:
case TyTy::FNPTR:
case TyTy::TUPLE:
case TyTy::UINT:
case TyTy::USIZE:
case TyTy::NEVER:
case TyTy::PLACEHOLDER:
case TyTy::PROJECTION:
case TyTy::DYNAMIC:
case TyTy::CLOSURE:
case TyTy::ERROR:
return new TyTy::ErrorType (0);
}
return new TyTy::ErrorType (0);
}
TyTy::BaseType *
UnifyRules::expect_char (TyTy::CharType *ltype, TyTy::BaseType *rtype)
{
switch (rtype->get_kind ())
{
case TyTy::INFER: {
TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype);
bool is_valid
= r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL;
if (is_valid)
return ltype->clone ();
}
break;
case TyTy::CHAR:
return rtype->clone ();
case TyTy::INT:
case TyTy::FLOAT:
case TyTy::ISIZE:
case TyTy::ADT:
case TyTy::STR:
case TyTy::REF:
case TyTy::POINTER:
case TyTy::PARAM:
case TyTy::ARRAY:
case TyTy::SLICE:
case TyTy::FNDEF:
case TyTy::FNPTR:
case TyTy::TUPLE:
case TyTy::BOOL:
case TyTy::UINT:
case TyTy::USIZE:
case TyTy::NEVER:
case TyTy::PLACEHOLDER:
case TyTy::PROJECTION:
case TyTy::DYNAMIC:
case TyTy::CLOSURE:
case TyTy::ERROR:
return new TyTy::ErrorType (0);
}
return new TyTy::ErrorType (0);
}
TyTy::BaseType *
UnifyRules::expect_int (TyTy::IntType *ltype, TyTy::BaseType *rtype)
{
switch (rtype->get_kind ())
{
case TyTy::INFER: {
TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype);
bool is_valid
= r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL
|| r->get_infer_kind () == TyTy::InferType::InferTypeKind::INTEGRAL;
if (is_valid)
return ltype->clone ();
}
break;
case TyTy::INT: {
TyTy::IntType &type = *static_cast<TyTy::IntType *> (rtype);
bool is_valid = ltype->get_int_kind () == type.get_int_kind ();
if (is_valid)
return new TyTy::IntType (type.get_ref (), type.get_ty_ref (),
type.get_int_kind ());
}
break;
case TyTy::FLOAT:
case TyTy::ISIZE:
case TyTy::ADT:
case TyTy::STR:
case TyTy::REF:
case TyTy::POINTER:
case TyTy::PARAM:
case TyTy::ARRAY:
case TyTy::SLICE:
case TyTy::FNDEF:
case TyTy::FNPTR:
case TyTy::TUPLE:
case TyTy::BOOL:
case TyTy::CHAR:
case TyTy::UINT:
case TyTy::USIZE:
case TyTy::NEVER:
case TyTy::PLACEHOLDER:
case TyTy::PROJECTION:
case TyTy::DYNAMIC:
case TyTy::CLOSURE:
case TyTy::ERROR:
return new TyTy::ErrorType (0);
}
return new TyTy::ErrorType (0);
}
TyTy::BaseType *
UnifyRules::expect_uint (TyTy::UintType *ltype, TyTy::BaseType *rtype)
{
switch (rtype->get_kind ())
{
case TyTy::INFER: {
TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype);
bool is_valid
= r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL
|| r->get_infer_kind () == TyTy::InferType::InferTypeKind::INTEGRAL;
if (is_valid)
return ltype->clone ();
}
break;
case TyTy::UINT: {
TyTy::UintType &type = *static_cast<TyTy::UintType *> (rtype);
bool is_valid = ltype->get_uint_kind () == type.get_uint_kind ();
if (is_valid)
return new TyTy::UintType (type.get_ref (), type.get_ty_ref (),
type.get_uint_kind ());
}
break;
case TyTy::FLOAT:
case TyTy::ISIZE:
case TyTy::ADT:
case TyTy::STR:
case TyTy::REF:
case TyTy::POINTER:
case TyTy::PARAM:
case TyTy::ARRAY:
case TyTy::SLICE:
case TyTy::FNDEF:
case TyTy::FNPTR:
case TyTy::TUPLE:
case TyTy::BOOL:
case TyTy::CHAR:
case TyTy::INT:
case TyTy::USIZE:
case TyTy::NEVER:
case TyTy::PLACEHOLDER:
case TyTy::PROJECTION:
case TyTy::DYNAMIC:
case TyTy::CLOSURE:
case TyTy::ERROR:
return new TyTy::ErrorType (0);
}
return new TyTy::ErrorType (0);
}
TyTy::BaseType *
UnifyRules::expect_float (TyTy::FloatType *ltype, TyTy::BaseType *rtype)
{
switch (rtype->get_kind ())
{
case TyTy::INFER: {
TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype);
bool is_valid
= r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL
|| r->get_infer_kind () == TyTy::InferType::InferTypeKind::FLOAT;
if (is_valid)
return ltype->clone ();
}
break;
case TyTy::FLOAT: {
TyTy::FloatType &type = *static_cast<TyTy::FloatType *> (rtype);
bool is_valid = ltype->get_float_kind () == type.get_float_kind ();
if (is_valid)
return new TyTy::FloatType (type.get_ref (), type.get_ty_ref (),
type.get_float_kind ());
}
break;
case TyTy::ISIZE:
case TyTy::ADT:
case TyTy::STR:
case TyTy::REF:
case TyTy::POINTER:
case TyTy::PARAM:
case TyTy::ARRAY:
case TyTy::SLICE:
case TyTy::FNDEF:
case TyTy::FNPTR:
case TyTy::TUPLE:
case TyTy::BOOL:
case TyTy::CHAR:
case TyTy::INT:
case TyTy::UINT:
case TyTy::USIZE:
case TyTy::NEVER:
case TyTy::PLACEHOLDER:
case TyTy::PROJECTION:
case TyTy::DYNAMIC:
case TyTy::CLOSURE:
case TyTy::ERROR:
return new TyTy::ErrorType (0);
}
return new TyTy::ErrorType (0);
}
TyTy::BaseType *
UnifyRules::expect_isize (TyTy::ISizeType *ltype, TyTy::BaseType *rtype)
{
switch (rtype->get_kind ())
{
case TyTy::INFER: {
TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype);
bool is_valid
= r->get_infer_kind () != TyTy::InferType::InferTypeKind::FLOAT;
if (is_valid)
return ltype->clone ();
}
break;
case TyTy::ISIZE:
return rtype->clone ();
case TyTy::ADT:
case TyTy::STR:
case TyTy::REF:
case TyTy::POINTER:
case TyTy::PARAM:
case TyTy::ARRAY:
case TyTy::SLICE:
case TyTy::FNDEF:
case TyTy::FNPTR:
case TyTy::TUPLE:
case TyTy::BOOL:
case TyTy::CHAR:
case TyTy::INT:
case TyTy::UINT:
case TyTy::FLOAT:
case TyTy::USIZE:
case TyTy::NEVER:
case TyTy::PLACEHOLDER:
case TyTy::PROJECTION:
case TyTy::DYNAMIC:
case TyTy::CLOSURE:
case TyTy::ERROR:
return new TyTy::ErrorType (0);
}
return new TyTy::ErrorType (0);
}
TyTy::BaseType *
UnifyRules::expect_usize (TyTy::USizeType *ltype, TyTy::BaseType *rtype)
{
switch (rtype->get_kind ())
{
case TyTy::INFER: {
TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype);
bool is_valid
= r->get_infer_kind () != TyTy::InferType::InferTypeKind::FLOAT;
if (is_valid)
return ltype->clone ();
}
break;
case TyTy::USIZE:
return rtype->clone ();
case TyTy::ADT:
case TyTy::STR:
case TyTy::REF:
case TyTy::POINTER:
case TyTy::PARAM:
case TyTy::ARRAY:
case TyTy::SLICE:
case TyTy::FNDEF:
case TyTy::FNPTR:
case TyTy::TUPLE:
case TyTy::BOOL:
case TyTy::CHAR:
case TyTy::INT:
case TyTy::UINT:
case TyTy::FLOAT:
case TyTy::ISIZE:
case TyTy::NEVER:
case TyTy::PLACEHOLDER:
case TyTy::PROJECTION:
case TyTy::DYNAMIC:
case TyTy::CLOSURE:
case TyTy::ERROR:
return new TyTy::ErrorType (0);
}
return new TyTy::ErrorType (0);
}
TyTy::BaseType *
UnifyRules::expect_never (TyTy::NeverType *ltype, TyTy::BaseType *rtype)
{
switch (rtype->get_kind ())
{
case TyTy::INFER: {
TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype);
bool is_valid
= r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL;
if (is_valid)
return ltype->clone ();
}
break;
case TyTy::NEVER:
return rtype->clone ();
case TyTy::PLACEHOLDER:
case TyTy::PROJECTION:
case TyTy::DYNAMIC:
case TyTy::CLOSURE:
case TyTy::SLICE:
case TyTy::PARAM:
case TyTy::POINTER:
case TyTy::STR:
case TyTy::ADT:
case TyTy::REF:
case TyTy::ARRAY:
case TyTy::FNDEF:
case TyTy::FNPTR:
case TyTy::TUPLE:
case TyTy::BOOL:
case TyTy::CHAR:
case TyTy::INT:
case TyTy::UINT:
case TyTy::FLOAT:
case TyTy::USIZE:
case TyTy::ISIZE:
case TyTy::ERROR:
return new TyTy::ErrorType (0);
}
return new TyTy::ErrorType (0);
}
TyTy::BaseType *
UnifyRules::expect_placeholder (TyTy::PlaceholderType *ltype,
TyTy::BaseType *rtype)
{
switch (rtype->get_kind ())
{
case TyTy::INFER: {
TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype);
bool is_valid
= r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL;
if (is_valid)
return ltype->clone ();
}
break;
case TyTy::PLACEHOLDER: {
TyTy::PlaceholderType &type
= *static_cast<TyTy::PlaceholderType *> (rtype);
bool symbol_match
= ltype->get_symbol ().compare (type.get_symbol ()) == 0;
if (symbol_match)
{
return type.clone ();
}
}
break;
case TyTy::PROJECTION:
case TyTy::DYNAMIC:
case TyTy::CLOSURE:
case TyTy::SLICE:
case TyTy::PARAM:
case TyTy::POINTER:
case TyTy::STR:
case TyTy::ADT:
case TyTy::REF:
case TyTy::ARRAY:
case TyTy::FNDEF:
case TyTy::FNPTR:
case TyTy::TUPLE:
case TyTy::BOOL:
case TyTy::CHAR:
case TyTy::INT:
case TyTy::UINT:
case TyTy::FLOAT:
case TyTy::USIZE:
case TyTy::ISIZE:
case TyTy::NEVER:
case TyTy::ERROR:
return new TyTy::ErrorType (0);
}
return new TyTy::ErrorType (0);
}
TyTy::BaseType *
UnifyRules::expect_projection (TyTy::ProjectionType *ltype,
TyTy::BaseType *rtype)
{
switch (rtype->get_kind ())
{
case TyTy::INFER: {
TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype);
bool is_valid
= r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL;
if (is_valid)
return ltype->clone ();
}
break;
// FIXME
case TyTy::PROJECTION:
gcc_unreachable ();
break;
case TyTy::DYNAMIC:
case TyTy::CLOSURE:
case TyTy::SLICE:
case TyTy::PARAM:
case TyTy::POINTER:
case TyTy::STR:
case TyTy::ADT:
case TyTy::REF:
case TyTy::ARRAY:
case TyTy::FNDEF:
case TyTy::FNPTR:
case TyTy::TUPLE:
case TyTy::BOOL:
case TyTy::CHAR:
case TyTy::INT:
case TyTy::UINT:
case TyTy::FLOAT:
case TyTy::USIZE:
case TyTy::ISIZE:
case TyTy::NEVER:
case TyTy::PLACEHOLDER:
case TyTy::ERROR:
return new TyTy::ErrorType (0);
}
return new TyTy::ErrorType (0);
}
TyTy::BaseType *
UnifyRules::expect_dyn (TyTy::DynamicObjectType *ltype, TyTy::BaseType *rtype)
{
switch (rtype->get_kind ())
{
case TyTy::INFER: {
TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype);
bool is_valid
= r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL;
if (is_valid)
return ltype->clone ();
}
break;
case TyTy::DYNAMIC: {
TyTy::DynamicObjectType &type
= *static_cast<TyTy::DynamicObjectType *> (rtype);
if (ltype->num_specified_bounds () != type.num_specified_bounds ())
{
return new TyTy::ErrorType (0);
}
if (!ltype->bounds_compatible (type, locus, true))
{
return new TyTy::ErrorType (0);
}
return ltype->clone ();
}
break;
case TyTy::CLOSURE:
case TyTy::SLICE:
case TyTy::PARAM:
case TyTy::POINTER:
case TyTy::STR:
case TyTy::ADT:
case TyTy::REF:
case TyTy::ARRAY:
case TyTy::FNDEF:
case TyTy::FNPTR:
case TyTy::TUPLE:
case TyTy::BOOL:
case TyTy::CHAR:
case TyTy::INT:
case TyTy::UINT:
case TyTy::FLOAT:
case TyTy::USIZE:
case TyTy::ISIZE:
case TyTy::NEVER:
case TyTy::PLACEHOLDER:
case TyTy::PROJECTION:
case TyTy::ERROR:
return new TyTy::ErrorType (0);
}
return new TyTy::ErrorType (0);
}
TyTy::BaseType *
UnifyRules::expect_closure (TyTy::ClosureType *ltype, TyTy::BaseType *rtype)
{
switch (rtype->get_kind ())
{
case TyTy::INFER: {
TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype);
bool is_valid
= r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL;
if (is_valid)
return ltype->clone ();
}
break;
case TyTy::CLOSURE: {
TyTy::ClosureType &type = *static_cast<TyTy::ClosureType *> (rtype);
if (ltype->get_def_id () != type.get_def_id ())
{
return new TyTy::ErrorType (0);
}
TyTy::BaseType *args_res
= UnifyRules::Resolve (TyTy::TyWithLocation (
&ltype->get_parameters ()),
TyTy::TyWithLocation (&type.get_parameters ()),
locus, commit_flag, false /* emit_error */);
if (args_res->get_kind () == TyTy::TypeKind::ERROR)
{
return new TyTy::ErrorType (0);
}
TyTy::BaseType *res = UnifyRules::Resolve (
TyTy::TyWithLocation (&ltype->get_result_type ()),
TyTy::TyWithLocation (&type.get_result_type ()), locus, commit_flag,
false /* emit_error */);
if (res == nullptr || res->get_kind () == TyTy::TypeKind::ERROR)
{
return new TyTy::ErrorType (0);
}
return ltype->clone ();
}
break;
case TyTy::SLICE:
case TyTy::PARAM:
case TyTy::POINTER:
case TyTy::STR:
case TyTy::ADT:
case TyTy::REF:
case TyTy::ARRAY:
case TyTy::FNDEF:
case TyTy::FNPTR:
case TyTy::TUPLE:
case TyTy::BOOL:
case TyTy::CHAR:
case TyTy::INT:
case TyTy::UINT:
case TyTy::FLOAT:
case TyTy::USIZE:
case TyTy::ISIZE:
case TyTy::NEVER:
case TyTy::PLACEHOLDER:
case TyTy::PROJECTION:
case TyTy::DYNAMIC:
case TyTy::ERROR:
return new TyTy::ErrorType (0);
}
return new TyTy::ErrorType (0);
}
} // namespace Resolver
} // namespace Rust