source: src/ResolvExpr/Unify.cpp@ c01a2fd

Last change on this file since c01a2fd was b6f2e7ab, checked in by Andrew Beach <ajbeach@…>, 13 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
Line 
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//
7// Unify.cpp --
8//
9// Author : Richard C. Bilson
10// Created On : Sun May 17 12:27:10 2015
11// Last Modified By : Peter A. Buhr
12// Last Modified On : Fri Dec 13 23:43:05 2019
13// Update Count : 46
14//
15
16#include "Unify.hpp"
17
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
25#include <vector>
26
27#include "AST/Copy.hpp"
28#include "AST/Decl.hpp"
29#include "AST/Node.hpp"
30#include "AST/Pass.hpp"
31#include "AST/Print.hpp"
32#include "AST/Type.hpp"
33#include "AST/TypeEnvironment.hpp"
34#include "Common/Eval.hpp" // for eval
35#include "CommonType.hpp" // for commonType
36#include "FindOpenVars.hpp" // for findOpenVars
37#include "SpecCost.hpp" // for SpecCost
38#include "Tuples/Tuples.hpp" // for isTtype
39#include "Typeops.hpp" // for flatten, occurs
40
41namespace ast {
42 class SymbolTable;
43}
44
45// #define DEBUG
46
47namespace ResolvExpr {
48
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;
104 }
105 }
106 return typeInst;
107 }
108 };
109}
110
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 );
131 }
132 }
133 return dst;
134}
135
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
144
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 );
148
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;
158
159private:
160
161 void tryMatchOnStaticValue( const ast::Expr * e1 ) {
162 Evaluation r1 = eval(e1);
163 Evaluation r2 = eval(e2);
164
165 if ( !r1.hasKnownValue ) return;
166 if ( !r2.hasKnownValue ) return;
167
168 if ( r1.knownValue != r2.knownValue ) return;
169
170 visit_children = false;
171 result = true;
172 }
173
174public:
175
176 void previsit( const ast::Node * ) { assert(false); }
177
178 void previsit( const ast::Expr * e1 ) {
179 tryMatchOnStaticValue( e1 );
180 visit_children = false;
181 }
182
183 void previsit( const ast::CastExpr * e1 ) {
184 tryMatchOnStaticValue( e1 );
185
186 if ( result ) {
187 assert( visit_children == false );
188 } else {
189 assert( visit_children == true );
190 visit_children = false;
191
192 auto e2c = dynamic_cast< const ast::CastExpr * >( e2 );
193 if ( !e2c ) return;
194
195 // inspect casts' target types
196 if ( !unifyExact(
197 e1->result, e2c->result, tenv, need, have, open, widen ) ) return;
198
199 // inspect casts' inner expressions
200 result = unify( e1->arg, e2c->arg, tenv, need, have, open, widen );
201 }
202 }
203
204 void previsit( const ast::VariableExpr * e1 ) {
205 tryMatchOnStaticValue( e1 );
206
207 if ( result ) {
208 assert( visit_children == false );
209 } else {
210 assert( visit_children == true );
211 visit_children = false;
212
213 auto e2v = dynamic_cast< const ast::VariableExpr * >( e2 );
214 if ( !e2v ) return;
215
216 assert(e1->var);
217 assert(e2v->var);
218
219 // conservative: variable exprs match if their declarations are represented by the same C++ AST object
220 result = (e1->var == e2v->var);
221 }
222 }
223
224 void previsit( const ast::SizeofExpr * e1 ) {
225 tryMatchOnStaticValue( e1 );
226
227 if ( result ) {
228 assert( visit_children == false );
229 } else {
230 assert( visit_children == true );
231 visit_children = false;
232
233 auto e2so = dynamic_cast< const ast::SizeofExpr * >( e2 );
234 if ( !e2so ) return;
235
236 // expression unification calls type unification (mutual recursion)
237 result = unifyExact( e1->type, e2so->type, tenv, need, have, open, widen );
238 }
239 }
240
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};
245
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
272 void postvisit( const ast::VoidType * ) {
273 result = dynamic_cast< const ast::VoidType * >( type2 );
274 }
275
276 void postvisit( const ast::BasicType * basic ) {
277 if ( auto basic2 = dynamic_cast< const ast::BasicType * >( type2 ) ) {
278 result = basic->kind == basic2->kind;
279 }
280 }
281
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());
287 }
288 }
289
290 void postvisit( const ast::ArrayType * array ) {
291 auto array2 = dynamic_cast< const ast::ArrayType * >( type2 );
292 if ( !array2 ) return;
293
294 if ( array->isVarLen != array2->isVarLen ) return;
295 if ( (array->dimension != nullptr) != (array2->dimension != nullptr) ) return;
296
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 }
303
304 result = unifyExact(
305 array->base, array2->base, tenv, need, have, open, noWiden());
306 }
307
308 void postvisit( const ast::ReferenceType * ref ) {
309 if ( auto ref2 = dynamic_cast< const ast::ReferenceType * >( type2 ) ) {
310 result = unifyExact(
311 ref->base, ref2->base, tenv, need, have, open, noWiden());
312 }
313 }
314
315private:
316
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
331 return unifyExact(
332 t1, tupleFromTypes( crnt2, end2 ), env, need, have, open,
333 noWiden() );
334 } else if ( !isTuple1 && isTuple2 ) {
335 // combine remainder of list1, then unify
336 return unifyExact(
337 tupleFromTypes( crnt1, end1 ), t2, env, need, have, open,
338 noWiden() );
339 }
340
341 if ( !unifyExact(
342 t1, t2, env, need, have, open, noWiden() )
343 ) return false;
344
345 ++crnt1; ++crnt2;
346 }
347
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() );
364 }
365
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;
383 }
384 }
385
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 );
394 }
395 }
396
397public:
398 void postvisit( const ast::FunctionType * func ) {
399 auto func2 = dynamic_cast< const ast::FunctionType * >( type2 );
400 if ( !func2 ) return;
401
402 if ( func->isVarArgs != func2->isVarArgs ) return;
403
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 );
408
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;
416
417 if ( !unifyTypeList( params, params2, tenv, need, have, open ) ) return;
418 if ( !unifyTypeList(
419 func->returns, func2->returns, tenv, need, have, open ) ) return;
420
421 markAssertions( have, need, func );
422 markAssertions( have, need, func2 );
423
424 result = true;
425 }
426
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 }
439
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 );
448
449 ++crnt;
450 if ( crnt == end ) break;
451 param = strict_dynamic_cast< const ast::TypeExpr * >( crnt->get() );
452 } while(true);
453
454 return new ast::TupleType( std::move(types), qs );
455 }
456
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
489 }
490
491 if ( !unifyExact(
492 pty, pty2, tenv, need, have, open, noWiden() ) ) {
493 result = false;
494 return;
495 }
496
497 // ttype parameter should be last
498 if ( isTuple || isTuple2 ) break;
499 }
500 result = it == params.end() && jt == params2.end();
501 }
502
503public:
504 void postvisit( const ast::StructInstType * aggrType ) {
505 handleGenericRefType( aggrType, type2 );
506 }
507
508 void postvisit( const ast::UnionInstType * aggrType ) {
509 handleGenericRefType( aggrType, type2 );
510 }
511
512 void postvisit( const ast::EnumInstType * aggrType ) {
513 handleRefType( aggrType, type2 );
514 }
515
516 void postvisit( const ast::TraitInstType * aggrType ) {
517 handleRefType( aggrType, type2 );
518 }
519
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 }
527
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
546 return unifyExact(
547 t1, tupleFromTypes( list2 ), env, need, have, open,
548 noWiden() );
549 } else if ( !isTuple1 && isTuple2 ) {
550 // combine entirety of list1, then unify
551 return unifyExact(
552 tupleFromTypes( list1 ), t2, env, need, have, open,
553 noWiden() );
554 }
555
556 if ( !unifyExact(
557 t1, t2, env, need, have, open, noWiden() )
558 ) return false;
559
560 ++crnt1; ++crnt2;
561 }
562
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 }
582
583 return true;
584 }
585
586public:
587 void postvisit( const ast::TupleType * tuple ) {
588 auto tuple2 = dynamic_cast< const ast::TupleType * >( type2 );
589 if ( ! tuple2 ) return;
590
591 ast::Pass<TtypeExpander> expander{ tenv };
592
593 const ast::Type * flat = tuple->accept( expander );
594 const ast::Type * flat2 = tuple2->accept( expander );
595
596 auto types = flatten( flat );
597 auto types2 = flatten( flat2 );
598
599 result = unifyList( types, types2, tenv, need, have, open );
600 }
601
602 void postvisit( const ast::VarArgsType * ) {
603 result = dynamic_cast< const ast::VarArgsType * >( type2 );
604 }
605
606 void postvisit( const ast::ZeroType * ) {
607 result = dynamic_cast< const ast::ZeroType * >( type2 );
608 }
609
610 void postvisit( const ast::OneType * ) {
611 result = dynamic_cast< const ast::OneType * >( type2 );
612 }
613};
614
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}
664
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;
687 return true;
688 } else {
689 return false;
690 }
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;
699 }
700}
701
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];
705
706 std::vector<ast::ptr<ast::Type>> tys;
707 for ( const auto & decl : func->returns ) {
708 tys.emplace_back( decl );
709 }
710 return new ast::TupleType( std::move(tys) );
711}
712
713} // namespace ResolvExpr
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.