From patchwork Wed Apr 5 14:03:34 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arthur Cohen X-Patchwork-Id: 79715 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:b0ea:0:b0:3b6:4342:cba0 with SMTP id b10csp362038vqo; Wed, 5 Apr 2023 07:46:13 -0700 (PDT) X-Google-Smtp-Source: AKy350ay/MnySfOBjnsVm9cGrCeePqMjt1LvSrFv9sDVKaXOdjEQWV61Jw5b9CfUKZKliQQIHv/g X-Received: by 2002:a17:906:6d6:b0:8f6:5a70:cccc with SMTP id v22-20020a17090606d600b008f65a70ccccmr3400686ejb.66.1680705973698; Wed, 05 Apr 2023 07:46:13 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1680705973; cv=none; d=google.com; s=arc-20160816; b=JJL0dnfk1N12FO60zGCSZ3g/km6MHskJxv+cPz3K0/VkF5i70TrwZ4fs3NZzF9f4I0 lohUmSxrTT3A59Z2vaCpooibqN4KZlN4fODNuqhJRcpnXGopeOspdBo95SnRqc0lzFOp rvDeu3S2MU+DXTTRU2u+0vrqsDeSEX0YWu0l0UIRHA/ti5vvAN5e6mbMUqkh9gNKUHW0 Zckka3y9xT47YFx/MoWoUt78jC/TlPgRwCGBqHPaX9KdSW154WX8Wtjw05x0rHro/cP9 SYguYhB2/OezQ4gbbXIYvL8pF94PMT9HJP5SReoisDuEv287DNByuneIVjVtUvgJ8Lyx plcg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:reply-to:list-subscribe:list-help:list-post :list-archive:list-unsubscribe:list-id:precedence :content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:dkim-signature:dmarc-filter :delivered-to; bh=TPAVMNhi8KIDS5nM/JlCR+qN8Hui31lYY30a4DrlLWg=; b=sm2XbpwQbtRDq7IwO0Wq3ncwGZnRzy9wch2Kzp3/FT2cHT3T6GCpAcMjc2dVJjIkqw gb218pnqVhFXGYwckgw0gKcXp8yJkZ+5LNawnRqwCfgeglfo0BlfQgL+VUHXgXBWEiHS iBGCPRA317WbsZy5tAcv3ZebzNYddcU/fTDkBdRRsPIp98Y7wkdGV253Oe1DwC47ipM1 bGNESEKm+Y9rXiszEdSZGGo3B2HD6I2O8aWNVxjALQDUxtRTIqirXNTTWEch/Fpb8UoI qMyIxsIqijBvyQIi0W6j+SjYTMf2tnq2iZGmkoFPoUR9noNlq7RdQ6CaeoNQf1KfjLbO cc+g== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@embecosm.com header.s=google header.b=Fj7y0DQO; spf=pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 8.43.85.97 as permitted sender) smtp.mailfrom="gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org" Received: from sourceware.org (ip-8-43-85-97.sourceware.org. [8.43.85.97]) by mx.google.com with ESMTPS id hh9-20020a170906a94900b00939c3d2329csi638902ejb.396.2023.04.05.07.46.13 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 05 Apr 2023 07:46:13 -0700 (PDT) Received-SPF: pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 8.43.85.97 as permitted sender) client-ip=8.43.85.97; Authentication-Results: mx.google.com; dkim=pass header.i=@embecosm.com header.s=google header.b=Fj7y0DQO; spf=pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 8.43.85.97 as permitted sender) smtp.mailfrom="gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org" Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 444DE39E33E2 for ; Wed, 5 Apr 2023 14:16:36 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-wm1-x333.google.com (mail-wm1-x333.google.com [IPv6:2a00:1450:4864:20::333]) by sourceware.org (Postfix) with ESMTPS id E128C3877039 for ; Wed, 5 Apr 2023 14:06:05 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org E128C3877039 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=embecosm.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=embecosm.com Received: by mail-wm1-x333.google.com with SMTP id p34so20958592wms.3 for ; Wed, 05 Apr 2023 07:06:05 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=embecosm.com; s=google; t=1680703565; h=content-transfer-encoding:mime-version:reply-to:references :in-reply-to:message-id:date:subject:cc:to:from:from:to:cc:subject :date:message-id:reply-to; bh=TPAVMNhi8KIDS5nM/JlCR+qN8Hui31lYY30a4DrlLWg=; b=Fj7y0DQOz/mxkflaMT3GvbEfPUXt8DZUNvTL/XOSKkPwVTPTSbI8PVr9p1UF/FVpT3 0QsNcT6FYE1aCmq5q2uEInnJJZCv++ifCMa7+YpcrCYKNt5G7Bd+kvIId4XBnLg5F2j2 manbUm+CXjQt8lwpJTm1nFV+pwS/neWVz4xlhFREwW/+onENcokUuW6yVHtcPXlxvuvR QrkMMBCpj8qfSn2qDAKP4ClFphTwv6PVzz5AABIAce3N5SPMjfC2WYYEJV8TfjhCxCy4 81jwWJjuYtl9tR8vSOAhPS52Rx5mx318SyxL9r1rufwVeKS2k9Vz6C3kl90EkIS4hS3u HOKw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; t=1680703565; h=content-transfer-encoding:mime-version:reply-to:references :in-reply-to:message-id:date:subject:cc:to:from:x-gm-message-state :from:to:cc:subject:date:message-id:reply-to; bh=TPAVMNhi8KIDS5nM/JlCR+qN8Hui31lYY30a4DrlLWg=; b=mRl12JeXfVIZvvBmRsXzJRrh6pEgI1IaBVCne4h8ryMhqtmrnuMHzYFwKgK14nN2k+ LkcyqFAg+hOahreAZneCQerQdi0MF2u2JAE3x+enYHgvopLlmhF0TbpkY2q1WERh/4C/ osrNisIpp3PSuLKUx/4QlVR3pxfGk6TEQ91VYpVy9rdxyh4SrxVuv3e8YIcCYRBqMr6i W4ng/FR6c/mLmks66pbU1qvh5yMZdyfD0ibbqC91In/E45/VkOSefEYk2DsIql9QbKy1 U4H8CJr2pBGKo/jqgQM6dGe2D6ctW81Rlgw365wfk/z9a9gwwRIJS6x1PKlt6w50IWxS hBww== X-Gm-Message-State: AAQBX9cFpYK3Gv/16jlN0ErYqYAmDr6rN6tF+a1L9DY1Tc018kHFdQFU LhvceLjDWwf5zhALM9zR/enxFhSMFfo3IAcBXQ== X-Received: by 2002:a05:600c:2909:b0:3ef:d6be:897a with SMTP id i9-20020a05600c290900b003efd6be897amr4697816wmd.16.1680703563734; Wed, 05 Apr 2023 07:06:03 -0700 (PDT) Received: from platypus.localdomain ([62.23.166.218]) by smtp.gmail.com with ESMTPSA id ay8-20020a05600c1e0800b003edddae1068sm2330150wmb.9.2023.04.05.07.06.03 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 05 Apr 2023 07:06:03 -0700 (PDT) From: arthur.cohen@embecosm.com To: gcc-patches@gcc.gnu.org Cc: gcc-rust@gcc.gnu.org, Philip Herron Subject: [committed 50/88] gccrs: Refactor the type unification code Date: Wed, 5 Apr 2023 16:03:34 +0200 Message-Id: <20230405140411.3016563-51-arthur.cohen@embecosm.com> X-Mailer: git-send-email 2.40.0 In-Reply-To: <20230405140411.3016563-1-arthur.cohen@embecosm.com> References: <20230405140411.3016563-1-arthur.cohen@embecosm.com> MIME-Version: 1.0 X-Spam-Status: No, score=-14.6 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: arthur.cohen@embecosm.com Errors-To: gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org Sender: "Gcc-patches" X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1762347946788094086?= X-GMAIL-MSGID: =?utf-8?q?1762347946788094086?= From: Philip Herron This refactors the unification systems to be a consistent interface using switch statements and simple functions instead of the old clunky visitor system. This is more maintainable as it is harder to miss cases when we can take advantages of switch statements. Signed-off-by: Philip Herron gcc/rust/ChangeLog: * Make-lang.in: update names * backend/rust-compile-expr.cc (CompileExpr::resolve_method_address): update to use new interface * typecheck/rust-coercion.cc (TypeCoercionRules::coerce_borrowed_pointer): likewise * typecheck/rust-hir-type-check-base.cc (TypeCheckBase::unify_site): likewise * typecheck/rust-tyty.cc (BaseType::destructure): likewise (InferType::unify): removed old unify interface (ErrorType::unify): likewise (ADTType::unify): likewise (TupleType::unify): likewise (FnType::unify): likewise (FnPtr::unify): likewise (ClosureType::unify): likewise (ArrayType::unify): likewise (SliceType::unify): likewise (BoolType::unify): likewise (IntType::unify): likewise (UintType::unify): likewise (FloatType::unify): likewise (USizeType::unify): likewise (ISizeType::unify): likewise (CharType::unify): likewise (ReferenceType::unify): likewise (PointerType::unify): likewise (ParamType::unify): likewise (StrType::unify): likewise (NeverType::unify): likewise (PlaceholderType::unify): likewise (ProjectionType::unify): likewise (DynamicObjectType::unify): likewise * typecheck/rust-tyty.h: update destructure interface * typecheck/rust-tyty-rules.h: Removed. * typecheck/rust-unify.cc: New file. * typecheck/rust-unify.h: New file. gcc/testsuite/ChangeLog: * rust/compile/never_type_err1.rs: Moved to... * rust/compile/never_type1.rs: ...here. It now works --- gcc/rust/Make-lang.in | 1 + gcc/rust/backend/rust-compile-expr.cc | 6 +- gcc/rust/typecheck/rust-coercion.cc | 6 +- .../typecheck/rust-hir-type-check-base.cc | 15 +- gcc/rust/typecheck/rust-tyty-rules.h | 1406 -------------- gcc/rust/typecheck/rust-tyty.cc | 229 +-- gcc/rust/typecheck/rust-tyty.h | 31 +- gcc/rust/typecheck/rust-unify.cc | 1640 +++++++++++++++++ gcc/rust/typecheck/rust-unify.h | 91 + .../{never_type_err1.rs => never_type1.rs} | 3 +- 10 files changed, 1807 insertions(+), 1621 deletions(-) delete mode 100644 gcc/rust/typecheck/rust-tyty-rules.h create mode 100644 gcc/rust/typecheck/rust-unify.cc create mode 100644 gcc/rust/typecheck/rust-unify.h rename gcc/testsuite/rust/compile/{never_type_err1.rs => never_type1.rs} (52%) diff --git a/gcc/rust/Make-lang.in b/gcc/rust/Make-lang.in index 4752bb83562..1d2f34d7919 100644 --- a/gcc/rust/Make-lang.in +++ b/gcc/rust/Make-lang.in @@ -134,6 +134,7 @@ GRS_OBJS = \ rust/rust-hir-path-probe.o \ rust/rust-coercion.o \ rust/rust-casts.o \ + rust/rust-unify.o \ rust/rust-hir-type-check-base.o \ rust/rust-autoderef.o \ rust/rust-substitution-mapper.o \ diff --git a/gcc/rust/backend/rust-compile-expr.cc b/gcc/rust/backend/rust-compile-expr.cc index c26f6f440ec..d7945dbf26b 100644 --- a/gcc/rust/backend/rust-compile-expr.cc +++ b/gcc/rust/backend/rust-compile-expr.cc @@ -26,6 +26,7 @@ #include "rust-compile-block.h" #include "rust-compile-implitem.h" #include "rust-constexpr.h" +#include "rust-unify.h" #include "rust-gcc.h" #include "fold-const.h" @@ -2006,7 +2007,10 @@ CompileExpr::resolve_method_address (TyTy::FnType *fntype, HirId ref, { TyTy::BaseType *infer_impl_call = candidate_call->infer_substitions (expr_locus); - monomorphized = infer_impl_call->unify (fntype); + monomorphized = Resolver::UnifyRules::Resolve ( + TyTy::TyWithLocation (infer_impl_call), + TyTy::TyWithLocation (fntype), expr_locus, true /* commit */, + true /* emit_errors */); } return CompileInherentImplItem::Compile (impl_item, ctx, monomorphized); diff --git a/gcc/rust/typecheck/rust-coercion.cc b/gcc/rust/typecheck/rust-coercion.cc index fdf8eb95a33..bea40840fbf 100644 --- a/gcc/rust/typecheck/rust-coercion.cc +++ b/gcc/rust/typecheck/rust-coercion.cc @@ -18,6 +18,7 @@ #include "rust-hir-type-check-base.h" #include "rust-coercion.h" +#include "rust-unify.h" namespace Rust { namespace Resolver { @@ -218,7 +219,10 @@ TypeCoercionRules::coerce_borrowed_pointer (TyTy::BaseType *receiver, // we might be able to replace this with a can_eq because we default // back to a final unity anyway rust_debug ("coerce_borrowed_pointer -- unify"); - TyTy::BaseType *result = receiver->unify (expected); + TyTy::BaseType *result + = UnifyRules::Resolve (TyTy::TyWithLocation (receiver), + TyTy::TyWithLocation (expected), locus, + true /* commit */, true /* emit_errors */); return CoercionResult{{}, result}; } } diff --git a/gcc/rust/typecheck/rust-hir-type-check-base.cc b/gcc/rust/typecheck/rust-hir-type-check-base.cc index 85826aec8fe..6e42b7b7b23 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-base.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-base.cc @@ -22,6 +22,7 @@ #include "rust-hir-type-check-expr.h" #include "rust-hir-type-check-implitem.h" #include "rust-coercion.h" +#include "rust-unify.h" #include "rust-casts.h" namespace Rust { @@ -359,18 +360,8 @@ TypeCheckBase::unify_site (HirId id, TyTy::TyWithLocation lhs, rust_debug ("unify_site id={%u} expected={%s} expr={%s}", id, expected->debug_str ().c_str (), expr->debug_str ().c_str ()); - TyTy::BaseType *unified = expected->unify (expr); - if (unified->get_kind () == TyTy::TypeKind::ERROR) - { - RichLocation r (unify_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 ()); - } - - return unified; + return UnifyRules::Resolve (lhs, rhs, unify_locus, true /*commit*/, + true /*emit_error*/); } TyTy::BaseType * diff --git a/gcc/rust/typecheck/rust-tyty-rules.h b/gcc/rust/typecheck/rust-tyty-rules.h deleted file mode 100644 index cfe269221bd..00000000000 --- a/gcc/rust/typecheck/rust-tyty-rules.h +++ /dev/null @@ -1,1406 +0,0 @@ -// 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 -// . - -#ifndef RUST_TYTY_RULES -#define RUST_TYTY_RULES - -#include "rust-diagnostics.h" -#include "rust-tyty.h" -#include "rust-tyty-visitor.h" -#include "rust-hir-map.h" -#include "rust-hir-type-check.h" - -namespace Rust { -namespace TyTy { - -/* Rules specify how to unify two Ty. For example, the result of unifying the - two tuples (u64, A) and (B, i64) would be (u64, i64). - - Performing a unification requires a double dispatch. To illustrate, suppose - we want to unify `ty1` and `ty2`. Here's what it looks like: - 1. The caller calls `ty1.unify(ty2)`. This is the first dispatch. - 2. `ty1` creates a rule specific to its type(e.g. TupleRules). - 3. The rule calls `ty2.accept_vis(rule)`. This is the second dispatch. - 4. `ty2` calls `rule.visit(*this)`, which will method-overload to the - correct implementation at compile time. - - The nice thing about Rules is that they seperate unification logic from the - representation of Ty. To support unifying a new Ty, implement its - `accept_vis` and `unify` method to pass the unification request to Rules. - Then, create a new `XXXRules` class and implement one `visit` method for - every Ty it can unify with. */ -class BaseRules : public TyVisitor -{ -public: - virtual ~BaseRules () {} - - /* Unify two ty. Returns a pointer to the newly-created unified ty, or nullptr - if the two types cannot be unified. The caller is responsible for releasing - the memory of the returned ty. - - This method is meant to be used internally by Ty. If you're trying to unify - two ty, you can simply call `unify` on ty themselves. */ - virtual BaseType *unify (BaseType *other) - { - if (other->get_kind () == TypeKind::PARAM) - { - ParamType *p = static_cast (other); - other = p->resolve (); - } - else if (other->get_kind () == TypeKind::PLACEHOLDER) - { - PlaceholderType *p = static_cast (other); - if (p->can_resolve ()) - { - other = p->resolve (); - return get_base ()->unify (other); - } - } - else if (other->get_kind () == TypeKind::PROJECTION) - { - ProjectionType *p = static_cast (other); - other = p->get (); - return get_base ()->unify (other); - } - - other->accept_vis (*this); - if (resolved->get_kind () == TyTy::TypeKind::ERROR) - return resolved; - - resolved->append_reference (get_base ()->get_ref ()); - resolved->append_reference (other->get_ref ()); - for (auto ref : get_base ()->get_combined_refs ()) - resolved->append_reference (ref); - for (auto ref : other->get_combined_refs ()) - resolved->append_reference (ref); - - other->append_reference (resolved->get_ref ()); - other->append_reference (get_base ()->get_ref ()); - get_base ()->append_reference (resolved->get_ref ()); - get_base ()->append_reference (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 (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) - { - context->insert_type ( - Analysis::NodeMapping (mappings->get_current_crate (), - UNKNOWN_NODEID, ref, - UNKNOWN_LOCAL_DEFID), - resolved->clone ()); - } - } - } - return resolved; - } - - virtual void visit (TupleType &) override {} - - virtual void visit (ADTType &) override {} - - virtual void visit (InferType &) override {} - - virtual void visit (FnType &) override {} - - virtual void visit (FnPtr &) override {} - - virtual void visit (ArrayType &) override {} - - virtual void visit (SliceType &) override {} - - virtual void visit (BoolType &) override {} - - virtual void visit (IntType &) override {} - - virtual void visit (UintType &) override {} - - virtual void visit (USizeType &) override {} - - virtual void visit (ISizeType &) override {} - - virtual void visit (FloatType &) override {} - - virtual void visit (ErrorType &) override {} - - virtual void visit (CharType &) override {} - - virtual void visit (ReferenceType &) override {} - - virtual void visit (PointerType &) override {} - - virtual void visit (ParamType &) override {} - - virtual void visit (StrType &) override {} - - virtual void visit (NeverType &) override {} - - virtual void visit (PlaceholderType &) override {} - - virtual void visit (ProjectionType &) override {} - - virtual void visit (DynamicObjectType &) override {} - - virtual void visit (ClosureType &) override {} - -protected: - BaseRules (BaseType *base) - : mappings (Analysis::Mappings::get ()), - context (Resolver::TypeCheckContext::get ()), - resolved (new ErrorType (base->get_ref (), base->get_ref ())) - {} - - Analysis::Mappings *mappings; - Resolver::TypeCheckContext *context; - - /* Temporary storage for the result of a unification. - We could return the result directly instead of storing it in the rule - object, but that involves modifying the visitor pattern to accommodate - the return value, which is too complex. */ - BaseType *resolved; - -private: - /* Returns a pointer to the ty that created this rule. */ - virtual BaseType *get_base () = 0; -}; - -class InferRules : public BaseRules -{ - using Rust::TyTy::BaseRules::visit; - -public: - InferRules (InferType *base) : BaseRules (base), base (base) {} - - void visit (BoolType &type) override - { - bool is_valid - = (base->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL); - if (is_valid) - { - resolved = type.clone (); - return; - } - - BaseRules::visit (type); - } - - void visit (IntType &type) override - { - bool is_valid - = (base->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL) - || (base->get_infer_kind () - == TyTy::InferType::InferTypeKind::INTEGRAL); - if (is_valid) - { - resolved = type.clone (); - return; - } - - BaseRules::visit (type); - } - - void visit (UintType &type) override - { - bool is_valid - = (base->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL) - || (base->get_infer_kind () - == TyTy::InferType::InferTypeKind::INTEGRAL); - if (is_valid) - { - resolved = type.clone (); - return; - } - - BaseRules::visit (type); - } - - void visit (USizeType &type) override - { - bool is_valid - = (base->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL) - || (base->get_infer_kind () - == TyTy::InferType::InferTypeKind::INTEGRAL); - if (is_valid) - { - resolved = type.clone (); - return; - } - - BaseRules::visit (type); - } - - void visit (ISizeType &type) override - { - bool is_valid - = (base->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL) - || (base->get_infer_kind () - == TyTy::InferType::InferTypeKind::INTEGRAL); - if (is_valid) - { - resolved = type.clone (); - return; - } - - BaseRules::visit (type); - } - - void visit (FloatType &type) override - { - bool is_valid - = (base->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL) - || (base->get_infer_kind () == TyTy::InferType::InferTypeKind::FLOAT); - if (is_valid) - { - resolved = type.clone (); - return; - } - - BaseRules::visit (type); - } - - void visit (ArrayType &type) override - { - bool is_valid - = (base->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL); - if (is_valid) - { - resolved = type.clone (); - return; - } - - BaseRules::visit (type); - } - - void visit (SliceType &type) override - { - bool is_valid - = (base->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL); - if (is_valid) - { - resolved = type.clone (); - return; - } - - BaseRules::visit (type); - } - - void visit (ADTType &type) override - { - bool is_valid - = (base->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL); - if (is_valid) - { - resolved = type.clone (); - return; - } - - BaseRules::visit (type); - } - - void visit (TupleType &type) override - { - bool is_valid - = (base->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL); - if (is_valid) - { - resolved = type.clone (); - return; - } - - BaseRules::visit (type); - } - - void visit (InferType &type) override - { - switch (base->get_infer_kind ()) - { - case InferType::InferTypeKind::GENERAL: - resolved = type.clone (); - return; - - case InferType::InferTypeKind::INTEGRAL: { - if (type.get_infer_kind () == InferType::InferTypeKind::INTEGRAL) - { - resolved = type.clone (); - return; - } - else if (type.get_infer_kind () == InferType::InferTypeKind::GENERAL) - { - resolved = base->clone (); - return; - } - } - break; - - case InferType::InferTypeKind::FLOAT: { - if (type.get_infer_kind () == InferType::InferTypeKind::FLOAT) - { - resolved = type.clone (); - return; - } - else if (type.get_infer_kind () == InferType::InferTypeKind::GENERAL) - { - resolved = base->clone (); - return; - } - } - break; - } - - BaseRules::visit (type); - } - - void visit (CharType &type) override - { - { - bool is_valid - = (base->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL); - if (is_valid) - { - resolved = type.clone (); - return; - } - - BaseRules::visit (type); - } - } - - void visit (ReferenceType &type) override - { - bool is_valid - = (base->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL); - if (is_valid) - { - resolved = type.clone (); - return; - } - - BaseRules::visit (type); - } - - void visit (PointerType &type) override - { - bool is_valid - = (base->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL); - if (is_valid) - { - resolved = type.clone (); - return; - } - - BaseRules::visit (type); - } - - void visit (ParamType &type) override - { - bool is_valid - = (base->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL); - if (is_valid) - { - resolved = type.clone (); - return; - } - - BaseRules::visit (type); - } - - void visit (DynamicObjectType &type) override - { - bool is_valid - = (base->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL); - if (is_valid) - { - resolved = type.clone (); - return; - } - - BaseRules::visit (type); - } - - void visit (ClosureType &type) override - { - bool is_valid - = (base->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL); - if (is_valid) - { - resolved = type.clone (); - return; - } - - BaseRules::visit (type); - } - -private: - BaseType *get_base () override { return base; } - - InferType *base; -}; - -class FnRules : public BaseRules -{ - using Rust::TyTy::BaseRules::visit; - -public: - FnRules (FnType *base) : BaseRules (base), base (base) {} - - void visit (InferType &type) override - { - if (type.get_infer_kind () != InferType::InferTypeKind::GENERAL) - { - BaseRules::visit (type); - return; - } - - resolved = base->clone (); - resolved->set_ref (type.get_ref ()); - } - - void visit (FnType &type) override - { - if (base->num_params () != type.num_params ()) - { - BaseRules::visit (type); - return; - } - - for (size_t i = 0; i < base->num_params (); i++) - { - auto a = base->param_at (i).second; - auto b = type.param_at (i).second; - - auto unified_param = a->unify (b); - if (unified_param == nullptr) - { - BaseRules::visit (type); - return; - } - } - - auto unified_return - = base->get_return_type ()->unify (type.get_return_type ()); - if (unified_return == nullptr) - { - BaseRules::visit (type); - return; - } - - resolved = base->clone (); - resolved->set_ref (type.get_ref ()); - } - -private: - BaseType *get_base () override { return base; } - - FnType *base; -}; - -class FnptrRules : public BaseRules -{ - using Rust::TyTy::BaseRules::visit; - -public: - FnptrRules (FnPtr *base) : BaseRules (base), base (base) {} - - void visit (InferType &type) override - { - if (type.get_infer_kind () != InferType::InferTypeKind::GENERAL) - { - BaseRules::visit (type); - return; - } - - resolved = base->clone (); - resolved->set_ref (type.get_ref ()); - } - - void visit (FnPtr &type) override - { - auto this_ret_type = base->get_return_type (); - auto other_ret_type = type.get_return_type (); - auto unified_result = this_ret_type->unify (other_ret_type); - if (unified_result == nullptr - || unified_result->get_kind () == TypeKind::ERROR) - { - BaseRules::visit (type); - return; - } - - if (base->num_params () != type.num_params ()) - { - BaseRules::visit (type); - return; - } - - for (size_t i = 0; i < base->num_params (); i++) - { - auto this_param = base->param_at (i); - auto other_param = type.param_at (i); - auto unified_param = this_param->unify (other_param); - if (unified_param == nullptr - || unified_param->get_kind () == TypeKind::ERROR) - { - BaseRules::visit (type); - return; - } - } - - resolved = base->clone (); - resolved->set_ref (type.get_ref ()); - } - - void visit (FnType &type) override - { - auto this_ret_type = base->get_return_type (); - auto other_ret_type = type.get_return_type (); - auto unified_result = this_ret_type->unify (other_ret_type); - if (unified_result == nullptr - || unified_result->get_kind () == TypeKind::ERROR) - { - BaseRules::visit (type); - return; - } - - if (base->num_params () != type.num_params ()) - { - BaseRules::visit (type); - return; - } - - for (size_t i = 0; i < base->num_params (); i++) - { - auto this_param = base->param_at (i); - auto other_param = type.param_at (i).second; - auto unified_param = this_param->unify (other_param); - if (unified_param == nullptr - || unified_param->get_kind () == TypeKind::ERROR) - { - BaseRules::visit (type); - return; - } - } - - resolved = base->clone (); - resolved->set_ref (type.get_ref ()); - } - -private: - BaseType *get_base () override { return base; } - - FnPtr *base; -}; - -class ClosureRules : public BaseRules -{ - using Rust::TyTy::BaseRules::visit; - -public: - ClosureRules (ClosureType *base) : BaseRules (base), base (base) {} - - void visit (InferType &type) override - { - if (type.get_infer_kind () != InferType::InferTypeKind::GENERAL) - { - BaseRules::visit (type); - return; - } - - resolved = base->clone (); - resolved->set_ref (type.get_ref ()); - } - - void visit (ClosureType &type) override - { - if (base->get_def_id () != type.get_def_id ()) - { - BaseRules::visit (type); - return; - } - - TyTy::BaseType *args_res - = base->get_parameters ().unify (&type.get_parameters ()); - if (args_res == nullptr || args_res->get_kind () == TypeKind::ERROR) - { - BaseRules::visit (type); - return; - } - - TyTy::BaseType *res - = base->get_result_type ().unify (&type.get_result_type ()); - if (res == nullptr || res->get_kind () == TypeKind::ERROR) - { - BaseRules::visit (type); - return; - } - - resolved = base->clone (); - resolved->set_ref (type.get_ref ()); - } - -private: - BaseType *get_base () override { return base; } - - ClosureType *base; -}; - -class ArrayRules : public BaseRules -{ - using Rust::TyTy::BaseRules::visit; - -public: - ArrayRules (ArrayType *base) : BaseRules (base), base (base) {} - - void visit (ArrayType &type) override - { - // check base type - auto base_resolved - = base->get_element_type ()->unify (type.get_element_type ()); - if (base_resolved == nullptr) - { - BaseRules::visit (type); - return; - } - - resolved - = new ArrayType (type.get_ref (), type.get_ty_ref (), - type.get_ident ().locus, type.get_capacity_expr (), - TyVar (base_resolved->get_ref ())); - } - - void visit (InferType &type) override - { - if (type.get_infer_kind () != InferType::InferTypeKind::GENERAL) - { - BaseRules::visit (type); - return; - } - - resolved = base->clone (); - resolved->set_ref (type.get_ref ()); - } - -private: - BaseType *get_base () override { return base; } - - ArrayType *base; -}; - -class SliceRules : public BaseRules -{ - using Rust::TyTy::BaseRules::visit; - -public: - SliceRules (SliceType *base) : BaseRules (base), base (base) {} - - void visit (SliceType &type) override - { - // check base type - auto base_resolved - = base->get_element_type ()->unify (type.get_element_type ()); - if (base_resolved == nullptr) - { - BaseRules::visit (type); - return; - } - - resolved = new SliceType (type.get_ref (), type.get_ty_ref (), - type.get_ident ().locus, - TyVar (base_resolved->get_ref ())); - } - - void visit (InferType &type) override - { - if (type.get_infer_kind () != InferType::InferTypeKind::GENERAL) - { - BaseRules::visit (type); - return; - } - - resolved = base->clone (); - resolved->set_ref (type.get_ref ()); - } - -private: - BaseType *get_base () override { return base; } - - SliceType *base; -}; - -class BoolRules : public BaseRules -{ - using Rust::TyTy::BaseRules::visit; - -public: - BoolRules (BoolType *base) : BaseRules (base), base (base) {} - - void visit (BoolType &type) override - { - resolved = new BoolType (type.get_ref (), type.get_ty_ref ()); - } - - void visit (InferType &type) override - { - switch (type.get_infer_kind ()) - { - case InferType::InferTypeKind::GENERAL: - resolved = base->clone (); - break; - - default: - BaseRules::visit (type); - break; - } - } - -private: - BaseType *get_base () override { return base; } - - BoolType *base; -}; - -class IntRules : public BaseRules -{ - using Rust::TyTy::BaseRules::visit; - -public: - IntRules (IntType *base) : BaseRules (base), base (base) {} - - void visit (InferType &type) override - { - // cant assign a float inference variable - if (type.get_infer_kind () == InferType::InferTypeKind::FLOAT) - { - BaseRules::visit (type); - return; - } - - resolved = base->clone (); - resolved->set_ref (type.get_ref ()); - } - - void visit (IntType &type) override - { - if (type.get_int_kind () != base->get_int_kind ()) - { - BaseRules::visit (type); - return; - } - - resolved - = new IntType (type.get_ref (), type.get_ty_ref (), type.get_int_kind ()); - } - -private: - BaseType *get_base () override { return base; } - - IntType *base; -}; - -class UintRules : public BaseRules -{ - using Rust::TyTy::BaseRules::visit; - -public: - UintRules (UintType *base) : BaseRules (base), base (base) {} - - void visit (InferType &type) override - { - // cant assign a float inference variable - if (type.get_infer_kind () == InferType::InferTypeKind::FLOAT) - { - BaseRules::visit (type); - return; - } - - resolved = base->clone (); - resolved->set_ref (type.get_ref ()); - } - - void visit (UintType &type) override - { - if (type.get_uint_kind () != base->get_uint_kind ()) - { - BaseRules::visit (type); - return; - } - - resolved = new UintType (type.get_ref (), type.get_ty_ref (), - type.get_uint_kind ()); - } - -private: - BaseType *get_base () override { return base; } - - UintType *base; -}; - -class FloatRules : public BaseRules -{ - using Rust::TyTy::BaseRules::visit; - -public: - FloatRules (FloatType *base) : BaseRules (base), base (base) {} - - void visit (InferType &type) override - { - if (type.get_infer_kind () == InferType::InferTypeKind::INTEGRAL) - { - BaseRules::visit (type); - return; - } - - resolved = base->clone (); - resolved->set_ref (type.get_ref ()); - } - - void visit (FloatType &type) override - { - if (type.get_float_kind () != base->get_float_kind ()) - { - BaseRules::visit (type); - return; - } - - resolved = new FloatType (type.get_ref (), type.get_ty_ref (), - type.get_float_kind ()); - } - -private: - BaseType *get_base () override { return base; } - - FloatType *base; -}; - -class ADTRules : public BaseRules -{ - using Rust::TyTy::BaseRules::visit; - -public: - ADTRules (ADTType *base) : BaseRules (base), base (base) {} - - void visit (ADTType &type) override - { - if (base->get_adt_kind () != type.get_adt_kind ()) - { - BaseRules::visit (type); - return; - } - - if (base->get_identifier ().compare (type.get_identifier ()) != 0) - { - BaseRules::visit (type); - return; - } - - if (base->number_of_variants () != type.number_of_variants ()) - { - BaseRules::visit (type); - return; - } - - for (size_t i = 0; i < type.number_of_variants (); ++i) - { - TyTy::VariantDef *a = base->get_variants ().at (i); - TyTy::VariantDef *b = type.get_variants ().at (i); - - if (a->num_fields () != b->num_fields ()) - { - BaseRules::visit (type); - return; - } - - 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 (); - - BaseType *unified_ty = this_field_ty->unify (other_field_ty); - if (unified_ty->get_kind () == TyTy::TypeKind::ERROR) - return; - } - } - - // generic args for the unit-struct case - if (type.is_unit () && base->is_unit ()) - { - rust_assert (type.get_num_substitutions () - == base->get_num_substitutions ()); - - for (size_t i = 0; i < type.get_num_substitutions (); i++) - { - auto &a = base->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 = pa->unify (pb); - if (res->get_kind () == TyTy::TypeKind::ERROR) - { - return; - } - } - } - - resolved = type.clone (); - } - - void visit (InferType &type) override - { - if (type.get_infer_kind () != InferType::InferTypeKind::GENERAL) - { - BaseRules::visit (type); - return; - } - - resolved = base->clone (); - resolved->set_ref (type.get_ref ()); - } - -private: - BaseType *get_base () override { return base; } - - ADTType *base; -}; - -class TupleRules : public BaseRules -{ - using Rust::TyTy::BaseRules::visit; - -public: - TupleRules (TupleType *base) : BaseRules (base), base (base) {} - - void visit (TupleType &type) override - { - if (base->num_fields () != type.num_fields ()) - { - BaseRules::visit (type); - return; - } - - std::vector fields; - for (size_t i = 0; i < base->num_fields (); i++) - { - BaseType *bo = base->get_field (i); - BaseType *fo = type.get_field (i); - - BaseType *unified_ty = bo->unify (fo); - if (unified_ty->get_kind () == TyTy::TypeKind::ERROR) - return; - - fields.push_back (TyVar (unified_ty->get_ref ())); - } - - resolved = new TyTy::TupleType (type.get_ref (), type.get_ty_ref (), - type.get_ident ().locus, fields); - } - - void visit (InferType &type) override - { - if (type.get_infer_kind () != InferType::InferTypeKind::GENERAL) - { - BaseRules::visit (type); - return; - } - - resolved = base->clone (); - resolved->set_ref (type.get_ref ()); - } - -private: - BaseType *get_base () override { return base; } - - TupleType *base; -}; - -class USizeRules : public BaseRules -{ - using Rust::TyTy::BaseRules::visit; - -public: - USizeRules (USizeType *base) : BaseRules (base), base (base) {} - - void visit (InferType &type) override - { - // cant assign a float inference variable - if (type.get_infer_kind () == InferType::InferTypeKind::FLOAT) - { - BaseRules::visit (type); - return; - } - - resolved = base->clone (); - resolved->set_ref (type.get_ref ()); - } - - void visit (USizeType &type) override { resolved = type.clone (); } - -private: - BaseType *get_base () override { return base; } - - USizeType *base; -}; - -class ISizeRules : public BaseRules -{ - using Rust::TyTy::BaseRules::visit; - -public: - ISizeRules (ISizeType *base) : BaseRules (base), base (base) {} - - void visit (InferType &type) override - { - // cant assign a float inference variable - if (type.get_infer_kind () == InferType::InferTypeKind::FLOAT) - { - BaseRules::visit (type); - return; - } - - resolved = base->clone (); - resolved->set_ref (type.get_ref ()); - } - - void visit (ISizeType &type) override { resolved = type.clone (); } - -private: - BaseType *get_base () override { return base; } - - ISizeType *base; -}; - -class CharRules : public BaseRules -{ - using Rust::TyTy::BaseRules::visit; - -public: - CharRules (CharType *base) : BaseRules (base), base (base) {} - - void visit (InferType &type) override - { - if (type.get_infer_kind () != InferType::InferTypeKind::GENERAL) - { - BaseRules::visit (type); - return; - } - - resolved = base->clone (); - resolved->set_ref (type.get_ref ()); - } - - void visit (CharType &type) override { resolved = type.clone (); } - -private: - BaseType *get_base () override { return base; } - - CharType *base; -}; - -class ReferenceRules : public BaseRules -{ - using Rust::TyTy::BaseRules::visit; - -public: - ReferenceRules (ReferenceType *base) : BaseRules (base), base (base) {} - - void visit (ReferenceType &type) override - { - auto base_type = base->get_base (); - auto other_base_type = type.get_base (); - - TyTy::BaseType *base_resolved = base_type->unify (other_base_type); - if (base_resolved == nullptr - || base_resolved->get_kind () == TypeKind::ERROR) - { - BaseRules::visit (type); - return; - } - - // rust is permissive about mutablity here you can always go from mutable to - // immutable but not the otherway round - bool mutability_ok = base->is_mutable () ? type.is_mutable () : true; - if (!mutability_ok) - { - BaseRules::visit (type); - return; - } - - resolved = new ReferenceType (base->get_ref (), base->get_ty_ref (), - TyVar (base_resolved->get_ref ()), - base->mutability ()); - } - - void visit (InferType &type) override - { - if (type.get_infer_kind () != InferType::InferTypeKind::GENERAL) - { - BaseRules::visit (type); - return; - } - - resolved = base->clone (); - resolved->set_ref (type.get_ref ()); - } - -private: - BaseType *get_base () override { return base; } - - ReferenceType *base; -}; - -class PointerRules : public BaseRules -{ - using Rust::TyTy::BaseRules::visit; - -public: - PointerRules (PointerType *base) : BaseRules (base), base (base) {} - - void visit (PointerType &type) override - { - auto base_type = base->get_base (); - auto other_base_type = type.get_base (); - - TyTy::BaseType *base_resolved = base_type->unify (other_base_type); - if (base_resolved == nullptr - || base_resolved->get_kind () == TypeKind::ERROR) - { - BaseRules::visit (type); - return; - } - - // rust is permissive about mutablity here you can always go from mutable to - // immutable but not the otherway round - bool mutability_ok = base->is_mutable () ? type.is_mutable () : true; - if (!mutability_ok) - { - BaseRules::visit (type); - return; - } - - resolved = new PointerType (base->get_ref (), base->get_ty_ref (), - TyVar (base_resolved->get_ref ()), - base->mutability ()); - } - - void visit (InferType &type) override - { - if (type.get_infer_kind () != InferType::InferTypeKind::GENERAL) - { - BaseRules::visit (type); - return; - } - - resolved = base->clone (); - resolved->set_ref (type.get_ref ()); - } - -private: - BaseType *get_base () override { return base; } - - PointerType *base; -}; - -class ParamRules : public BaseRules -{ - using Rust::TyTy::BaseRules::visit; - -public: - ParamRules (ParamType *base) : BaseRules (base), base (base) {} - - // param types are a placeholder we shouldn't have cases where we unify - // against it. eg: struct foo { a: T }; When we invoke it we can do either: - // - // foo{ a: 123 }. - // Then this enforces the i32 type to be referenced on the - // field via an hirid. - // - // rust also allows for a = foo{a:123}; Where we can use an Inference Variable - // to handle the typing of the struct - BaseType *unify (BaseType *other) override final - { - if (!base->can_resolve ()) - return BaseRules::unify (other); - - auto lookup = base->resolve (); - return lookup->unify (other); - } - - void visit (ParamType &type) override - { - if (base->get_symbol ().compare (type.get_symbol ()) != 0) - { - BaseRules::visit (type); - return; - } - - resolved = type.clone (); - } - - void visit (InferType &type) override - { - if (type.get_infer_kind () != InferType::InferTypeKind::GENERAL) - { - BaseRules::visit (type); - return; - } - - resolved = base->clone (); - } - -private: - BaseType *get_base () override { return base; } - - ParamType *base; -}; - -class StrRules : public BaseRules -{ - // FIXME we will need a enum for the StrType like ByteBuf etc.. - using Rust::TyTy::BaseRules::visit; - -public: - StrRules (StrType *base) : BaseRules (base), base (base) {} - - void visit (StrType &type) override { resolved = type.clone (); } - -private: - BaseType *get_base () override { return base; } - - StrType *base; -}; - -class NeverRules : public BaseRules -{ - using Rust::TyTy::BaseRules::visit; - -public: - NeverRules (NeverType *base) : BaseRules (base), base (base) {} - - void visit (NeverType &type) override { resolved = type.clone (); } - -private: - BaseType *get_base () override { return base; } - - NeverType *base; -}; - -class PlaceholderRules : public BaseRules -{ - using Rust::TyTy::BaseRules::visit; - -public: - PlaceholderRules (PlaceholderType *base) : BaseRules (base), base (base) {} - - BaseType *unify (BaseType *other) override final - { - if (!base->can_resolve ()) - return BaseRules::unify (other); - - BaseType *lookup = base->resolve (); - return lookup->unify (other); - } - - void visit (PlaceholderType &type) override - { - if (base->get_symbol ().compare (type.get_symbol ()) != 0) - { - BaseRules::visit (type); - return; - } - - resolved = type.clone (); - } - - void visit (InferType &type) override - { - if (type.get_infer_kind () != InferType::InferTypeKind::GENERAL) - { - BaseRules::visit (type); - return; - } - - resolved = base->clone (); - } - -private: - BaseType *get_base () override { return base; } - - PlaceholderType *base; -}; - -class DynamicRules : public BaseRules -{ - using Rust::TyTy::BaseRules::visit; - -public: - DynamicRules (DynamicObjectType *base) : BaseRules (base), base (base) {} - - void visit (InferType &type) override - { - if (type.get_infer_kind () != InferType::InferTypeKind::GENERAL) - { - BaseRules::visit (type); - return; - } - - resolved = base->clone (); - } - - void visit (DynamicObjectType &type) override - { - if (base->num_specified_bounds () != type.num_specified_bounds ()) - { - BaseRules::visit (type); - return; - } - - Location ref_locus = mappings->lookup_location (type.get_ref ()); - if (!base->bounds_compatible (type, ref_locus, true)) - { - BaseRules::visit (type); - return; - } - - resolved = base->clone (); - } - -private: - BaseType *get_base () override { return base; } - - DynamicObjectType *base; -}; - -} // namespace TyTy -} // namespace Rust - -#endif // RUST_TYTY_RULES diff --git a/gcc/rust/typecheck/rust-tyty.cc b/gcc/rust/typecheck/rust-tyty.cc index a3271eb0d1a..fe5aa2b059c 100644 --- a/gcc/rust/typecheck/rust-tyty.cc +++ b/gcc/rust/typecheck/rust-tyty.cc @@ -30,7 +30,6 @@ #include "rust-hir-trait-reference.h" #include "rust-hir-type-bounds.h" #include "rust-hir-trait-resolve.h" -#include "rust-tyty-rules.h" #include "rust-tyty-cmp.h" #include "options.h" @@ -376,6 +375,58 @@ BaseType::get_root () const return root; } +BaseType * +BaseType::destructure () +{ + int recurisve_ops = 0; + BaseType *x = this; + while (true) + { + if (recurisve_ops++ >= rust_max_recursion_depth) + { + rust_error_at ( + Location (), + "% count exceeds limit of %i (use " + "% to increase the limit)", + rust_max_recursion_depth); + return new ErrorType (get_ref ()); + } + + switch (x->get_kind ()) + { + case TyTy::TypeKind::PARAM: { + TyTy::ParamType *p = static_cast (x); + TyTy::BaseType *pr = p->resolve (); + if (pr == x) + return pr; + + x = pr; + } + break; + + case TyTy::TypeKind::PLACEHOLDER: { + TyTy::PlaceholderType *p = static_cast (x); + if (!p->can_resolve ()) + return p; + + x = p->resolve (); + } + break; + + case TyTy::TypeKind::PROJECTION: { + TyTy::ProjectionType *p = static_cast (x); + x = p->get (); + } + break; + + default: + return x; + } + } + + return x; +} + const BaseType * BaseType::destructure () const { @@ -397,14 +448,20 @@ BaseType::destructure () const { case TyTy::TypeKind::PARAM: { const TyTy::ParamType *p = static_cast (x); - x = p->resolve (); + const TyTy::BaseType *pr = p->resolve (); + if (pr == x) + return pr; + + x = pr; } break; case TyTy::TypeKind::PLACEHOLDER: { const TyTy::PlaceholderType *p = static_cast (x); - rust_assert (p->can_resolve ()); + if (!p->can_resolve ()) + return p; + x = p->resolve (); } break; @@ -512,13 +569,6 @@ InferType::as_string () const return ""; } -BaseType * -InferType::unify (BaseType *other) -{ - InferRules r (this); - return r.unify (other); -} - bool InferType::can_eq (const BaseType *other, bool emit_errors) const { @@ -637,12 +687,6 @@ ErrorType::as_string () const return ""; } -BaseType * -ErrorType::unify (BaseType *other) -{ - return this; -} - bool ErrorType::can_eq (const BaseType *other, bool emit_errors) const { @@ -1009,13 +1053,6 @@ ADTType::as_string () const return identifier + subst_as_string () + "{" + variants_buffer + "}"; } -BaseType * -ADTType::unify (BaseType *other) -{ - ADTRules r (this); - return r.unify (other); -} - bool ADTType::can_eq (const BaseType *other, bool emit_errors) const { @@ -1278,13 +1315,6 @@ TupleType::get_field (size_t index) const return fields.at (index).get_tyty (); } -BaseType * -TupleType::unify (BaseType *other) -{ - TupleRules r (this); - return r.unify (other); -} - bool TupleType::can_eq (const BaseType *other, bool emit_errors) const { @@ -1385,13 +1415,6 @@ FnType::as_string () const return "fn" + subst_as_string () + " (" + params_str + ") -> " + ret_str; } -BaseType * -FnType::unify (BaseType *other) -{ - FnRules r (this); - return r.unify (other); -} - bool FnType::can_eq (const BaseType *other, bool emit_errors) const { @@ -1616,13 +1639,6 @@ FnPtr::as_string () const return "fnptr (" + params_str + ") -> " + get_return_type ()->as_string (); } -BaseType * -FnPtr::unify (BaseType *other) -{ - FnptrRules r (this); - return r.unify (other); -} - bool FnPtr::can_eq (const BaseType *other, bool emit_errors) const { @@ -1696,13 +1712,6 @@ ClosureType::as_string () const return "|" + params_buf + "| {" + result_type.get_tyty ()->as_string () + "}"; } -BaseType * -ClosureType::unify (BaseType *other) -{ - ClosureRules r (this); - return r.unify (other); -} - bool ClosureType::can_eq (const BaseType *other, bool emit_errors) const { @@ -1812,13 +1821,6 @@ ArrayType::as_string () const return "[" + get_element_type ()->as_string () + ":" + "CAPACITY" + "]"; } -BaseType * -ArrayType::unify (BaseType *other) -{ - ArrayRules r (this); - return r.unify (other); -} - bool ArrayType::can_eq (const BaseType *other, bool emit_errors) const { @@ -1895,13 +1897,6 @@ SliceType::as_string () const return "[" + get_element_type ()->as_string () + "]"; } -BaseType * -SliceType::unify (BaseType *other) -{ - SliceRules r (this); - return r.unify (other); -} - bool SliceType::can_eq (const BaseType *other, bool emit_errors) const { @@ -2006,13 +2001,6 @@ BoolType::as_string () const return "bool"; } -BaseType * -BoolType::unify (BaseType *other) -{ - BoolRules r (this); - return r.unify (other); -} - bool BoolType::can_eq (const BaseType *other, bool emit_errors) const { @@ -2094,13 +2082,6 @@ IntType::as_string () const return "__unknown_int_type"; } -BaseType * -IntType::unify (BaseType *other) -{ - IntRules r (this); - return r.unify (other); -} - bool IntType::can_eq (const BaseType *other, bool emit_errors) const { @@ -2200,13 +2181,6 @@ UintType::as_string () const return "__unknown_uint_type"; } -BaseType * -UintType::unify (BaseType *other) -{ - UintRules r (this); - return r.unify (other); -} - bool UintType::can_eq (const BaseType *other, bool emit_errors) const { @@ -2306,13 +2280,6 @@ FloatType::as_string () const return "__unknown_float_type"; } -BaseType * -FloatType::unify (BaseType *other) -{ - FloatRules r (this); - return r.unify (other); -} - bool FloatType::can_eq (const BaseType *other, bool emit_errors) const { @@ -2389,13 +2356,6 @@ USizeType::as_string () const return "usize"; } -BaseType * -USizeType::unify (BaseType *other) -{ - USizeRules r (this); - return r.unify (other); -} - bool USizeType::can_eq (const BaseType *other, bool emit_errors) const { @@ -2461,13 +2421,6 @@ ISizeType::as_string () const return "isize"; } -BaseType * -ISizeType::unify (BaseType *other) -{ - ISizeRules r (this); - return r.unify (other); -} - bool ISizeType::can_eq (const BaseType *other, bool emit_errors) const { @@ -2533,13 +2486,6 @@ CharType::as_string () const return "char"; } -BaseType * -CharType::unify (BaseType *other) -{ - CharRules r (this); - return r.unify (other); -} - bool CharType::can_eq (const BaseType *other, bool emit_errors) const { @@ -2655,13 +2601,6 @@ ReferenceType::get_name () const + get_base ()->get_name (); } -BaseType * -ReferenceType::unify (BaseType *other) -{ - ReferenceRules r (this); - return r.unify (other); -} - bool ReferenceType::can_eq (const BaseType *other, bool emit_errors) const { @@ -2821,13 +2760,6 @@ PointerType::get_name () const + get_base ()->get_name (); } -BaseType * -PointerType::unify (BaseType *other) -{ - PointerRules r (this); - return r.unify (other); -} - bool PointerType::can_eq (const BaseType *other, bool emit_errors) const { @@ -2964,13 +2896,6 @@ ParamType::get_name () const return resolve ()->get_name (); } -BaseType * -ParamType::unify (BaseType *other) -{ - ParamRules r (this); - return r.unify (other); -} - bool ParamType::can_eq (const BaseType *other, bool emit_errors) const { @@ -3130,13 +3055,6 @@ StrType::as_string () const return "str"; } -BaseType * -StrType::unify (BaseType *other) -{ - StrRules r (this); - return r.unify (other); -} - bool StrType::can_eq (const BaseType *other, bool emit_errors) const { @@ -3202,13 +3120,6 @@ NeverType::as_string () const return "!"; } -BaseType * -NeverType::unify (BaseType *other) -{ - NeverRules r (this); - return r.unify (other); -} - bool NeverType::can_eq (const BaseType *other, bool emit_errors) const { @@ -3295,13 +3206,6 @@ PlaceholderType::as_string () const + ">"; } -BaseType * -PlaceholderType::unify (BaseType *other) -{ - PlaceholderRules r (this); - return r.unify (other); -} - bool PlaceholderType::can_eq (const BaseType *other, bool emit_errors) const { @@ -3465,12 +3369,6 @@ ProjectionType::as_string () const return "as_string () + ">"; } -BaseType * -ProjectionType::unify (BaseType *other) -{ - return base->unify (other); -} - bool ProjectionType::can_eq (const BaseType *other, bool emit_errors) const { @@ -3602,13 +3500,6 @@ DynamicObjectType::as_string () const return "dyn [" + raw_bounds_as_string () + "]"; } -BaseType * -DynamicObjectType::unify (BaseType *other) -{ - DynamicRules r (this); - return r.unify (other); -} - bool DynamicObjectType::can_eq (const BaseType *other, bool emit_errors) const { diff --git a/gcc/rust/typecheck/rust-tyty.h b/gcc/rust/typecheck/rust-tyty.h index 1cf7131c1cb..d2cf5b07fc1 100644 --- a/gcc/rust/typecheck/rust-tyty.h +++ b/gcc/rust/typecheck/rust-tyty.h @@ -105,11 +105,6 @@ public: virtual std::string get_name () const = 0; - // Unify two types. Returns a pointer to the newly-created unified ty, or - // nullptr if the two ty cannot be unified. The caller is responsible for - // releasing the memory of the returned ty. - virtual BaseType *unify (BaseType *other) = 0; - // similar to unify but does not actually perform type unification but // determines whether they are compatible. Consider the following // @@ -177,6 +172,7 @@ public: // This will get the monomorphized type from Params, Placeholders or // Projections if available or error + BaseType *destructure (); const BaseType *destructure () const; const RustIdent &get_ident () const; @@ -221,8 +217,6 @@ public: std::string as_string () const override; - BaseType *unify (BaseType *other) override; - bool can_eq (const BaseType *other, bool emit_errors) const override final; BaseType *clone () const final override; @@ -255,7 +249,6 @@ public: std::string as_string () const override; - BaseType *unify (BaseType *other) override; bool can_eq (const BaseType *other, bool emit_errors) const override final; BaseType *clone () const final override; @@ -284,7 +277,6 @@ public: std::string as_string () const override; - BaseType *unify (BaseType *other) override; bool can_eq (const BaseType *other, bool emit_errors) const override final; BaseType *clone () const final override; @@ -361,7 +353,6 @@ public: std::string as_string () const override; - BaseType *unify (BaseType *other) override; bool can_eq (const BaseType *other, bool emit_errors) const override final; bool is_equal (const BaseType &other) const override; @@ -598,7 +589,6 @@ public: std::string as_string () const override; - BaseType *unify (BaseType *other) override; bool can_eq (const BaseType *other, bool emit_errors) const override final; bool is_equal (const BaseType &other) const override; @@ -738,7 +728,6 @@ public: std::string get_identifier () const { return identifier; } - BaseType *unify (BaseType *other) override; bool can_eq (const BaseType *other, bool emit_errors) const override final; bool is_equal (const BaseType &other) const override; @@ -858,7 +847,6 @@ public: std::string as_string () const override; - BaseType *unify (BaseType *other) override; bool can_eq (const BaseType *other, bool emit_errors) const override final; bool is_equal (const BaseType &other) const override; @@ -938,7 +926,6 @@ public: std::string as_string () const override; std::string get_name () const override final { return as_string (); } - BaseType *unify (BaseType *other) override; bool can_eq (const BaseType *other, bool emit_errors) const override final; bool is_equal (const BaseType &other) const override; @@ -1007,7 +994,6 @@ public: std::string get_name () const override final { return as_string (); } - BaseType *unify (BaseType *other) override; bool can_eq (const BaseType *other, bool emit_errors) const override final; bool is_equal (const BaseType &other) const override; @@ -1055,7 +1041,6 @@ public: std::string get_name () const override final { return as_string (); } - BaseType *unify (BaseType *other) override; bool can_eq (const BaseType *other, bool emit_errors) const override final; bool is_equal (const BaseType &other) const override; @@ -1089,7 +1074,6 @@ public: std::string get_name () const override final; - BaseType *unify (BaseType *other) override; bool can_eq (const BaseType *other, bool emit_errors) const override final; BaseType *clone () const final override; @@ -1120,7 +1104,6 @@ public: std::string get_name () const override final; - BaseType *unify (BaseType *other) override; bool can_eq (const BaseType *other, bool emit_errors) const override final; IntKind get_int_kind () const; @@ -1159,7 +1142,6 @@ public: std::string get_name () const override final; - BaseType *unify (BaseType *other) override; bool can_eq (const BaseType *other, bool emit_errors) const override final; UintKind get_uint_kind () const; @@ -1194,7 +1176,6 @@ public: std::string as_string () const override; std::string get_name () const override final; - BaseType *unify (BaseType *other) override; bool can_eq (const BaseType *other, bool emit_errors) const override final; FloatKind get_float_kind () const; @@ -1222,7 +1203,6 @@ public: std::string as_string () const override; std::string get_name () const override final; - BaseType *unify (BaseType *other) override; bool can_eq (const BaseType *other, bool emit_errors) const override final; BaseType *clone () const final override; @@ -1243,7 +1223,6 @@ public: std::string as_string () const override; std::string get_name () const override final; - BaseType *unify (BaseType *other) override; bool can_eq (const BaseType *other, bool emit_errors) const override final; BaseType *clone () const final override; @@ -1263,7 +1242,6 @@ public: std::string as_string () const override; std::string get_name () const override final; - BaseType *unify (BaseType *other) override; bool can_eq (const BaseType *other, bool emit_errors) const override final; BaseType *clone () const final override; @@ -1284,7 +1262,6 @@ public: std::string as_string () const override; - BaseType *unify (BaseType *other) override; bool can_eq (const BaseType *other, bool emit_errors) const override final; bool is_equal (const BaseType &other) const override; @@ -1311,7 +1288,6 @@ public: std::string get_name () const override final; - BaseType *unify (BaseType *other) override; bool can_eq (const BaseType *other, bool emit_errors) const override final; bool is_equal (const BaseType &other) const override; @@ -1354,7 +1330,6 @@ public: std::string as_string () const override; std::string get_name () const override final; - BaseType *unify (BaseType *other) override; bool can_eq (const BaseType *other, bool emit_errors) const override final; bool is_equal (const BaseType &other) const override; @@ -1401,7 +1376,6 @@ public: std::string as_string () const override; - BaseType *unify (BaseType *other) override; bool can_eq (const BaseType *other, bool emit_errors) const override final; BaseType *clone () const final override; @@ -1428,7 +1402,6 @@ public: std::string as_string () const override; - BaseType *unify (BaseType *other) override; bool can_eq (const BaseType *other, bool emit_errors) const override final; BaseType *clone () const final override; @@ -1478,7 +1451,6 @@ public: std::string as_string () const override; - BaseType *unify (BaseType *other) override; bool can_eq (const BaseType *other, bool emit_errors) const override final; BaseType *clone () const final override; @@ -1524,7 +1496,6 @@ public: std::string as_string () const override; - BaseType *unify (BaseType *other) override; bool can_eq (const BaseType *other, bool emit_errors) const override final; bool is_equal (const BaseType &other) const override; diff --git a/gcc/rust/typecheck/rust-unify.cc b/gcc/rust/typecheck/rust-unify.cc new file mode 100644 index 00000000000..072f76133bc --- /dev/null +++ b/gcc/rust/typecheck/rust-unify.cc @@ -0,0 +1,1640 @@ +// 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 +// . + +#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 (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 ()); + + switch (ltype->get_kind ()) + { + case TyTy::INFER: + return expect_inference_variable (static_cast (ltype), + rtype); + + case TyTy::ADT: + return expect_adt (static_cast (ltype), rtype); + + case TyTy::STR: + return expect_str (static_cast (ltype), rtype); + + case TyTy::REF: + return expect_reference (static_cast (ltype), + rtype); + + case TyTy::POINTER: + return expect_pointer (static_cast (ltype), rtype); + + case TyTy::PARAM: + return expect_param (static_cast (ltype), rtype); + + case TyTy::ARRAY: + return expect_array (static_cast (ltype), rtype); + + case TyTy::SLICE: + return expect_slice (static_cast (ltype), rtype); + + case TyTy::FNDEF: + return expect_fndef (static_cast (ltype), rtype); + + case TyTy::FNPTR: + return expect_fnptr (static_cast (ltype), rtype); + + case TyTy::TUPLE: + return expect_tuple (static_cast (ltype), rtype); + + case TyTy::BOOL: + return expect_bool (static_cast (ltype), rtype); + + case TyTy::CHAR: + return expect_char (static_cast (ltype), rtype); + + case TyTy::INT: + return expect_int (static_cast (ltype), rtype); + + case TyTy::UINT: + return expect_uint (static_cast (ltype), rtype); + + case TyTy::FLOAT: + return expect_float (static_cast (ltype), rtype); + + case TyTy::USIZE: + return expect_usize (static_cast (ltype), rtype); + + case TyTy::ISIZE: + return expect_isize (static_cast (ltype), rtype); + + case TyTy::NEVER: + return expect_never (static_cast (ltype), rtype); + + case TyTy::PLACEHOLDER: + return expect_placeholder (static_cast (ltype), + rtype); + + case TyTy::PROJECTION: + return expect_projection (static_cast (ltype), + rtype); + + case TyTy::DYNAMIC: + return expect_dyn (static_cast (ltype), rtype); + + case TyTy::CLOSURE: + return expect_closure (static_cast (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (rtype); + if (ltype->num_fields () != type.num_fields ()) + { + return new TyTy::ErrorType (0); + } + + std::vector 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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (rtype); + if (ltype->get_def_id () != type.get_def_id ()) + { + return new TyTy::ErrorType (0); + } + + TyTy::BaseType *args_res + = UnifyRules::Resolve (TyTy::TyWithLocation ( + <ype->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 (<ype->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 diff --git a/gcc/rust/typecheck/rust-unify.h b/gcc/rust/typecheck/rust-unify.h new file mode 100644 index 00000000000..6e46b9642a6 --- /dev/null +++ b/gcc/rust/typecheck/rust-unify.h @@ -0,0 +1,91 @@ +// 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 +// . + +#ifndef RUST_UNIFY +#define RUST_UNIFY + +#include "rust-tyty-util.h" +#include "rust-hir-type-check.h" + +namespace Rust { +namespace Resolver { + +class UnifyRules +{ +public: + static TyTy::BaseType *Resolve (TyTy::TyWithLocation lhs, + TyTy::TyWithLocation rhs, Location locus, + bool commit_flag, bool emit_error); + +protected: + TyTy::BaseType *expect_inference_variable (TyTy::InferType *ltype, + TyTy::BaseType *rtype); + TyTy::BaseType *expect_adt (TyTy::ADTType *ltype, TyTy::BaseType *rtype); + TyTy::BaseType *expect_str (TyTy::StrType *ltype, TyTy::BaseType *rtype); + TyTy::BaseType *expect_reference (TyTy::ReferenceType *ltype, + TyTy::BaseType *rtype); + TyTy::BaseType *expect_pointer (TyTy::PointerType *ltype, + TyTy::BaseType *rtype); + TyTy::BaseType *expect_param (TyTy::ParamType *ltype, TyTy::BaseType *rtype); + TyTy::BaseType *expect_array (TyTy::ArrayType *ltype, TyTy::BaseType *rtype); + TyTy::BaseType *expect_slice (TyTy::SliceType *ltype, TyTy::BaseType *rtype); + TyTy::BaseType *expect_fndef (TyTy::FnType *ltype, TyTy::BaseType *rtype); + TyTy::BaseType *expect_fnptr (TyTy::FnPtr *ltype, TyTy::BaseType *rtype); + TyTy::BaseType *expect_tuple (TyTy::TupleType *ltype, TyTy::BaseType *rtype); + TyTy::BaseType *expect_bool (TyTy::BoolType *ltype, TyTy::BaseType *rtype); + TyTy::BaseType *expect_char (TyTy::CharType *ltype, TyTy::BaseType *rtype); + TyTy::BaseType *expect_int (TyTy::IntType *ltype, TyTy::BaseType *rtype); + TyTy::BaseType *expect_uint (TyTy::UintType *ltype, TyTy::BaseType *rtype); + TyTy::BaseType *expect_float (TyTy::FloatType *ltype, TyTy::BaseType *rtype); + TyTy::BaseType *expect_isize (TyTy::ISizeType *ltype, TyTy::BaseType *rtype); + TyTy::BaseType *expect_usize (TyTy::USizeType *ltype, TyTy::BaseType *rtype); + TyTy::BaseType *expect_never (TyTy::NeverType *ltype, TyTy::BaseType *rtype); + TyTy::BaseType *expect_placeholder (TyTy::PlaceholderType *ltype, + TyTy::BaseType *rtype); + TyTy::BaseType *expect_projection (TyTy::ProjectionType *ltype, + TyTy::BaseType *rtype); + TyTy::BaseType *expect_dyn (TyTy::DynamicObjectType *ltype, + TyTy::BaseType *rtype); + TyTy::BaseType *expect_closure (TyTy::ClosureType *ltype, + TyTy::BaseType *rtype); + +private: + UnifyRules (TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs, + Location locus, bool commit_flag, bool emit_error); + + void emit_type_mismatch () const; + void commit (TyTy::BaseType *resolved); + TyTy::BaseType *go (); + + TyTy::BaseType *get_base (); + TyTy::BaseType *get_other (); + + TyTy::TyWithLocation lhs; + TyTy::TyWithLocation rhs; + Location locus; + bool commit_flag; + bool emit_error; + + Analysis::Mappings &mappings; + TypeCheckContext &context; +}; + +} // namespace Resolver +} // namespace Rust + +#endif // RUST_UNIFY diff --git a/gcc/testsuite/rust/compile/never_type_err1.rs b/gcc/testsuite/rust/compile/never_type1.rs similarity index 52% rename from gcc/testsuite/rust/compile/never_type_err1.rs rename to gcc/testsuite/rust/compile/never_type1.rs index 52b1283fadf..8d56176fee3 100644 --- a/gcc/testsuite/rust/compile/never_type_err1.rs +++ b/gcc/testsuite/rust/compile/never_type1.rs @@ -1,8 +1,7 @@ fn test() { let a; - // FIXME: Unimplemented features - a = if true { // { dg-error "expected .T.. got .!." } + a = if true { return; } else { return;