source: src/ResolvExpr/Unify.cpp @ f5dbc8d

Last change on this file since f5dbc8d was b6f2e7ab, checked in by Andrew Beach <ajbeach@…>, 2 months ago

Removed SizeofExpr::expr and AlignofExpr::expr, expressions that would be stored there are wrapped in TypeofType? and stored in the type field. Some special cases to hide the typeof in code generation were added. In addition, initializer length is calculated in more cases so that the full type of more arrays is known sooner. Other than that, most of the code changes were just stripping out the conditional code and checks no longer needed. Some tests had to be updated, because the typeof is not hidden in dumps and the resolver replaces known typeof expressions with the type. The extension case caused some concern but it appears that just hides warnings in the expression which no longer exists.

  • Property mode set to 100644
File size: 22.3 KB
RevLine 
[a32b204]1//
2// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
3//
4// The contents of this file are covered under the licence agreement in the
5// file "LICENCE" distributed with Cforall.
6//
[c92bdcc]7// Unify.cpp --
[a32b204]8//
9// Author           : Richard C. Bilson
10// Created On       : Sun May 17 12:27:10 2015
[07de76b]11// Last Modified By : Peter A. Buhr
12// Last Modified On : Fri Dec 13 23:43:05 2019
13// Update Count     : 46
[a32b204]14//
[51b7345]15
[c92bdcc]16#include "Unify.hpp"
[f474e91]17
[d76c588]18#include <cassert>                  // for assertf, assert
19#include <iterator>                 // for back_insert_iterator, back_inserter
20#include <map>                      // for _Rb_tree_const_iterator, _Rb_tree_i...
21#include <memory>                   // for unique_ptr
22#include <set>                      // for set
23#include <string>                   // for string, operator==, operator!=, bas...
24#include <utility>                  // for pair, move
[54e41b3]25#include <vector>
[51b7345]26
[2890212]27#include "AST/Copy.hpp"
[f474e91]28#include "AST/Decl.hpp"
[54e41b3]29#include "AST/Node.hpp"
[f474e91]30#include "AST/Pass.hpp"
[2890212]31#include "AST/Print.hpp"
[54e41b3]32#include "AST/Type.hpp"
[d76c588]33#include "AST/TypeEnvironment.hpp"
[c92bdcc]34#include "Common/Eval.hpp"          // for eval
[5bf3976]35#include "CommonType.hpp"           // for commonType
[c92bdcc]36#include "FindOpenVars.hpp"         // for findOpenVars
[5bf3976]37#include "SpecCost.hpp"             // for SpecCost
[c92bdcc]38#include "Tuples/Tuples.hpp"        // for isTtype
39#include "Typeops.hpp"              // for flatten, occurs
[ea6332d]40
[f474e91]41namespace ast {
42        class SymbolTable;
43}
44
[1cbca6e]45// #define DEBUG
[51b7345]46
47namespace ResolvExpr {
48
[13de4478]49bool typesCompatible(
50                const ast::Type * first, const ast::Type * second,
51                const ast::TypeEnvironment & env ) {
52        ast::TypeEnvironment newEnv;
53        ast::OpenVarSet open, closed;
54        ast::AssertionSet need, have;
55
56        ast::ptr<ast::Type> newFirst( first ), newSecond( second );
57        env.apply( newFirst );
58        env.apply( newSecond );
59
60        // findOpenVars( newFirst, open, closed, need, have, FirstClosed );
61        findOpenVars( newSecond, open, closed, need, have, newEnv, FirstOpen );
62
63        return unifyExact(newFirst, newSecond, newEnv, need, have, open, noWiden() );
64}
65
66bool typesCompatibleIgnoreQualifiers(
67                const ast::Type * first, const ast::Type * second,
68                const ast::TypeEnvironment & env ) {
69        ast::TypeEnvironment newEnv;
70        ast::OpenVarSet open;
71        ast::AssertionSet need, have;
72
73        ast::Type * newFirst  = shallowCopy( first  );
74        ast::Type * newSecond = shallowCopy( second );
75
76        newFirst ->qualifiers = {};
77        newSecond->qualifiers = {};
78        ast::ptr< ast::Type > t1_(newFirst );
79        ast::ptr< ast::Type > t2_(newSecond);
80
81        ast::ptr< ast::Type > subFirst = env.apply(newFirst).node;
82        ast::ptr< ast::Type > subSecond = env.apply(newSecond).node;
83
84        return unifyExact(
85                subFirst,
86                subSecond,
87                newEnv, need, have, open, noWiden() );
88}
89
90namespace {
91        /// Replaces ttype variables with their bound types.
92        /// If this isn't done when satifying ttype assertions, then argument lists can have
93        /// different size and structure when they should be compatible.
94        struct TtypeExpander : public ast::WithShortCircuiting, public ast::PureVisitor {
95                ast::TypeEnvironment & tenv;
96
97                TtypeExpander( ast::TypeEnvironment & env ) : tenv( env ) {}
98
99                const ast::Type * postvisit( const ast::TypeInstType * typeInst ) {
100                        if ( const ast::EqvClass * clz = tenv.lookup( *typeInst ) ) {
101                                // expand ttype parameter into its actual type
102                                if ( clz->data.kind == ast::TypeDecl::Ttype && clz->bound ) {
103                                        return clz->bound;
[ef1da0e2]104                                }
105                        }
[13de4478]106                        return typeInst;
107                }
108        };
109}
[0bd46fd]110
[13de4478]111std::vector< ast::ptr< ast::Type > > flattenList(
112        const std::vector< ast::ptr< ast::Type > > & src, ast::TypeEnvironment & env
113) {
114        std::vector< ast::ptr< ast::Type > > dst;
115        dst.reserve( src.size() );
116        for ( const auto & d : src ) {
117                ast::Pass<TtypeExpander> expander( env );
118                // TtypeExpander pass is impure (may mutate nodes in place)
119                // need to make nodes shared to prevent accidental mutation
120                ast::ptr<ast::Type> dc = d->accept(expander);
121                auto types = flatten( dc );
122                for ( ast::ptr< ast::Type > & t : types ) {
123                        // outermost const, volatile, _Atomic qualifiers in parameters should not play
124                        // a role in the unification of function types, since they do not determine
125                        // whether a function is callable.
126                        // NOTE: **must** consider at least mutex qualifier, since functions can be
127                        // overloaded on outermost mutex and a mutex function has different
128                        // requirements than a non-mutex function
129                        remove_qualifiers( t, ast::CV::Const | ast::CV::Volatile | ast::CV::Atomic );
130                        dst.emplace_back( t );
[ef1da0e2]131                }
132        }
[13de4478]133        return dst;
134}
[ef1da0e2]135
[13de4478]136// Unification of Expressions
137//
138// Boolean outcome (obvious):  Are they basically spelled the same?
139// Side effect of binding variables (subtle):  if `sizeof(int)` ===_expr `sizeof(T)` then `int` ===_ty `T`
140//
141// Context:  if `float[VAREXPR1]` ===_ty `float[VAREXPR2]` then `VAREXPR1` ===_expr `VAREXPR2`
142// where the VAREXPR are meant as notational metavariables representing the fact that unification always
143// sees distinct ast::VariableExpr objects at these positions
[f02f546]144
[13de4478]145static bool unify( const ast::Expr * e1, const ast::Expr * e2, ast::TypeEnvironment & env,
146        ast::AssertionSet & need, ast::AssertionSet & have, const ast::OpenVarSet & open,
147        WidenMode widen );
[f02f546]148
[13de4478]149class UnifyExpr final : public ast::WithShortCircuiting {
150        const ast::Expr * e2;
151        ast::TypeEnvironment & tenv;
152        ast::AssertionSet & need;
153        ast::AssertionSet & have;
154        const ast::OpenVarSet & open;
155        WidenMode widen;
156public:
157        bool result;
[f02f546]158
[13de4478]159private:
[f02f546]160
[13de4478]161        void tryMatchOnStaticValue( const ast::Expr * e1 ) {
162                Evaluation r1 = eval(e1);
163                Evaluation r2 = eval(e2);
[f02f546]164
[13de4478]165                if ( !r1.hasKnownValue ) return;
166                if ( !r2.hasKnownValue ) return;
[f02f546]167
[13de4478]168                if ( r1.knownValue != r2.knownValue ) return;
[f02f546]169
[13de4478]170                visit_children = false;
171                result = true;
172        }
[f02f546]173
[13de4478]174public:
[f02f546]175
[13de4478]176        void previsit( const ast::Node * ) { assert(false); }
[f02f546]177
[13de4478]178        void previsit( const ast::Expr * e1 ) {
179                tryMatchOnStaticValue( e1 );
180                visit_children = false;
181        }
[f02f546]182
[13de4478]183        void previsit( const ast::CastExpr * e1 ) {
184                tryMatchOnStaticValue( e1 );
[f02f546]185
[13de4478]186                if ( result ) {
187                        assert( visit_children == false );
188                } else {
189                        assert( visit_children == true );
190                        visit_children = false;
[f02f546]191
[13de4478]192                        auto e2c = dynamic_cast< const ast::CastExpr * >( e2 );
193                        if ( !e2c ) return;
[f02f546]194
[13de4478]195                        // inspect casts' target types
196                        if ( !unifyExact(
197                                e1->result, e2c->result, tenv, need, have, open, widen ) ) return;
[f02f546]198
[13de4478]199                        // inspect casts' inner expressions
200                        result = unify( e1->arg, e2c->arg, tenv, need, have, open, widen );
[f02f546]201                }
[13de4478]202        }
[f02f546]203
[13de4478]204        void previsit( const ast::VariableExpr * e1 ) {
205                tryMatchOnStaticValue( e1 );
[f02f546]206
[13de4478]207                if ( result ) {
208                        assert( visit_children == false );
209                } else {
210                        assert( visit_children == true );
211                        visit_children = false;
[f02f546]212
[13de4478]213                        auto e2v = dynamic_cast< const ast::VariableExpr * >( e2 );
214                        if ( !e2v ) return;
[f02f546]215
[13de4478]216                        assert(e1->var);
217                        assert(e2v->var);
[f02f546]218
[13de4478]219                        // conservative: variable exprs match if their declarations are represented by the same C++ AST object
220                        result = (e1->var == e2v->var);
[f02f546]221                }
[13de4478]222        }
[f02f546]223
[13de4478]224        void previsit( const ast::SizeofExpr * e1 ) {
225                tryMatchOnStaticValue( e1 );
[f02f546]226
[13de4478]227                if ( result ) {
228                        assert( visit_children == false );
229                } else {
230                        assert( visit_children == true );
231                        visit_children = false;
[f02f546]232
[13de4478]233                        auto e2so = dynamic_cast< const ast::SizeofExpr * >( e2 );
234                        if ( !e2so ) return;
[f02f546]235
[13de4478]236                        // expression unification calls type unification (mutual recursion)
237                        result = unifyExact( e1->type, e2so->type, tenv, need, have, open, widen );
[f02f546]238                }
[13de4478]239        }
[f02f546]240
[13de4478]241        UnifyExpr( const ast::Expr * e2, ast::TypeEnvironment & env, ast::AssertionSet & need,
242                ast::AssertionSet & have, const ast::OpenVarSet & open, WidenMode widen )
243        : e2( e2 ), tenv(env), need(need), have(have), open(open), widen(widen), result(false) {}
244};
[f02f546]245
[13de4478]246static bool unify( const ast::Expr * e1, const ast::Expr * e2, ast::TypeEnvironment & env,
247        ast::AssertionSet & need, ast::AssertionSet & have, const ast::OpenVarSet & open,
248        WidenMode widen ) {
249        assert( e1 && e2 );
250        return ast::Pass<UnifyExpr>::read( e1, e2, env, need, have, open, widen );
251}
252
253class Unify final : public ast::WithShortCircuiting {
254        const ast::Type * type2;
255        ast::TypeEnvironment & tenv;
256        ast::AssertionSet & need;
257        ast::AssertionSet & have;
258        const ast::OpenVarSet & open;
259        WidenMode widen;
260public:
261        static size_t traceId;
262        bool result;
263
264        Unify(
265                const ast::Type * type2, ast::TypeEnvironment & env, ast::AssertionSet & need,
266                ast::AssertionSet & have, const ast::OpenVarSet & open, WidenMode widen )
267        : type2(type2), tenv(env), need(need), have(have), open(open), widen(widen),
268        result(false) {}
269
270        void previsit( const ast::Node * ) { visit_children = false; }
271
[822332e]272        void postvisit( const ast::VoidType * ) {
273                result = dynamic_cast< const ast::VoidType * >( type2 );
[f02f546]274        }
275
[13de4478]276        void postvisit( const ast::BasicType * basic ) {
277                if ( auto basic2 = dynamic_cast< const ast::BasicType * >( type2 ) ) {
278                        result = basic->kind == basic2->kind;
[f474e91]279                }
[13de4478]280        }
[f474e91]281
[13de4478]282        void postvisit( const ast::PointerType * pointer ) {
283                if ( auto pointer2 = dynamic_cast< const ast::PointerType * >( type2 ) ) {
284                        result = unifyExact(
285                                pointer->base, pointer2->base, tenv, need, have, open,
286                                noWiden());
[f474e91]287                }
[13de4478]288        }
[f474e91]289
[13de4478]290        void postvisit( const ast::ArrayType * array ) {
291                auto array2 = dynamic_cast< const ast::ArrayType * >( type2 );
292                if ( !array2 ) return;
[f474e91]293
[13de4478]294                if ( array->isVarLen != array2->isVarLen ) return;
295                if ( (array->dimension != nullptr) != (array2->dimension != nullptr) ) return;
[f474e91]296
[13de4478]297                if ( array->dimension ) {
298                        assert( array2->dimension );
299                        // type unification calls expression unification (mutual recursion)
300                        if ( !unify(array->dimension, array2->dimension,
301                                tenv, need, have, open, widen) ) return;
302                }
[f474e91]303
[13de4478]304                result = unifyExact(
[acb33f15]305                        array->base, array2->base, tenv, need, have, open, noWiden());
[13de4478]306        }
[f474e91]307
[13de4478]308        void postvisit( const ast::ReferenceType * ref ) {
309                if ( auto ref2 = dynamic_cast< const ast::ReferenceType * >( type2 ) ) {
[7870799]310                        result = unifyExact(
[13de4478]311                                ref->base, ref2->base, tenv, need, have, open, noWiden());
[f474e91]312                }
[13de4478]313        }
[f474e91]314
[13de4478]315private:
[f474e91]316
[13de4478]317        template< typename Iter >
318        static bool unifyTypeList(
319                Iter crnt1, Iter end1, Iter crnt2, Iter end2, ast::TypeEnvironment & env,
320                ast::AssertionSet & need, ast::AssertionSet & have, const ast::OpenVarSet & open
321        ) {
322                while ( crnt1 != end1 && crnt2 != end2 ) {
323                        const ast::Type * t1 = *crnt1;
324                        const ast::Type * t2 = *crnt2;
325                        bool isTuple1 = Tuples::isTtype( t1 );
326                        bool isTuple2 = Tuples::isTtype( t2 );
327
328                        // assumes here that ttype *must* be last parameter
329                        if ( isTuple1 && !isTuple2 ) {
330                                // combine remainder of list2, then unify
[7870799]331                                return unifyExact(
[954c954]332                                        t1, tupleFromTypes( crnt2, end2 ), env, need, have, open,
[251ce80]333                                        noWiden() );
[13de4478]334                        } else if ( !isTuple1 && isTuple2 ) {
335                                // combine remainder of list1, then unify
[7870799]336                                return unifyExact(
[954c954]337                                        tupleFromTypes( crnt1, end1 ), t2, env, need, have, open,
[251ce80]338                                        noWiden() );
[f474e91]339                        }
340
[13de4478]341                        if ( !unifyExact(
342                                t1, t2, env, need, have, open, noWiden() )
343                        ) return false;
344
345                        ++crnt1; ++crnt2;
[f474e91]346                }
347
[13de4478]348                // May get to the end of one argument list before the other. This is only okay if the
349                // other is a ttype
350                if ( crnt1 != end1 ) {
351                        // try unifying empty tuple with ttype
352                        const ast::Type * t1 = *crnt1;
353                        if ( !Tuples::isTtype( t1 ) ) return false;
354                        return unifyExact(
355                                t1, tupleFromTypes( crnt2, end2 ), env, need, have, open,
356                                noWiden() );
357                } else if ( crnt2 != end2 ) {
358                        // try unifying empty tuple with ttype
359                        const ast::Type * t2 = *crnt2;
360                        if ( !Tuples::isTtype( t2 ) ) return false;
361                        return unifyExact(
362                                tupleFromTypes( crnt1, end1 ), t2, env, need, have, open,
363                                noWiden() );
[f474e91]364                }
365
[13de4478]366                return true;
367        }
368
369        static bool unifyTypeList(
370                const std::vector< ast::ptr< ast::Type > > & list1,
371                const std::vector< ast::ptr< ast::Type > > & list2,
372                ast::TypeEnvironment & env, ast::AssertionSet & need, ast::AssertionSet & have,
373                const ast::OpenVarSet & open
374        ) {
375                return unifyTypeList(
376                        list1.begin(), list1.end(), list2.begin(), list2.end(), env, need, have, open);
377        }
378
379        static void markAssertionSet( ast::AssertionSet & assns, const ast::VariableExpr * assn ) {
380                auto i = assns.find( assn );
381                if ( i != assns.end() ) {
382                        i->second.isUsed = true;
[f474e91]383                }
[13de4478]384        }
[f474e91]385
[13de4478]386        /// mark all assertions in `type` used in both `assn1` and `assn2`
387        static void markAssertions(
388                ast::AssertionSet & assn1, ast::AssertionSet & assn2,
389                const ast::FunctionType * type
390        ) {
391                for ( auto & assert : type->assertions ) {
392                        markAssertionSet( assn1, assert );
393                        markAssertionSet( assn2, assert );
[f474e91]394                }
[13de4478]395        }
[f474e91]396
[13de4478]397public:
398        void postvisit( const ast::FunctionType * func ) {
399                auto func2 = dynamic_cast< const ast::FunctionType * >( type2 );
400                if ( !func2 ) return;
[f474e91]401
[13de4478]402                if ( func->isVarArgs != func2->isVarArgs ) return;
[7870799]403
[13de4478]404                // Flatten the parameter lists for both functions so that tuple structure does not
405                // affect unification. Does not actually mutate function parameters.
406                auto params = flattenList( func->params, tenv );
407                auto params2 = flattenList( func2->params, tenv );
[f474e91]408
[13de4478]409                // sizes don't have to match if ttypes are involved; need to be more precise w.r.t.
410                // where the ttype is to prevent errors
411                if (
412                        ( params.size() != params2.size() || func->returns.size() != func2->returns.size() )
413                        && !func->isTtype()
414                        && !func2->isTtype()
415                ) return;
[f474e91]416
[13de4478]417                if ( !unifyTypeList( params, params2, tenv, need, have, open ) ) return;
418                if ( !unifyTypeList(
419                        func->returns, func2->returns, tenv, need, have, open ) ) return;
[7870799]420
[13de4478]421                markAssertions( have, need, func );
422                markAssertions( have, need, func2 );
[f474e91]423
[13de4478]424                result = true;
425        }
[7870799]426
[13de4478]427private:
428        // Returns: other, cast as XInstType
429        // Assigns this->result: whether types are compatible (up to generic parameters)
430        template< typename XInstType >
431        const XInstType * handleRefType( const XInstType * inst, const ast::Type * other ) {
432                // check that the other type is compatible and named the same
433                auto otherInst = dynamic_cast< const XInstType * >( other );
434                if ( otherInst && inst->name == otherInst->name ) {
435                        this->result = otherInst;
436                }
437                return otherInst;
438        }
[f474e91]439
[13de4478]440        /// Creates a tuple type based on a list of TypeExpr
441        template< typename Iter >
442        static const ast::Type * tupleFromExprs(
443                const ast::TypeExpr * param, Iter & crnt, Iter end, ast::CV::Qualifiers qs
444        ) {
445                std::vector< ast::ptr< ast::Type > > types;
446                do {
447                        types.emplace_back( param->type );
[f474e91]448
[13de4478]449                        ++crnt;
450                        if ( crnt == end ) break;
451                        param = strict_dynamic_cast< const ast::TypeExpr * >( crnt->get() );
452                } while(true);
[f474e91]453
[13de4478]454                return new ast::TupleType( std::move(types), qs );
455        }
[f474e91]456
[13de4478]457        template< typename XInstType >
458        void handleGenericRefType( const XInstType * inst, const ast::Type * other ) {
459                // check that other type is compatible and named the same
460                const XInstType * otherInst = handleRefType( inst, other );
461                if ( !this->result ) return;
462
463                // check that parameters of types unify, if any
464                const std::vector< ast::ptr< ast::Expr > > & params = inst->params;
465                const std::vector< ast::ptr< ast::Expr > > & params2 = otherInst->params;
466
467                auto it = params.begin();
468                auto jt = params2.begin();
469                for ( ; it != params.end() && jt != params2.end(); ++it, ++jt ) {
470                        auto param = strict_dynamic_cast< const ast::TypeExpr * >( it->get() );
471                        auto param2 = strict_dynamic_cast< const ast::TypeExpr * >( jt->get() );
472
473                        ast::ptr< ast::Type > pty = param->type;
474                        ast::ptr< ast::Type > pty2 = param2->type;
475
476                        bool isTuple = Tuples::isTtype( pty );
477                        bool isTuple2 = Tuples::isTtype( pty2 );
478
479                        if ( isTuple && isTuple2 ) {
480                                ++it; ++jt;  // skip ttype parameters before break
481                        } else if ( isTuple ) {
482                                // bundle remaining params into tuple
483                                pty2 = tupleFromExprs( param2, jt, params2.end(), pty->qualifiers );
484                                ++it;  // skip ttype parameter for break
485                        } else if ( isTuple2 ) {
486                                // bundle remaining params into tuple
487                                pty = tupleFromExprs( param, it, params.end(), pty2->qualifiers );
488                                ++jt;  // skip ttype parameter for break
[f474e91]489                        }
490
[13de4478]491                        if ( !unifyExact(
492                                        pty, pty2, tenv, need, have, open, noWiden() ) ) {
493                                result = false;
494                                return;
495                        }
[f474e91]496
[13de4478]497                        // ttype parameter should be last
498                        if ( isTuple || isTuple2 ) break;
[f474e91]499                }
[13de4478]500                result = it == params.end() && jt == params2.end();
501        }
[f474e91]502
[13de4478]503public:
504        void postvisit( const ast::StructInstType * aggrType ) {
505                handleGenericRefType( aggrType, type2 );
506        }
[f474e91]507
[13de4478]508        void postvisit( const ast::UnionInstType * aggrType ) {
509                handleGenericRefType( aggrType, type2 );
510        }
[0522ebe]511
[13de4478]512        void postvisit( const ast::EnumInstType * aggrType ) {
513                handleRefType( aggrType, type2 );
514        }
[f474e91]515
[13de4478]516        void postvisit( const ast::TraitInstType * aggrType ) {
517                handleRefType( aggrType, type2 );
518        }
[f474e91]519
[13de4478]520        void postvisit( const ast::TypeInstType * typeInst ) {
521                // assert( open.find( *typeInst ) == open.end() );
522                auto otherInst = dynamic_cast< const ast::TypeInstType * >( type2 );
523                if ( otherInst && typeInst->name == otherInst->name ) {
524                        this->result = otherInst;
525                }
526        }
[f474e91]527
[13de4478]528private:
529        /// Creates a tuple type based on a list of Type
530        static bool unifyList(
531                const std::vector< ast::ptr< ast::Type > > & list1,
532                const std::vector< ast::ptr< ast::Type > > & list2, ast::TypeEnvironment & env,
533                ast::AssertionSet & need, ast::AssertionSet & have, const ast::OpenVarSet & open
534        ) {
535                auto crnt1 = list1.begin();
536                auto crnt2 = list2.begin();
537                while ( crnt1 != list1.end() && crnt2 != list2.end() ) {
538                        const ast::Type * t1 = *crnt1;
539                        const ast::Type * t2 = *crnt2;
540                        bool isTuple1 = Tuples::isTtype( t1 );
541                        bool isTuple2 = Tuples::isTtype( t2 );
542
543                        // assumes ttype must be last parameter
544                        if ( isTuple1 && !isTuple2 ) {
545                                // combine entirety of list2, then unify
[7870799]546                                return unifyExact(
[13de4478]547                                        t1, tupleFromTypes( list2 ), env, need, have, open,
548                                        noWiden() );
549                        } else if ( !isTuple1 && isTuple2 ) {
550                                // combine entirety of list1, then unify
[f474e91]551                                return unifyExact(
[13de4478]552                                        tupleFromTypes( list1 ), t2, env, need, have, open,
553                                        noWiden() );
[f474e91]554                        }
555
[13de4478]556                        if ( !unifyExact(
557                                t1, t2, env, need, have, open, noWiden() )
558                        ) return false;
[f474e91]559
[13de4478]560                        ++crnt1; ++crnt2;
561                }
[ef9988b]562
[13de4478]563                if ( crnt1 != list1.end() ) {
564                        // try unifying empty tuple type with ttype
565                        const ast::Type * t1 = *crnt1;
566                        if ( !Tuples::isTtype( t1 ) ) return false;
567                        // xxx - this doesn't generate an empty tuple, contrary to comment; both ported
568                        // from Rob's code
569                        return unifyExact(
570                                        t1, tupleFromTypes( list2 ), env, need, have, open,
571                                        noWiden() );
572                } else if ( crnt2 != list2.end() ) {
573                        // try unifying empty tuple with ttype
574                        const ast::Type * t2 = *crnt2;
575                        if ( !Tuples::isTtype( t2 ) ) return false;
576                        // xxx - this doesn't generate an empty tuple, contrary to comment; both ported
577                        // from Rob's code
578                        return unifyExact(
579                                        tupleFromTypes( list1 ), t2, env, need, have, open,
580                                        noWiden() );
581                }
[f474e91]582
[13de4478]583                return true;
584        }
[f474e91]585
[13de4478]586public:
587        void postvisit( const ast::TupleType * tuple ) {
588                auto tuple2 = dynamic_cast< const ast::TupleType * >( type2 );
589                if ( ! tuple2 ) return;
[f474e91]590
[13de4478]591                ast::Pass<TtypeExpander> expander{ tenv };
[f474e91]592
[13de4478]593                const ast::Type * flat = tuple->accept( expander );
594                const ast::Type * flat2 = tuple2->accept( expander );
[f474e91]595
[13de4478]596                auto types = flatten( flat );
597                auto types2 = flatten( flat2 );
[f474e91]598
[acb33f15]599                result = unifyList( types, types2, tenv, need, have, open );
[13de4478]600        }
[0bd3faf]601
[822332e]602        void postvisit( const ast::VarArgsType * ) {
[acb33f15]603                result = dynamic_cast< const ast::VarArgsType * >( type2 );
[2773ab8]604        }
605
[822332e]606        void postvisit( const ast::ZeroType * ) {
[acb33f15]607                result = dynamic_cast< const ast::ZeroType * >( type2 );
[ee574a2]608        }
609
[822332e]610        void postvisit( const ast::OneType * ) {
[acb33f15]611                result = dynamic_cast< const ast::OneType * >( type2 );
[f474e91]612        }
[13de4478]613};
[f474e91]614
[13de4478]615// size_t Unify::traceId = Stats::Heap::new_stacktrace_id("Unify");
616
617bool unify(
618                const ast::ptr<ast::Type> & type1, const ast::ptr<ast::Type> & type2,
619                ast::TypeEnvironment & env, ast::AssertionSet & need, ast::AssertionSet & have,
620                ast::OpenVarSet & open
621) {
622        ast::ptr<ast::Type> common;
623        return unify( type1, type2, env, need, have, open, common );
624}
625
626bool unify(
627                const ast::ptr<ast::Type> & type1, const ast::ptr<ast::Type> & type2,
628                ast::TypeEnvironment & env, ast::AssertionSet & need, ast::AssertionSet & have,
629                ast::OpenVarSet & open, ast::ptr<ast::Type> & common
630) {
631        ast::OpenVarSet closed;
632        // findOpenVars( type1, open, closed, need, have, FirstClosed );
633        findOpenVars( type2, open, closed, need, have, env, FirstOpen );
634        return unifyInexact(
635                type1, type2, env, need, have, open, WidenMode{ true, true }, common );
636}
637
638bool unifyExact(
639                const ast::Type * type1, const ast::Type * type2, ast::TypeEnvironment & env,
640                ast::AssertionSet & need, ast::AssertionSet & have, const ast::OpenVarSet & open,
641                WidenMode widen
642) {
643        if ( type1->qualifiers != type2->qualifiers ) return false;
644
645        auto var1 = dynamic_cast< const ast::TypeInstType * >( type1 );
646        auto var2 = dynamic_cast< const ast::TypeInstType * >( type2 );
647        bool isopen1 = var1 && env.lookup(*var1);
648        bool isopen2 = var2 && env.lookup(*var2);
649
650        if ( isopen1 && isopen2 ) {
651                if ( var1->base->kind != var2->base->kind ) return false;
652                return env.bindVarToVar(
653                        var1, var2, ast::TypeData{ var1->base->kind, var1->base->sized||var2->base->sized }, need, have,
654                        open, widen );
655        } else if ( isopen1 ) {
656                return env.bindVar( var1, type2, ast::TypeData{var1->base}, need, have, open, widen );
657        } else if ( isopen2 ) {
658                return env.bindVar( var2, type1, ast::TypeData{var2->base}, need, have, open, widen );
659        } else {
660                return ast::Pass<Unify>::read(
661                        type1, type2, env, need, have, open, widen );
662        }
663}
[f474e91]664
[13de4478]665bool unifyInexact(
666                const ast::ptr<ast::Type> & type1, const ast::ptr<ast::Type> & type2,
667                ast::TypeEnvironment & env, ast::AssertionSet & need, ast::AssertionSet & have,
668                const ast::OpenVarSet & open, WidenMode widen,
669                ast::ptr<ast::Type> & common
670) {
671        ast::CV::Qualifiers q1 = type1->qualifiers, q2 = type2->qualifiers;
672
673        // force t1 and t2 to be cloned if their qualifiers must be stripped, so that type1 and
674        // type2 are left unchanged; calling convention forces type{1,2}->strong_ref >= 1
675        ast::Type * t1 = shallowCopy(type1.get());
676        ast::Type * t2 = shallowCopy(type2.get());
677        t1->qualifiers = {};
678        t2->qualifiers = {};
679        ast::ptr< ast::Type > t1_(t1);
680        ast::ptr< ast::Type > t2_(t2);
681
682        if ( unifyExact( t1, t2, env, need, have, open, widen ) ) {
683                // if exact unification on unqualified types, try to merge qualifiers
684                if ( q1 == q2 || ( ( q1 > q2 || widen.first ) && ( q2 > q1 || widen.second ) ) ) {
685                        t1->qualifiers = q1 | q2;
686                        common = t1;
[f474e91]687                        return true;
688                } else {
689                        return false;
690                }
[13de4478]691        } else if (( common = commonType( t1, t2, env, need, have, open, widen ))) {
692                // no exact unification, but common type
693                auto c = shallowCopy(common.get());
694                c->qualifiers = q1 | q2;
695                common = c;
696                return true;
697        } else {
698                return false;
[f474e91]699        }
[13de4478]700}
[f474e91]701
[13de4478]702ast::ptr<ast::Type> extractResultType( const ast::FunctionType * func ) {
703        if ( func->returns.empty() ) return new ast::VoidType();
704        if ( func->returns.size() == 1 ) return func->returns[0];
[4139e3d]705
[13de4478]706        std::vector<ast::ptr<ast::Type>> tys;
707        for ( const auto & decl : func->returns ) {
708                tys.emplace_back( decl );
[54e41b3]709        }
[13de4478]710        return new ast::TupleType( std::move(tys) );
711}
712
[51b7345]713} // namespace ResolvExpr
[a32b204]714
715// Local Variables: //
716// tab-width: 4 //
717// mode: c++ //
718// compile-command: "make install" //
719// End: //
Note: See TracBrowser for help on using the repository browser.