Changeset a065f1f for src


Ignore:
Timestamp:
Sep 20, 2022, 8:37:17 PM (3 years ago)
Author:
JiadaL <j82liang@…>
Branches:
ADT, ast-experimental, master, pthread-emulation
Children:
53a768d
Parents:
4520b77e (diff), ef1da0e2 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge branch 'master' of plg.uwaterloo.ca:software/cfa/cfa-cc

Location:
src
Files:
2 added
13 edited

Legend:

Unmodified
Added
Removed
  • src/AST/Print.cpp

    r4520b77e ra065f1f  
    9090
    9191                static constexpr auto Qualifiers = make_array<const char*>(
    92                         "const", "restrict", "volatile", "lvalue", "mutex", "_Atomic"
     92                        "const", "restrict", "volatile", "mutex", "_Atomic"
    9393                );
    9494        };
     
    16351635constexpr array<const char*, 3> Printer::Names::FuncSpecifiers;
    16361636constexpr array<const char*, 6> Printer::Names::StorageClasses;
    1637 constexpr array<const char*, 6> Printer::Names::Qualifiers;
     1637constexpr array<const char*, 5> Printer::Names::Qualifiers;
    16381638}
  • src/AST/Type.hpp

    r4520b77e ra065f1f  
    412412                std::string typeString() const { return std::string("_") + std::to_string(formal_usage) + "_" + std::to_string(expr_id) + "_" + base->name; }
    413413                bool operator==(const TypeEnvKey & other) const { return base == other.base && formal_usage == other.formal_usage && expr_id == other.expr_id; }
    414 
    415414        };
    416415
  • src/AST/TypeEnvironment.hpp

    r4520b77e ra065f1f  
    5656struct AssertCompare {
    5757        bool operator()( const VariableExpr * d1, const VariableExpr * d2 ) const {
     58                auto kind1 = ast::SymbolTable::getSpecialFunctionKind(d1->var->name);
     59                auto kind2 = ast::SymbolTable::getSpecialFunctionKind(d2->var->name);
     60                // heuristics optimization: force special functions to go last
     61                if (kind1 > kind2) return true;
     62                else if (kind1 < kind2) return false;
     63
    5864                int cmp = d1->var->name.compare( d2->var->name );
    5965                return cmp < 0 || ( cmp == 0 && d1->result < d2->result );
  • src/AST/module.mk

    r4520b77e ra065f1f  
    2424        AST/Copy.cpp \
    2525        AST/Copy.hpp \
     26        AST/Create.cpp \
     27        AST/Create.hpp \
    2628        AST/CVQualifiers.hpp \
    2729        AST/Decl.cpp \
  • src/CodeGen/CodeGenerator.cc

    r4520b77e ra065f1f  
    494494                                        assert( false );
    495495                                } // switch
     496                        } else if( varExpr->get_var()->get_linkage() == LinkageSpec::BuiltinCFA && varExpr->get_var()->get_name() == "intptr" ) {
     497                                // THIS is a hack to make it a constant until a proper constexpr solution is created
     498                                output << "((void*)";
     499                                std::list< Expression* >::iterator arg = applicationExpr->get_args().begin();
     500                                (*arg++)->accept( *visitor );
     501                                output << ")";
    496502                        } else {
    497503                                varExpr->accept( *visitor );
  • src/Concurrency/Waitfor.cc

    r4520b77e ra065f1f  
    402402
    403403                clause.target.function = nullptr;
    404                 clause.target.arguments.empty();
     404                clause.target.arguments.clear();
    405405                clause.condition = nullptr;
    406406        }
  • src/GenPoly/InstantiateGenericNew.cpp

    r4520b77e ra065f1f  
    2222
    2323#include "AST/Copy.hpp"                // for deepCopy
     24#include "AST/Create.hpp"              // for asForward
    2425#include "AST/Pass.hpp"                // for Pass, WithGuard, WithShortCi...
    2526#include "AST/TranslationUnit.hpp"     // for TranslationUnit
     
    255256void stripInstParams( ast::BaseInstType * inst ) {
    256257        inst->params.clear();
    257 }
    258 
    259 // TODO: I think this should become a generic helper.
    260 template<typename Aggr>
    261 Aggr * asForward( Aggr const * decl ) {
    262         if ( !decl->body ) {
    263                 return nullptr;
    264         }
    265         Aggr * mut = ast::deepCopy( decl );
    266         mut->body = false;
    267         mut->members.clear();
    268         return mut;
    269258}
    270259
     
    553542                        // Forward declare before recursion. (TODO: Only when needed, #199.)
    554543                        insert( inst, typeSubs, newDecl );
    555                         if ( AggrDecl const * forwardDecl = asForward( newDecl ) ) {
     544                        if ( AggrDecl const * forwardDecl = ast::asForward( newDecl ) ) {
    556545                                declsToAddBefore.push_back( forwardDecl );
    557546                        }
  • src/GenPoly/Lvalue2.cc

    r4520b77e ra065f1f  
    2323}
    2424
    25 
    2625}
  • src/ResolvExpr/CommonType.cc

    r4520b77e ra065f1f  
    2828#include "Unify.h"                       // for unifyExact, WidenMode
    2929#include "typeops.h"                     // for isFtype
     30#include "Tuples/Tuples.h"
    3031
    3132// #define DEBUG
     
    675676                ast::TypeEnvironment & tenv;
    676677                const ast::OpenVarSet & open;
     678                ast::AssertionSet & need;
     679                ast::AssertionSet & have;
    677680        public:
    678681                static size_t traceId;
     
    681684                CommonType_new(
    682685                        const ast::Type * t2, WidenMode w, const ast::SymbolTable & st,
    683                         ast::TypeEnvironment & env, const ast::OpenVarSet & o )
    684                 : type2( t2 ), widen( w ), symtab( st ), tenv( env ), open( o ), result() {}
     686                        ast::TypeEnvironment & env, const ast::OpenVarSet & o,
     687                        ast::AssertionSet & need, ast::AssertionSet & have )
     688                : type2( t2 ), widen( w ), symtab( st ), tenv( env ), open( o ), need (need), have (have) ,result() {}
    685689
    686690                void previsit( const ast::Node * ) { visit_children = false; }
     
    753757                bool tryResolveWithTypedEnum( const ast::Type * type1 ) {
    754758                        if (auto enumInst = dynamic_cast<const ast::EnumInstType *> (type2) ) {
    755                                 ast::AssertionSet have, need; // unused
    756759                                ast::OpenVarSet newOpen{ open };
    757760                                if (enumInst->base->base
     
    792795                                        reset_qualifiers( t2 );
    793796
    794                                         ast::AssertionSet have, need;
    795797                                        ast::OpenVarSet newOpen{ open };
    796798                                        if ( unifyExact( t1, t2, tenv, have, need, newOpen, noWiden(), symtab ) ) {
     
    803805                                                }
    804806                                        }
     807                                        else if ( isFtype (t1) && isFtype (t2) ) {
     808                                                auto f1 = t1.as<ast::FunctionType>();
     809                                                if (!f1) return;
     810                                                auto f2 = t2.strict_as<ast::FunctionType>();
     811
     812                                                assertf(f1->returns.size() <= 1, "Function return should not be a list");
     813                                                assertf(f2->returns.size() <= 1, "Function return should not be a list");
     814
     815                                                if (
     816                                                        ( f1->params.size() != f2->params.size() || f1->returns.size() != f2->returns.size() )
     817                                                        && ! f1->isTtype()
     818                                                        && ! f2->isTtype()
     819                                                ) return;
     820
     821                                                auto params1 = flattenList( f1->params, tenv );
     822                                                auto params2 = flattenList( f2->params, tenv );
     823
     824                                                auto crnt1 = params1.begin();
     825                                                auto crnt2 = params2.begin();
     826                                                auto end1 = params1.end();
     827                                                auto end2 = params2.end();
     828
     829                                                while (crnt1 != end1 && crnt2 != end2 ) {
     830                                                        const ast::Type * arg1 = *crnt1;
     831                                                        const ast::Type * arg2 = *crnt2;
     832
     833                                                        bool isTuple1 = Tuples::isTtype( t1 );
     834                                                        bool isTuple2 = Tuples::isTtype( t2 );
     835
     836                                                        // assumes here that ttype *must* be last parameter
     837                                                        if ( isTuple1 && ! isTuple2 ) {
     838                                                                // combine remainder of list2, then unify
     839                                                                if (unifyExact(
     840                                                                        arg1, tupleFromTypes( crnt2, end2 ), tenv, need, have, open,
     841                                                                        noWiden(), symtab )) {
     842                                                                                break;
     843
     844                                                                }
     845                                                                else return;
     846                                                        } else if ( ! isTuple1 && isTuple2 ) {
     847                                                                // combine remainder of list1, then unify
     848                                                                if (unifyExact(
     849                                                                        tupleFromTypes( crnt1, end1 ), arg2, tenv, need, have, open,
     850                                                                        noWiden(), symtab )) {
     851                                                                                break;
     852
     853                                                                }
     854                                                                else return;
     855                                                        }
     856
     857                                                        // allow qualifiers of pointer and reference base to become more specific
     858                                                        if (auto ref1 = dynamic_cast<const ast::ReferenceType *> (arg1)) {
     859                                                                if (auto ref2 = dynamic_cast<const ast::ReferenceType *> (arg2)) {
     860                                                                        ast::ptr<ast::Type> base1 = ref1->base;
     861                                                                        ast::ptr<ast::Type> base2 = ref2->base;
     862
     863                                                                        // xxx - assume LHS is always the target type
     864
     865                                                                        if ( ! ((widen.second && ref2->qualifiers.is_mutex)
     866                                                                        || (ref1->qualifiers.is_mutex == ref2->qualifiers.is_mutex ))) return;
     867
     868                                                                        if ( (widen.second && base1->qualifiers <= base2->qualifiers ) || (base2->qualifiers == base1->qualifiers) ) {
     869
     870                                                                                reset_qualifiers(base1);
     871                                                                                reset_qualifiers(base2);
     872
     873                                                                                if ( ! unifyExact(
     874                                                                                        base1, base2, tenv, need, have, open, noWiden(), symtab )
     875                                                                                ) return;
     876                                                                        }       
     877                                                                }
     878                                                                else return;
     879                                                        }
     880                                                        else if (auto ptr1 = dynamic_cast<const ast::PointerType *> (arg1)) {
     881                                                                if (auto ptr2 = dynamic_cast<const ast::PointerType *> (arg2)) {
     882                                                                        ast::ptr<ast::Type> base1 = ptr1->base;
     883                                                                        ast::ptr<ast::Type> base2 = ptr2->base;
     884
     885                                                                        // xxx - assume LHS is always the target type
     886                                                                        // a function accepting const can always be called by non-const arg
     887
     888                                                                        if ( (widen.second && base1->qualifiers <= base2->qualifiers ) || (base2->qualifiers == base1->qualifiers) ) {
     889
     890                                                                                reset_qualifiers(base1);
     891                                                                                reset_qualifiers(base2);
     892
     893                                                                                if ( ! unifyExact(
     894                                                                                        base1, base2, tenv, need, have, open, noWiden(), symtab )
     895                                                                                ) return;
     896                                                                        }       
     897                                                                }
     898                                                                else return;
     899
     900                                                        }
     901                                                        else if (! unifyExact(
     902                                                                arg1, arg2, tenv, need, have, open, noWiden(), symtab )) return;
     903
     904                                                        ++crnt1; ++crnt2;
     905                                                }
     906                                                if ( crnt1 != end1 ) {
     907                                                        // try unifying empty tuple with ttype
     908                                                        const ast::Type * t1 = *crnt1;
     909                                                        if (! Tuples::isTtype( t1 ) ) return;
     910                                                        if (! unifyExact(
     911                                                                t1, tupleFromTypes( crnt2, end2 ), tenv, need, have, open,
     912                                                                noWiden(), symtab )) return;
     913                                                } else if ( crnt2 != end2 ) {
     914                                                        // try unifying empty tuple with ttype
     915                                                        const ast::Type * t2 = *crnt2;
     916                                                        if (! Tuples::isTtype( t2 ) ) return;
     917                                                        if (! unifyExact(
     918                                                                tupleFromTypes( crnt1, end1 ), t2, tenv, need, have, open,
     919                                                                noWiden(), symtab )) return;
     920                                                }
     921                                                if ((f1->returns.size() == 0 && f2->returns.size() == 0)
     922                                                  || (f1->returns.size() == 1 && f2->returns.size() == 1 && unifyExact(f1->returns[0], f2->returns[0], tenv, need, have, open, noWiden(), symtab))) {
     923                                                        result = pointer;
     924
     925                                                        for (auto & assn : f1->assertions) {
     926                                                                auto i = need.find(assn);
     927                                                                if (i != need.end()) i->second.isUsed = true;
     928                                                                auto j = have.find(assn);
     929                                                                if (j != have.end()) j->second.isUsed = true;
     930                                                        }
     931
     932                                                        for (auto & assn : f2->assertions) {
     933                                                                auto i = need.find(assn);
     934                                                                if (i != need.end()) i->second.isUsed = true;
     935                                                                auto j = have.find(assn);
     936                                                                if (j != have.end()) j->second.isUsed = true;
     937                                                        }
     938
     939                                                }
     940                                        } // if ftype
     941                                       
    805942                                }
    806943                        } else if ( widen.second && dynamic_cast< const ast::ZeroType * >( type2 ) ) {
     
    839976                                        reset_qualifiers( t2 );
    840977
    841                                         ast::AssertionSet have, need;
    842978                                        ast::OpenVarSet newOpen{ open };
    843979                                        if ( unifyExact( t1, t2, tenv, have, need, newOpen, noWiden(), symtab ) ) {
     
    857993                                // xxx - does unifying a ref with typed enumInst makes sense?
    858994                                if (!dynamic_cast<const ast::EnumInstType *>(type2))
    859                                         result = commonType( type2, ref, widen, symtab, tenv, open );
     995                                        result = commonType( type2, ref, tenv, need, have, open, widen, symtab );
    860996                        }
    861997                }
     
    8771013                        // xxx - is this already handled by unify?
    8781014                        if (!dynamic_cast<const ast::EnumInstType *>(type2))
    879                                 result = commonType( type2, enumInst, widen, symtab, tenv, open );
     1015                                result = commonType( type2, enumInst, tenv, need, have, open, widen, symtab);
    8801016                }
    8811017
     
    8951031                                        reset_qualifiers( t2 );
    8961032
    897                                         ast::AssertionSet have, need;
    8981033                                        ast::OpenVarSet newOpen{ open };
    8991034                                        if ( unifyExact( t1, t2, tenv, have, need, newOpen, noWiden(), symtab ) ) {
     
    9991134        ast::ptr< ast::Type > commonType(
    10001135                        const ast::ptr< ast::Type > & type1, const ast::ptr< ast::Type > & type2,
    1001                         WidenMode widen, const ast::SymbolTable & symtab, ast::TypeEnvironment & env,
    1002                         const ast::OpenVarSet & open
     1136                        ast::TypeEnvironment & env, ast::AssertionSet & need, ast::AssertionSet & have,
     1137                        const ast::OpenVarSet & open, WidenMode widen, const ast::SymbolTable & symtab
    10031138        ) {
    10041139                unsigned depth1 = type1->referenceDepth();
     
    10361171                }
    10371172                // otherwise both are reference types of the same depth and this is handled by the visitor
    1038                 ast::Pass<CommonType_new> visitor{ type2, widen, symtab, env, open };
     1173                ast::Pass<CommonType_new> visitor{ type2, widen, symtab, env, open, need, have };
    10391174                type1->accept( visitor );
    10401175                ast::ptr< ast::Type > result = visitor.core.result;
     
    10471182                                        if ( type->base ) {
    10481183                                                ast::CV::Qualifiers q1 = type1->qualifiers, q2 = type2->qualifiers;
    1049                                                 ast::AssertionSet have, need;
    10501184                                                ast::OpenVarSet newOpen{ open };
    10511185
  • src/ResolvExpr/ConversionCost.cc

    r4520b77e ra065f1f  
    2222#include "ResolvExpr/Cost.h"             // for Cost
    2323#include "ResolvExpr/TypeEnvironment.h"  // for EqvClass, TypeEnvironment
     24#include "ResolvExpr/Unify.h"
    2425#include "SymTab/Indexer.h"              // for Indexer
    2526#include "SynTree/Declaration.h"         // for TypeDecl, NamedTypeDecl
    2627#include "SynTree/Type.h"                // for Type, BasicType, TypeInstType
    2728#include "typeops.h"                     // for typesCompatibleIgnoreQualifiers
     29
    2830
    2931namespace ResolvExpr {
     
    657659                                cost = Cost::safe;
    658660                        }
    659                 } else {
     661                }
     662                /*
     663                else if ( const ast::FunctionType * dstFunc = dstAsPtr->base.as<ast::FunctionType>()) {
     664                        if (const ast::FunctionType * srcFunc = pointerType->base.as<ast::FunctionType>()) {
     665                                if (dstFunc->params.empty() && dstFunc->isVarArgs ) {
     666                                        cost = Cost::unsafe; // assign any function to variadic fptr
     667                                }
     668                        }
     669                        else {
     670                                ast::AssertionSet need, have; // unused
     671                                ast::OpenVarSet open;
     672                                env.extractOpenVars(open);
     673                                ast::TypeEnvironment tenv = env;
     674                                if ( unify(dstAsPtr->base, pointerType->base, tenv, need, have, open, symtab) ) {
     675                                        cost = Cost::safe;
     676                                }
     677                        }
     678                        // else infinity
     679                }
     680                */
     681                else {
    660682                        int assignResult = ptrsAssignable( pointerType->base, dstAsPtr->base, env );
    661683                        if ( 0 < assignResult && tq1 <= tq2 ) {
  • src/ResolvExpr/SatisfyAssertions.cpp

    r4520b77e ra065f1f  
    3636#include "AST/SymbolTable.hpp"
    3737#include "AST/TypeEnvironment.hpp"
     38#include "FindOpenVars.h"
    3839#include "Common/FilterCombos.h"
    3940#include "Common/Indenter.h"
     
    161162
    162163        /// Satisfy a single assertion
    163         bool satisfyAssertion( ast::AssertionList::value_type & assn, SatState & sat ) {
     164        bool satisfyAssertion( ast::AssertionList::value_type & assn, SatState & sat, bool allowConversion = false, bool skipUnbound = false) {
    164165                // skip unused assertions
    165166                if ( ! assn.second.isUsed ) return true;
     
    180181                        if (thisArgType.as<ast::PointerType>()) otypeKey = Mangle::Encoding::pointer;
    181182                        else if (!isUnboundType(thisArgType)) otypeKey = Mangle::mangle(thisArgType, Mangle::Type | Mangle::NoGenericParams);
     183                        else if (skipUnbound) return false;
    182184
    183185                        candidates = sat.symtab.specialLookupId(kind, otypeKey);
     
    205207
    206208                        // only keep candidates which unify
    207                         if ( unify( toType, adjType, newEnv, newNeed, have, newOpen, sat.symtab ) ) {
    208                                 // set up binding slot for recursive assertions
    209                                 ast::UniqueId crntResnSlot = 0;
    210                                 if ( ! newNeed.empty() ) {
    211                                         crntResnSlot = ++globalResnSlot;
    212                                         for ( auto & a : newNeed ) { a.second.resnSlot = crntResnSlot; }
    213                                 }
    214 
    215                                 matches.emplace_back(
    216                                         cdata, adjType, std::move( newEnv ), std::move( have ), std::move( newNeed ),
    217                                         std::move( newOpen ), crntResnSlot );
     209
     210                        ast::OpenVarSet closed;
     211                        findOpenVars( toType, newOpen, closed, newNeed, have, FirstClosed );
     212                        findOpenVars( adjType, newOpen, closed, newNeed, have, FirstOpen );
     213                        if ( allowConversion ) {
     214                                if ( auto c = commonType( toType, adjType, newEnv, newNeed, have, newOpen, WidenMode {true, true}, sat.symtab ) ) {
     215                                        // set up binding slot for recursive assertions
     216                                        ast::UniqueId crntResnSlot = 0;
     217                                        if ( ! newNeed.empty() ) {
     218                                                crntResnSlot = ++globalResnSlot;
     219                                                for ( auto & a : newNeed ) { a.second.resnSlot = crntResnSlot; }
     220                                        }
     221
     222                                        matches.emplace_back(
     223                                                cdata, adjType, std::move( newEnv ), std::move( have ), std::move( newNeed ),
     224                                                std::move( newOpen ), crntResnSlot );
     225                                }
     226                        }
     227                        else {
     228                                if ( unifyExact( toType, adjType, newEnv, newNeed, have, newOpen, WidenMode {true, true}, sat.symtab ) ) {
     229                                        // set up binding slot for recursive assertions
     230                                        ast::UniqueId crntResnSlot = 0;
     231                                        if ( ! newNeed.empty() ) {
     232                                                crntResnSlot = ++globalResnSlot;
     233                                                for ( auto & a : newNeed ) { a.second.resnSlot = crntResnSlot; }
     234                                        }
     235
     236                                        matches.emplace_back(
     237                                                cdata, adjType, std::move( newEnv ), std::move( have ), std::move( newNeed ),
     238                                                std::move( newOpen ), crntResnSlot );
     239                                }
    218240                        }
    219241                }
     
    413435                // for each current mutually-compatible set of assertions
    414436                for ( SatState & sat : sats ) {
     437                        bool allowConversion = false;
    415438                        // stop this branch if a better option is already found
    416439                        auto it = thresholds.find( pruneKey( *sat.cand ) );
     
    418441
    419442                        // should a limit be imposed? worst case here is O(n^2) but very unlikely to happen.
     443
    420444                        for (unsigned resetCount = 0; ; ++resetCount) {
    421445                                ast::AssertionList next;
     
    424448                                for ( auto & assn : sat.need ) {
    425449                                        // fail early if any assertion is not satisfiable
    426                                         if ( ! satisfyAssertion( assn, sat ) ) {
     450                                        if ( ! satisfyAssertion( assn, sat, allowConversion, !next.empty() ) ) {
    427451                                                next.emplace_back(assn);
    428452                                                // goto nextSat;
     
    433457                                // fail if nothing resolves
    434458                                else if (next.size() == sat.need.size()) {
    435                                         Indenter tabs{ 3 };
    436                                         std::ostringstream ss;
    437                                         ss << tabs << "Unsatisfiable alternative:\n";
    438                                         print( ss, *sat.cand, ++tabs );
    439                                         ss << (tabs-1) << "Could not satisfy assertion:\n";
    440                                         ast::print( ss, next[0].first, tabs );
    441 
    442                                         errors.emplace_back( ss.str() );
    443                                         goto nextSat;
    444                                 }
     459                                        if (allowConversion) {
     460                                                Indenter tabs{ 3 };
     461                                                std::ostringstream ss;
     462                                                ss << tabs << "Unsatisfiable alternative:\n";
     463                                                print( ss, *sat.cand, ++tabs );
     464                                                ss << (tabs-1) << "Could not satisfy assertion:\n";
     465                                                ast::print( ss, next[0].first, tabs );
     466
     467                                                errors.emplace_back( ss.str() );
     468                                                goto nextSat;
     469                                        }
     470
     471                                        else {
     472                                                allowConversion = true;
     473                                                continue;
     474                                        }
     475                                }
     476                                allowConversion = false;
    445477                                sat.need = std::move(next);
    446478                        }
  • src/ResolvExpr/Unify.cc

    r4520b77e ra065f1f  
    707707        }
    708708
     709        namespace {
     710                                /// Replaces ttype variables with their bound types.
     711                /// If this isn't done when satifying ttype assertions, then argument lists can have
     712                /// different size and structure when they should be compatible.
     713                struct TtypeExpander_new : public ast::WithShortCircuiting, public ast::PureVisitor {
     714                        ast::TypeEnvironment & tenv;
     715
     716                        TtypeExpander_new( ast::TypeEnvironment & env ) : tenv( env ) {}
     717
     718                        const ast::Type * postvisit( const ast::TypeInstType * typeInst ) {
     719                                if ( const ast::EqvClass * clz = tenv.lookup( *typeInst ) ) {
     720                                        // expand ttype parameter into its actual type
     721                                        if ( clz->data.kind == ast::TypeDecl::Ttype && clz->bound ) {
     722                                                return clz->bound;
     723                                        }
     724                                }
     725                                return typeInst;
     726                        }
     727                };
     728        }
     729       
     730        std::vector< ast::ptr< ast::Type > > flattenList(
     731                const std::vector< ast::ptr< ast::Type > > & src, ast::TypeEnvironment & env
     732        ) {
     733                std::vector< ast::ptr< ast::Type > > dst;
     734                dst.reserve( src.size() );
     735                for ( const auto & d : src ) {
     736                        ast::Pass<TtypeExpander_new> expander{ env };
     737                        // TtypeExpander pass is impure (may mutate nodes in place)
     738                        // need to make nodes shared to prevent accidental mutation
     739                        ast::ptr<ast::Type> dc = d->accept(expander);
     740                        auto types = flatten( dc );
     741                        for ( ast::ptr< ast::Type > & t : types ) {
     742                                // outermost const, volatile, _Atomic qualifiers in parameters should not play
     743                                // a role in the unification of function types, since they do not determine
     744                                // whether a function is callable.
     745                                // NOTE: **must** consider at least mutex qualifier, since functions can be
     746                                // overloaded on outermost mutex and a mutex function has different
     747                                // requirements than a non-mutex function
     748                                remove_qualifiers( t, ast::CV::Const | ast::CV::Volatile | ast::CV::Atomic );
     749                                dst.emplace_back( t );
     750                        }
     751                }
     752                return dst;
     753        }
     754
    709755        class Unify_new final : public ast::WithShortCircuiting {
    710756                const ast::Type * type2;
     
    778824
    779825        private:
    780                 /// Replaces ttype variables with their bound types.
    781                 /// If this isn't done when satifying ttype assertions, then argument lists can have
    782                 /// different size and structure when they should be compatible.
    783                 struct TtypeExpander_new : public ast::WithShortCircuiting, public ast::PureVisitor {
    784                         ast::TypeEnvironment & tenv;
    785 
    786                         TtypeExpander_new( ast::TypeEnvironment & env ) : tenv( env ) {}
    787 
    788                         const ast::Type * postvisit( const ast::TypeInstType * typeInst ) {
    789                                 if ( const ast::EqvClass * clz = tenv.lookup( *typeInst ) ) {
    790                                         // expand ttype parameter into its actual type
    791                                         if ( clz->data.kind == ast::TypeDecl::Ttype && clz->bound ) {
    792                                                 return clz->bound;
    793                                         }
    794                                 }
    795                                 return typeInst;
    796                         }
    797                 };
    798 
    799                 /// returns flattened version of `src`
    800                 static std::vector< ast::ptr< ast::Type > > flattenList(
    801                         const std::vector< ast::ptr< ast::Type > > & src, ast::TypeEnvironment & env
    802                 ) {
    803                         std::vector< ast::ptr< ast::Type > > dst;
    804                         dst.reserve( src.size() );
    805                         for ( const auto & d : src ) {
    806                                 ast::Pass<TtypeExpander_new> expander{ env };
    807                                 // TtypeExpander pass is impure (may mutate nodes in place)
    808                                 // need to make nodes shared to prevent accidental mutation
    809                                 ast::ptr<ast::Type> dc = d->accept(expander);
    810                                 auto types = flatten( dc );
    811                                 for ( ast::ptr< ast::Type > & t : types ) {
    812                                         // outermost const, volatile, _Atomic qualifiers in parameters should not play
    813                                         // a role in the unification of function types, since they do not determine
    814                                         // whether a function is callable.
    815                                         // NOTE: **must** consider at least mutex qualifier, since functions can be
    816                                         // overloaded on outermost mutex and a mutex function has different
    817                                         // requirements than a non-mutex function
    818                                         remove_qualifiers( t, ast::CV::Const | ast::CV::Volatile | ast::CV::Atomic );
    819                                         dst.emplace_back( t );
    820                                 }
    821                         }
    822                         return dst;
    823                 }
    824 
    825                 /// Creates a tuple type based on a list of DeclWithType
    826                 template< typename Iter >
    827                 static const ast::Type * tupleFromTypes( Iter crnt, Iter end ) {
    828                         std::vector< ast::ptr< ast::Type > > types;
    829                         while ( crnt != end ) {
    830                                 // it is guaranteed that a ttype variable will be bound to a flat tuple, so ensure
    831                                 // that this results in a flat tuple
    832                                 flatten( *crnt, types );
    833 
    834                                 ++crnt;
    835                         }
    836 
    837                         return new ast::TupleType{ std::move(types) };
    838                 }
    839826
    840827                template< typename Iter >
     
    10481035        private:
    10491036                /// Creates a tuple type based on a list of Type
    1050                 static const ast::Type * tupleFromTypes(
    1051                         const std::vector< ast::ptr< ast::Type > > & tys
    1052                 ) {
    1053                         std::vector< ast::ptr< ast::Type > > out;
    1054                         for ( const ast::Type * ty : tys ) {
    1055                                 // it is guaranteed that a ttype variable will be bound to a flat tuple, so ensure
    1056                                 // that this results in a flat tuple
    1057                                 flatten( ty, out );
    1058                         }
    1059 
    1060                         return new ast::TupleType{ std::move(out) };
    1061                 }
     1037               
    10621038
    10631039                static bool unifyList(
     
    12311207                        }
    12321208
    1233                 } else if (( common = commonType( t1, t2, widen, symtab, env, open ) )) {
     1209                } else if ( common = commonType( t1, t2, env, need, have, open, widen, symtab )) {
    12341210                        // no exact unification, but common type
    12351211                        auto c = shallowCopy(common.get());
  • src/ResolvExpr/typeops.h

    r4520b77e ra065f1f  
    138138        Type * commonType( Type * type1, Type * type2, bool widenFirst, bool widenSecond, const SymTab::Indexer & indexer, TypeEnvironment & env, const OpenVarSet & openVars );
    139139        ast::ptr< ast::Type > commonType(
    140                 const ast::ptr< ast::Type > & type1, const ast::ptr< ast::Type > & type2, WidenMode widen,
    141                 const ast::SymbolTable & symtab, ast::TypeEnvironment & env, const ast::OpenVarSet & open );
     140                const ast::ptr< ast::Type > & type1, const ast::ptr< ast::Type > & type2,
     141                        ast::TypeEnvironment & env, ast::AssertionSet & need, ast::AssertionSet & have,
     142                        const ast::OpenVarSet & open, WidenMode widen, const ast::SymbolTable & symtab
     143        );
     144        // in Unify.cc
     145        std::vector< ast::ptr< ast::Type > > flattenList(
     146                const std::vector< ast::ptr< ast::Type > > & src, ast::TypeEnvironment & env
     147        );
    142148
    143149        // in PolyCost.cc
     
    181187
    182188        /// flatten tuple type into existing list of types
    183         static inline void flatten(
     189        inline void flatten(
    184190                const ast::Type * type, std::vector< ast::ptr< ast::Type > > & out
    185191        ) {
     
    194200
    195201        /// flatten tuple type into list of types
    196         static inline std::vector< ast::ptr< ast::Type > > flatten( const ast::Type * type ) {
     202        inline std::vector< ast::ptr< ast::Type > > flatten( const ast::Type * type ) {
    197203                std::vector< ast::ptr< ast::Type > > out;
    198204                out.reserve( type->size() );
     
    200206                return out;
    201207        }
     208
     209        template< typename Iter >
     210        const ast::Type * tupleFromTypes( Iter crnt, Iter end ) {
     211                std::vector< ast::ptr< ast::Type > > types;
     212                while ( crnt != end ) {
     213                        // it is guaranteed that a ttype variable will be bound to a flat tuple, so ensure
     214                        // that this results in a flat tuple
     215                        flatten( *crnt, types );
     216
     217                        ++crnt;
     218                }
     219
     220
     221                return new ast::TupleType{ std::move(types) };
     222        }
     223
     224        inline const ast::Type * tupleFromTypes(
     225                const std::vector< ast::ptr< ast::Type > > & tys
     226        ) {
     227                return tupleFromTypes( tys.begin(), tys.end() );
     228        }
     229
     230       
    202231
    203232        // in TypeEnvironment.cc
Note: See TracChangeset for help on using the changeset viewer.