source: src/ResolvExpr/AlternativeFinder.cc@ 1dd1bd2

ADT aaron-thesis arm-eh ast-experimental cleanup-dtors deferred_resn enum forall-pointer-decay jacob/cs343-translation jenkins-sandbox new-ast new-ast-unique-expr no_list persistent-indexer pthread-emulation qualifiedEnum
Last change on this file since 1dd1bd2 was 1dd1bd2, checked in by Aaron Moss <a3moss@…>, 7 years ago

Add var count and type specialization costs to resolver model

  • Property mode set to 100644
File size: 74.4 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// AlternativeFinder.cc --
8//
9// Author : Richard C. Bilson
10// Created On : Sat May 16 23:52:08 2015
11// Last Modified By : Peter A. Buhr
12// Last Modified On : Sat Feb 17 11:19:39 2018
13// Update Count : 33
14//
15
16#include <algorithm> // for copy
17#include <cassert> // for strict_dynamic_cast, assert, assertf
18#include <cstddef> // for size_t
19#include <iostream> // for operator<<, cerr, ostream, endl
20#include <iterator> // for back_insert_iterator, back_inserter
21#include <list> // for _List_iterator, list, _List_const_...
22#include <map> // for _Rb_tree_iterator, map, _Rb_tree_c...
23#include <memory> // for allocator_traits<>::value_type, unique_ptr
24#include <utility> // for pair
25#include <vector> // for vector
26
27#include "CompilationState.h" // for resolvep
28#include "Alternative.h" // for AltList, Alternative
29#include "AlternativeFinder.h"
30#include "Common/SemanticError.h" // for SemanticError
31#include "Common/utility.h" // for deleteAll, printAll, CodeLocation
32#include "Cost.h" // for Cost, Cost::zero, operator<<, Cost...
33#include "ExplodedActual.h" // for ExplodedActual
34#include "InitTweak/InitTweak.h" // for getFunctionName
35#include "RenameVars.h" // for RenameVars, global_renamer
36#include "ResolveTypeof.h" // for resolveTypeof
37#include "Resolver.h" // for resolveStmtExpr
38#include "SymTab/Indexer.h" // for Indexer
39#include "SymTab/Mangler.h" // for Mangler
40#include "SymTab/Validate.h" // for validateType
41#include "SynTree/Constant.h" // for Constant
42#include "SynTree/Declaration.h" // for DeclarationWithType, TypeDecl, Dec...
43#include "SynTree/Expression.h" // for Expression, CastExpr, NameExpr
44#include "SynTree/Initializer.h" // for SingleInit, operator<<, Designation
45#include "SynTree/SynTree.h" // for UniqueId
46#include "SynTree/Type.h" // for Type, FunctionType, PointerType
47#include "Tuples/Explode.h" // for explode
48#include "Tuples/Tuples.h" // for isTtype, handleTupleAssignment
49#include "Unify.h" // for unify
50#include "typeops.h" // for adjustExprType, polyCost, castCost
51
52#define PRINT( text ) if ( resolvep ) { text }
53//#define DEBUG_COST
54
55using std::move;
56
57/// copies any copyable type
58template<typename T>
59T copy(const T& x) { return x; }
60
61namespace ResolvExpr {
62 struct AlternativeFinder::Finder : public WithShortCircuiting {
63 Finder( AlternativeFinder & altFinder ) : altFinder( altFinder ), indexer( altFinder.indexer ), alternatives( altFinder.alternatives ), env( altFinder.env ), targetType( altFinder.targetType ) {}
64
65 void previsit( BaseSyntaxNode * ) { visit_children = false; }
66
67 void postvisit( ApplicationExpr * applicationExpr );
68 void postvisit( UntypedExpr * untypedExpr );
69 void postvisit( AddressExpr * addressExpr );
70 void postvisit( LabelAddressExpr * labelExpr );
71 void postvisit( CastExpr * castExpr );
72 void postvisit( VirtualCastExpr * castExpr );
73 void postvisit( UntypedMemberExpr * memberExpr );
74 void postvisit( MemberExpr * memberExpr );
75 void postvisit( NameExpr * variableExpr );
76 void postvisit( VariableExpr * variableExpr );
77 void postvisit( ConstantExpr * constantExpr );
78 void postvisit( SizeofExpr * sizeofExpr );
79 void postvisit( AlignofExpr * alignofExpr );
80 void postvisit( UntypedOffsetofExpr * offsetofExpr );
81 void postvisit( OffsetofExpr * offsetofExpr );
82 void postvisit( OffsetPackExpr * offsetPackExpr );
83 void postvisit( AttrExpr * attrExpr );
84 void postvisit( LogicalExpr * logicalExpr );
85 void postvisit( ConditionalExpr * conditionalExpr );
86 void postvisit( CommaExpr * commaExpr );
87 void postvisit( ImplicitCopyCtorExpr * impCpCtorExpr );
88 void postvisit( ConstructorExpr * ctorExpr );
89 void postvisit( RangeExpr * rangeExpr );
90 void postvisit( UntypedTupleExpr * tupleExpr );
91 void postvisit( TupleExpr * tupleExpr );
92 void postvisit( TupleIndexExpr * tupleExpr );
93 void postvisit( TupleAssignExpr * tupleExpr );
94 void postvisit( UniqueExpr * unqExpr );
95 void postvisit( StmtExpr * stmtExpr );
96 void postvisit( UntypedInitExpr * initExpr );
97 void postvisit( InitExpr * initExpr );
98 void postvisit( DeletedExpr * delExpr );
99 void postvisit( GenericExpr * genExpr );
100
101 /// Adds alternatives for anonymous members
102 void addAnonConversions( const Alternative & alt );
103 /// Adds alternatives for member expressions, given the aggregate, conversion cost for that aggregate, and name of the member
104 template< typename StructOrUnionType > void addAggMembers( StructOrUnionType *aggInst, Expression *expr, const Cost &newCost, const TypeEnvironment & env, const std::string & name );
105 /// Adds alternatives for member expressions where the left side has tuple type
106 void addTupleMembers( TupleType * tupleType, Expression *expr, const Cost &newCost, const TypeEnvironment & env, Expression * member );
107 /// Adds alternatives for offsetof expressions, given the base type and name of the member
108 template< typename StructOrUnionType > void addOffsetof( StructOrUnionType *aggInst, const std::string &name );
109 /// Takes a final result and checks if its assertions can be satisfied
110 template<typename OutputIterator>
111 void validateFunctionAlternative( const Alternative &func, ArgPack& result, const std::vector<ArgPack>& results, OutputIterator out );
112 /// Finds matching alternatives for a function, given a set of arguments
113 template<typename OutputIterator>
114 void makeFunctionAlternatives( const Alternative &func, FunctionType *funcType, const ExplodedArgs& args, OutputIterator out );
115 /// Checks if assertion parameters match for a new alternative
116 template< typename OutputIterator >
117 void inferParameters( const AssertionSet &need, AssertionSet &have, const Alternative &newAlt, OpenVarSet &openVars, OutputIterator out );
118 private:
119 AlternativeFinder & altFinder;
120 const SymTab::Indexer &indexer;
121 AltList & alternatives;
122 const TypeEnvironment &env;
123 Type *& targetType;
124 };
125
126 Cost sumCost( const AltList &in ) {
127 Cost total = Cost::zero;
128 for ( AltList::const_iterator i = in.begin(); i != in.end(); ++i ) {
129 total += i->cost;
130 }
131 return total;
132 }
133
134 void printAlts( const AltList &list, std::ostream &os, unsigned int indentAmt ) {
135 Indenter indent = { Indenter::tabsize, indentAmt };
136 for ( AltList::const_iterator i = list.begin(); i != list.end(); ++i ) {
137 i->print( os, indent );
138 os << std::endl;
139 }
140 }
141
142 namespace {
143 void makeExprList( const AltList &in, std::list< Expression* > &out ) {
144 for ( AltList::const_iterator i = in.begin(); i != in.end(); ++i ) {
145 out.push_back( i->expr->clone() );
146 }
147 }
148
149 struct PruneStruct {
150 bool isAmbiguous;
151 AltList::iterator candidate;
152 PruneStruct() {}
153 PruneStruct( AltList::iterator candidate ): isAmbiguous( false ), candidate( candidate ) {}
154 };
155
156 /// Prunes a list of alternatives down to those that have the minimum conversion cost for a given return type; skips ambiguous interpretations
157 template< typename InputIterator, typename OutputIterator >
158 void pruneAlternatives( InputIterator begin, InputIterator end, OutputIterator out ) {
159 // select the alternatives that have the minimum conversion cost for a particular set of result types
160 std::map< std::string, PruneStruct > selected;
161 for ( AltList::iterator candidate = begin; candidate != end; ++candidate ) {
162 PruneStruct current( candidate );
163 std::string mangleName;
164 {
165 Type * newType = candidate->expr->get_result()->clone();
166 candidate->env.apply( newType );
167 mangleName = SymTab::Mangler::mangle( newType );
168 delete newType;
169 }
170 std::map< std::string, PruneStruct >::iterator mapPlace = selected.find( mangleName );
171 if ( mapPlace != selected.end() ) {
172 if ( candidate->cost < mapPlace->second.candidate->cost ) {
173 PRINT(
174 std::cerr << "cost " << candidate->cost << " beats " << mapPlace->second.candidate->cost << std::endl;
175 )
176 selected[ mangleName ] = current;
177 } else if ( candidate->cost == mapPlace->second.candidate->cost ) {
178 // if one of the candidates contains a deleted identifier, can pick the other, since
179 // deleted expressions should not be ambiguous if there is another option that is at least as good
180 if ( findDeletedExpr( candidate->expr ) ) {
181 // do nothing
182 PRINT( std::cerr << "candidate is deleted" << std::endl; )
183 } else if ( findDeletedExpr( mapPlace->second.candidate->expr ) ) {
184 PRINT( std::cerr << "current is deleted" << std::endl; )
185 selected[ mangleName ] = current;
186 } else {
187 PRINT(
188 std::cerr << "marking ambiguous" << std::endl;
189 )
190 mapPlace->second.isAmbiguous = true;
191 }
192 } else {
193 PRINT(
194 std::cerr << "cost " << candidate->cost << " loses to " << mapPlace->second.candidate->cost << std::endl;
195 )
196 }
197 } else {
198 selected[ mangleName ] = current;
199 }
200 }
201
202 // accept the alternatives that were unambiguous
203 for ( std::map< std::string, PruneStruct >::iterator target = selected.begin(); target != selected.end(); ++target ) {
204 if ( ! target->second.isAmbiguous ) {
205 Alternative &alt = *target->second.candidate;
206 alt.env.applyFree( alt.expr->get_result() );
207 *out++ = alt;
208 }
209 }
210 }
211
212 void renameTypes( Expression *expr ) {
213 renameTyVars( expr->result );
214 }
215 } // namespace
216
217 void referenceToRvalueConversion( Expression *& expr, Cost & cost ) {
218 if ( dynamic_cast< ReferenceType * >( expr->get_result() ) ) {
219 // cast away reference from expr
220 expr = new CastExpr( expr, expr->get_result()->stripReferences()->clone() );
221 cost.incReference();
222 }
223 }
224
225 template< typename InputIterator, typename OutputIterator >
226 void AlternativeFinder::findSubExprs( InputIterator begin, InputIterator end, OutputIterator out ) {
227 while ( begin != end ) {
228 AlternativeFinder finder( indexer, env );
229 finder.findWithAdjustment( *begin );
230 // XXX either this
231 //Designators::fixDesignations( finder, (*begin++)->get_argName() );
232 // or XXX this
233 begin++;
234 PRINT(
235 std::cerr << "findSubExprs" << std::endl;
236 printAlts( finder.alternatives, std::cerr );
237 )
238 *out++ = finder;
239 }
240 }
241
242 AlternativeFinder::AlternativeFinder( const SymTab::Indexer &indexer, const TypeEnvironment &env )
243 : indexer( indexer ), env( env ) {
244 }
245
246 void AlternativeFinder::find( Expression *expr, bool adjust, bool prune, bool failFast ) {
247 PassVisitor<Finder> finder( *this );
248 expr->accept( finder );
249 if ( failFast && alternatives.empty() ) {
250 PRINT(
251 std::cerr << "No reasonable alternatives for expression " << expr << std::endl;
252 )
253 SemanticError( expr, "No reasonable alternatives for expression " );
254 }
255 if ( prune ) {
256 auto oldsize = alternatives.size();
257 PRINT(
258 std::cerr << "alternatives before prune:" << std::endl;
259 printAlts( alternatives, std::cerr );
260 )
261 AltList pruned;
262 pruneAlternatives( alternatives.begin(), alternatives.end(), back_inserter( pruned ) );
263 if ( failFast && pruned.empty() ) {
264 std::ostringstream stream;
265 AltList winners;
266 findMinCost( alternatives.begin(), alternatives.end(), back_inserter( winners ) );
267 stream << "Cannot choose between " << winners.size() << " alternatives for expression\n";
268 expr->print( stream );
269 stream << " Alternatives are:\n";
270 printAlts( winners, stream, 1 );
271 SemanticError( expr->location, stream.str() );
272 }
273 alternatives = move(pruned);
274 PRINT(
275 std::cerr << "there are " << oldsize << " alternatives before elimination" << std::endl;
276 )
277 PRINT(
278 std::cerr << "there are " << alternatives.size() << " alternatives after elimination" << std::endl;
279 )
280 }
281 // adjust types after pruning so that types substituted by pruneAlternatives are correctly adjusted
282 for ( AltList::iterator i = alternatives.begin(); i != alternatives.end(); ++i ) {
283 if ( adjust ) {
284 adjustExprType( i->expr->get_result(), i->env, indexer );
285 }
286 }
287
288 // Central location to handle gcc extension keyword, etc. for all expression types.
289 for ( Alternative &iter: alternatives ) {
290 iter.expr->set_extension( expr->get_extension() );
291 iter.expr->location = expr->location;
292 } // for
293 }
294
295 void AlternativeFinder::findWithAdjustment( Expression *expr ) {
296 find( expr, true );
297 }
298
299 void AlternativeFinder::findWithoutPrune( Expression * expr ) {
300 find( expr, true, false );
301 }
302
303 void AlternativeFinder::maybeFind( Expression * expr ) {
304 find( expr, true, true, false );
305 }
306
307 void AlternativeFinder::Finder::addAnonConversions( const Alternative & alt ) {
308 // adds anonymous member interpretations whenever an aggregate value type is seen.
309 // it's okay for the aggregate expression to have reference type -- cast it to the base type to treat the aggregate as the referenced value
310 std::unique_ptr<Expression> aggrExpr( alt.expr->clone() );
311 alt.env.apply( aggrExpr->result );
312 Type * aggrType = aggrExpr->result;
313 if ( dynamic_cast< ReferenceType * >( aggrType ) ) {
314 aggrType = aggrType->stripReferences();
315 aggrExpr.reset( new CastExpr( aggrExpr.release(), aggrType->clone() ) );
316 }
317
318 if ( StructInstType *structInst = dynamic_cast< StructInstType* >( aggrExpr->result ) ) {
319 addAggMembers( structInst, aggrExpr.get(), alt.cost+Cost::safe, alt.env, "" );
320 } else if ( UnionInstType *unionInst = dynamic_cast< UnionInstType* >( aggrExpr->result ) ) {
321 addAggMembers( unionInst, aggrExpr.get(), alt.cost+Cost::safe, alt.env, "" );
322 } // if
323 }
324
325 template< typename StructOrUnionType >
326 void AlternativeFinder::Finder::addAggMembers( StructOrUnionType *aggInst, Expression *expr, const Cost &newCost, const TypeEnvironment & env, const std::string & name ) {
327 std::list< Declaration* > members;
328 aggInst->lookup( name, members );
329
330 for ( Declaration * decl : members ) {
331 if ( DeclarationWithType *dwt = dynamic_cast< DeclarationWithType* >( decl ) ) {
332 // addAnonAlternatives uses vector::push_back, which invalidates references to existing elements, so
333 // can't construct in place and use vector::back
334 Alternative newAlt( new MemberExpr( dwt, expr->clone() ), env, newCost );
335 renameTypes( newAlt.expr );
336 addAnonConversions( newAlt ); // add anonymous member interpretations whenever an aggregate value type is seen as a member expression.
337 alternatives.push_back( std::move(newAlt) );
338 } else {
339 assert( false );
340 }
341 }
342 }
343
344 void AlternativeFinder::Finder::addTupleMembers( TupleType * tupleType, Expression *expr, const Cost &newCost, const TypeEnvironment & env, Expression * member ) {
345 if ( ConstantExpr * constantExpr = dynamic_cast< ConstantExpr * >( member ) ) {
346 // get the value of the constant expression as an int, must be between 0 and the length of the tuple type to have meaning
347 auto val = constantExpr->intValue();
348 std::string tmp;
349 if ( val >= 0 && (unsigned long long)val < tupleType->size() ) {
350 alternatives.push_back( Alternative( new TupleIndexExpr( expr->clone(), val ), env, newCost ) );
351 } // if
352 } // if
353 }
354
355 void AlternativeFinder::Finder::postvisit( ApplicationExpr *applicationExpr ) {
356 alternatives.push_back( Alternative( applicationExpr->clone(), env, Cost::zero ) );
357 }
358
359 Cost computeConversionCost( Type * actualType, Type * formalType, const SymTab::Indexer &indexer, const TypeEnvironment & env ) {
360 PRINT(
361 std::cerr << std::endl << "converting ";
362 actualType->print( std::cerr, 8 );
363 std::cerr << std::endl << " to ";
364 formalType->print( std::cerr, 8 );
365 std::cerr << std::endl << "environment is: ";
366 env.print( std::cerr, 8 );
367 std::cerr << std::endl;
368 )
369 Cost convCost = conversionCost( actualType, formalType, indexer, env );
370 PRINT(
371 std::cerr << std::endl << "cost is " << convCost << std::endl;
372 )
373 if ( convCost == Cost::infinity ) {
374 return convCost;
375 }
376 convCost.incPoly( polyCost( formalType, env, indexer ) + polyCost( actualType, env, indexer ) );
377 PRINT(
378 std::cerr << "cost with polycost is " << convCost << std::endl;
379 )
380 return convCost;
381 }
382
383 Cost computeExpressionConversionCost( Expression *& actualExpr, Type * formalType, const SymTab::Indexer &indexer, const TypeEnvironment & env ) {
384 Cost convCost = computeConversionCost( actualExpr->result, formalType, indexer, env );
385
386 // if there is a non-zero conversion cost, ignoring poly cost, then the expression requires conversion.
387 // ignore poly cost for now, since this requires resolution of the cast to infer parameters and this
388 // does not currently work for the reason stated below.
389 Cost tmpCost = convCost;
390 tmpCost.incPoly( -tmpCost.get_polyCost() );
391 if ( tmpCost != Cost::zero ) {
392 Type *newType = formalType->clone();
393 env.apply( newType );
394 actualExpr = new CastExpr( actualExpr, newType );
395 // xxx - SHOULD be able to resolve this cast, but at the moment pointers are not castable to zero_t, but are implicitly convertible. This is clearly
396 // inconsistent, once this is fixed it should be possible to resolve the cast.
397 // xxx - this isn't working, it appears because type1 (the formal type) is seen as widenable, but it shouldn't be, because this makes the conversion from DT* to DT* since commontype(zero_t, DT*) is DT*, rather than just nothing.
398
399 // AlternativeFinder finder( indexer, env );
400 // finder.findWithAdjustment( actualExpr );
401 // assertf( finder.get_alternatives().size() > 0, "Somehow castable expression failed to find alternatives." );
402 // assertf( finder.get_alternatives().size() == 1, "Somehow got multiple alternatives for known cast expression." );
403 // Alternative & alt = finder.get_alternatives().front();
404 // delete actualExpr;
405 // actualExpr = alt.expr->clone();
406 }
407 return convCost;
408 }
409
410 Cost computeApplicationConversionCost( Alternative &alt, const SymTab::Indexer &indexer ) {
411 ApplicationExpr *appExpr = strict_dynamic_cast< ApplicationExpr* >( alt.expr );
412 PointerType *pointer = strict_dynamic_cast< PointerType* >( appExpr->function->result );
413 FunctionType *function = strict_dynamic_cast< FunctionType* >( pointer->base );
414
415 Cost convCost = Cost::zero;
416 std::list< DeclarationWithType* >& formals = function->parameters;
417 std::list< DeclarationWithType* >::iterator formal = formals.begin();
418 std::list< Expression* >& actuals = appExpr->args;
419
420 for ( Expression*& actualExpr : actuals ) {
421 Type * actualType = actualExpr->result;
422 PRINT(
423 std::cerr << "actual expression:" << std::endl;
424 actualExpr->print( std::cerr, 8 );
425 std::cerr << "--- results are" << std::endl;
426 actualType->print( std::cerr, 8 );
427 )
428 if ( formal == formals.end() ) {
429 if ( function->isVarArgs ) {
430 convCost.incUnsafe();
431 PRINT( std::cerr << "end of formals with varargs function: inc unsafe: " << convCost << std::endl; ; )
432 // convert reference-typed expressions to value-typed expressions
433 referenceToRvalueConversion( actualExpr, convCost );
434 continue;
435 } else {
436 return Cost::infinity;
437 }
438 }
439 if ( DefaultArgExpr * def = dynamic_cast< DefaultArgExpr * >( actualExpr ) ) {
440 // default arguments should be free - don't include conversion cost.
441 // Unwrap them here because they are not relevant to the rest of the system.
442 actualExpr = def->expr;
443 ++formal;
444 continue;
445 }
446 // mark conversion cost to formal and also specialization cost of formal type
447 Type * formalType = (*formal)->get_type();
448 convCost += computeExpressionConversionCost( actualExpr, formalType, indexer, alt.env );
449 convCost.decSpec( specCost( formalType ) );
450 ++formal; // can't be in for-loop update because of the continue
451 }
452 if ( formal != formals.end() ) {
453 return Cost::infinity;
454 }
455
456 // mark specialization cost of return types
457 for ( DeclarationWithType* returnVal : function->returnVals ) {
458 convCost.decSpec( specCost( returnVal->get_type() ) );
459 }
460
461 // mark type variable and specialization cost of forall clause
462 convCost.incVar( function->forall.size() );
463 for ( TypeDecl* td : function->forall ) {
464 convCost.decSpec( td->assertions.size() );
465 }
466
467 // xxx -- replace with new costs in resolver
468 for ( InferredParams::const_iterator assert = appExpr->get_inferParams().begin(); assert != appExpr->get_inferParams().end(); ++assert ) {
469 convCost += computeConversionCost( assert->second.actualType, assert->second.formalType, indexer, alt.env );
470 }
471
472 return convCost;
473 }
474
475 /// Adds type variables to the open variable set and marks their assertions
476 void makeUnifiableVars( Type *type, OpenVarSet &unifiableVars, AssertionSet &needAssertions ) {
477 for ( Type::ForallList::const_iterator tyvar = type->forall.begin(); tyvar != type->forall.end(); ++tyvar ) {
478 unifiableVars[ (*tyvar)->get_name() ] = TypeDecl::Data{ *tyvar };
479 for ( std::list< DeclarationWithType* >::iterator assert = (*tyvar)->assertions.begin(); assert != (*tyvar)->assertions.end(); ++assert ) {
480 needAssertions[ *assert ].isUsed = true;
481 }
482/// needAssertions.insert( needAssertions.end(), (*tyvar)->get_assertions().begin(), (*tyvar)->get_assertions().end() );
483 }
484 }
485
486 static const int recursionLimit = /*10*/ 4; ///< Limit to depth of recursion satisfaction
487
488 void addToIndexer( AssertionSet &assertSet, SymTab::Indexer &indexer ) {
489 for ( AssertionSet::iterator i = assertSet.begin(); i != assertSet.end(); ++i ) {
490 if ( i->second.isUsed ) {
491 indexer.addId( i->first );
492 }
493 }
494 }
495
496 template< typename ForwardIterator, typename OutputIterator >
497 void inferRecursive( ForwardIterator begin, ForwardIterator end, const Alternative &newAlt, OpenVarSet &openVars, const SymTab::Indexer &decls, const AssertionSet &newNeed, int level, const SymTab::Indexer &indexer, OutputIterator out ) {
498 if ( newAlt.cost == Cost::infinity ) return; // don't proceed down this dead end
499 if ( begin == end ) {
500 if ( newNeed.empty() ) {
501 PRINT(
502 std::cerr << "all assertions satisfied, output alternative: ";
503 newAlt.print( std::cerr );
504 std::cerr << std::endl;
505 );
506 *out++ = newAlt;
507 return;
508 } else if ( level >= recursionLimit ) {
509 SemanticError( newAlt.expr->location, "Too many recursive assertions" );
510 } else {
511 AssertionSet newerNeed;
512 PRINT(
513 std::cerr << "recursing with new set:" << std::endl;
514 printAssertionSet( newNeed, std::cerr, 8 );
515 )
516 inferRecursive( newNeed.begin(), newNeed.end(), newAlt, openVars, decls, newerNeed, level+1, indexer, out );
517 return;
518 }
519 }
520
521 ForwardIterator cur = begin++;
522 if ( ! cur->second.isUsed ) {
523 inferRecursive( begin, end, newAlt, openVars, decls, newNeed, level, indexer, out );
524 return; // xxx - should this continue? previously this wasn't here, and it looks like it should be
525 }
526 DeclarationWithType *curDecl = cur->first;
527
528 PRINT(
529 std::cerr << "inferRecursive: assertion is ";
530 curDecl->print( std::cerr );
531 std::cerr << std::endl;
532 )
533 std::list< SymTab::Indexer::IdData > candidates;
534 decls.lookupId( curDecl->get_name(), candidates );
535/// if ( candidates.empty() ) { std::cerr << "no candidates!" << std::endl; }
536 for ( const auto & data : candidates ) {
537 DeclarationWithType * candidate = data.id;
538 PRINT(
539 std::cerr << "inferRecursive: candidate is ";
540 candidate->print( std::cerr );
541 std::cerr << std::endl;
542 )
543
544 AssertionSet newHave, newerNeed( newNeed );
545 TypeEnvironment newEnv( newAlt.env );
546 OpenVarSet newOpenVars( openVars );
547 Type *adjType = candidate->get_type()->clone();
548 adjustExprType( adjType, newEnv, indexer );
549 renameTyVars( adjType );
550 PRINT(
551 std::cerr << "unifying ";
552 curDecl->get_type()->print( std::cerr );
553 std::cerr << " with ";
554 adjType->print( std::cerr );
555 std::cerr << std::endl;
556 )
557 if ( unify( curDecl->get_type(), adjType, newEnv, newerNeed, newHave, newOpenVars, indexer ) ) {
558 PRINT(
559 std::cerr << "success!" << std::endl;
560 )
561 SymTab::Indexer newDecls( decls );
562 addToIndexer( newHave, newDecls );
563 Alternative newerAlt( newAlt );
564 newerAlt.env = newEnv;
565 assertf( candidate->get_uniqueId(), "Assertion candidate does not have a unique ID: %s", toString( candidate ).c_str() );
566
567 // everything with an empty idChain was pulled in by the current assertion.
568 // add current assertion's idChain + current assertion's ID so that the correct inferParameters can be found.
569 for ( auto & a : newerNeed ) {
570 if ( a.second.idChain.empty() ) {
571 a.second.idChain = cur->second.idChain;
572 a.second.idChain.push_back( curDecl->get_uniqueId() );
573 }
574 }
575
576 Expression *varExpr = data.combine( newerAlt.cvtCost );
577 delete varExpr->get_result();
578 varExpr->set_result( adjType->clone() );
579 PRINT(
580 std::cerr << "satisfying assertion " << curDecl->get_uniqueId() << " ";
581 curDecl->print( std::cerr );
582 std::cerr << " with declaration " << candidate->get_uniqueId() << " ";
583 candidate->print( std::cerr );
584 std::cerr << std::endl;
585 )
586 // follow the current assertion's ID chain to find the correct set of inferred parameters to add the candidate to (i.e. the set of inferred parameters belonging to the entity which requested the assertion parameter).
587 InferredParams * inferParameters = &newerAlt.expr->get_inferParams();
588 for ( UniqueId id : cur->second.idChain ) {
589 inferParameters = (*inferParameters)[ id ].inferParams.get();
590 }
591 // XXX: this is a memory leak, but adjType can't be deleted because it might contain assertions
592 (*inferParameters)[ curDecl->get_uniqueId() ] = ParamEntry( candidate->get_uniqueId(), adjType->clone(), curDecl->get_type()->clone(), varExpr );
593 inferRecursive( begin, end, newerAlt, newOpenVars, newDecls, newerNeed, level, indexer, out );
594 } else {
595 delete adjType;
596 }
597 }
598 }
599
600 template< typename OutputIterator >
601 void AlternativeFinder::Finder::inferParameters( const AssertionSet &need, AssertionSet &have, const Alternative &newAlt, OpenVarSet &openVars, OutputIterator out ) {
602// PRINT(
603// std::cerr << "inferParameters: assertions needed are" << std::endl;
604// printAll( need, std::cerr, 8 );
605// )
606 SymTab::Indexer decls( indexer );
607 // PRINT(
608 // std::cerr << "============= original indexer" << std::endl;
609 // indexer.print( std::cerr );
610 // std::cerr << "============= new indexer" << std::endl;
611 // decls.print( std::cerr );
612 // )
613 addToIndexer( have, decls );
614 AssertionSet newNeed;
615 PRINT(
616 std::cerr << "env is: " << std::endl;
617 newAlt.env.print( std::cerr, 0 );
618 std::cerr << std::endl;
619 )
620
621 inferRecursive( need.begin(), need.end(), newAlt, openVars, decls, newNeed, 0, indexer, out );
622// PRINT(
623// std::cerr << "declaration 14 is ";
624// Declaration::declFromId
625// *out++ = newAlt;
626// )
627 }
628
629 /// Gets a default value from an initializer, nullptr if not present
630 ConstantExpr* getDefaultValue( Initializer* init ) {
631 if ( SingleInit* si = dynamic_cast<SingleInit*>( init ) ) {
632 if ( CastExpr* ce = dynamic_cast<CastExpr*>( si->value ) ) {
633 return dynamic_cast<ConstantExpr*>( ce->arg );
634 } else {
635 return dynamic_cast<ConstantExpr*>( si->value );
636 }
637 }
638 return nullptr;
639 }
640
641 /// State to iteratively build a match of parameter expressions to arguments
642 struct ArgPack {
643 std::size_t parent; ///< Index of parent pack
644 std::unique_ptr<Expression> expr; ///< The argument stored here
645 Cost cost; ///< The cost of this argument
646 TypeEnvironment env; ///< Environment for this pack
647 AssertionSet need; ///< Assertions outstanding for this pack
648 AssertionSet have; ///< Assertions found for this pack
649 OpenVarSet openVars; ///< Open variables for this pack
650 unsigned nextArg; ///< Index of next argument in arguments list
651 unsigned tupleStart; ///< Number of tuples that start at this index
652 unsigned nextExpl; ///< Index of next exploded element
653 unsigned explAlt; ///< Index of alternative for nextExpl > 0
654
655 ArgPack()
656 : parent(0), expr(), cost(Cost::zero), env(), need(), have(), openVars(), nextArg(0),
657 tupleStart(0), nextExpl(0), explAlt(0) {}
658
659 ArgPack(const TypeEnvironment& env, const AssertionSet& need, const AssertionSet& have,
660 const OpenVarSet& openVars)
661 : parent(0), expr(), cost(Cost::zero), env(env), need(need), have(have),
662 openVars(openVars), nextArg(0), tupleStart(0), nextExpl(0), explAlt(0) {}
663
664 ArgPack(std::size_t parent, Expression* expr, TypeEnvironment&& env, AssertionSet&& need,
665 AssertionSet&& have, OpenVarSet&& openVars, unsigned nextArg,
666 unsigned tupleStart = 0, Cost cost = Cost::zero, unsigned nextExpl = 0,
667 unsigned explAlt = 0 )
668 : parent(parent), expr(expr->clone()), cost(cost), env(move(env)), need(move(need)),
669 have(move(have)), openVars(move(openVars)), nextArg(nextArg), tupleStart(tupleStart),
670 nextExpl(nextExpl), explAlt(explAlt) {}
671
672 ArgPack(const ArgPack& o, TypeEnvironment&& env, AssertionSet&& need, AssertionSet&& have,
673 OpenVarSet&& openVars, unsigned nextArg, Cost added )
674 : parent(o.parent), expr(o.expr ? o.expr->clone() : nullptr), cost(o.cost + added),
675 env(move(env)), need(move(need)), have(move(have)), openVars(move(openVars)),
676 nextArg(nextArg), tupleStart(o.tupleStart), nextExpl(0), explAlt(0) {}
677
678 /// true iff this pack is in the middle of an exploded argument
679 bool hasExpl() const { return nextExpl > 0; }
680
681 /// Gets the list of exploded alternatives for this pack
682 const ExplodedActual& getExpl( const ExplodedArgs& args ) const {
683 return args[nextArg-1][explAlt];
684 }
685
686 /// Ends a tuple expression, consolidating the appropriate actuals
687 void endTuple( const std::vector<ArgPack>& packs ) {
688 // add all expressions in tuple to list, summing cost
689 std::list<Expression*> exprs;
690 const ArgPack* pack = this;
691 if ( expr ) { exprs.push_front( expr.release() ); }
692 while ( pack->tupleStart == 0 ) {
693 pack = &packs[pack->parent];
694 exprs.push_front( pack->expr->clone() );
695 cost += pack->cost;
696 }
697 // reset pack to appropriate tuple
698 expr.reset( new TupleExpr( exprs ) );
699 tupleStart = pack->tupleStart - 1;
700 parent = pack->parent;
701 }
702 };
703
704 /// Instantiates an argument to match a formal, returns false if no results left
705 bool instantiateArgument( Type* formalType, Initializer* initializer,
706 const ExplodedArgs& args, std::vector<ArgPack>& results, std::size_t& genStart,
707 const SymTab::Indexer& indexer, unsigned nTuples = 0 ) {
708 if ( TupleType * tupleType = dynamic_cast<TupleType*>( formalType ) ) {
709 // formalType is a TupleType - group actuals into a TupleExpr
710 ++nTuples;
711 for ( Type* type : *tupleType ) {
712 // xxx - dropping initializer changes behaviour from previous, but seems correct
713 // ^^^ need to handle the case where a tuple has a default argument
714 if ( ! instantiateArgument(
715 type, nullptr, args, results, genStart, indexer, nTuples ) )
716 return false;
717 nTuples = 0;
718 }
719 // re-consititute tuples for final generation
720 for ( auto i = genStart; i < results.size(); ++i ) {
721 results[i].endTuple( results );
722 }
723 return true;
724 } else if ( TypeInstType * ttype = Tuples::isTtype( formalType ) ) {
725 // formalType is a ttype, consumes all remaining arguments
726 // xxx - mixing default arguments with variadic??
727
728 // completed tuples; will be spliced to end of results to finish
729 std::vector<ArgPack> finalResults{};
730
731 // iterate until all results completed
732 std::size_t genEnd;
733 ++nTuples;
734 do {
735 genEnd = results.size();
736
737 // add another argument to results
738 for ( std::size_t i = genStart; i < genEnd; ++i ) {
739 auto nextArg = results[i].nextArg;
740
741 // use next element of exploded tuple if present
742 if ( results[i].hasExpl() ) {
743 const ExplodedActual& expl = results[i].getExpl( args );
744
745 unsigned nextExpl = results[i].nextExpl + 1;
746 if ( nextExpl == expl.exprs.size() ) {
747 nextExpl = 0;
748 }
749
750 results.emplace_back(
751 i, expl.exprs[results[i].nextExpl].get(), copy(results[i].env),
752 copy(results[i].need), copy(results[i].have),
753 copy(results[i].openVars), nextArg, nTuples, Cost::zero, nextExpl,
754 results[i].explAlt );
755
756 continue;
757 }
758
759 // finish result when out of arguments
760 if ( nextArg >= args.size() ) {
761 ArgPack newResult{
762 results[i].env, results[i].need, results[i].have,
763 results[i].openVars };
764 newResult.nextArg = nextArg;
765 Type* argType;
766
767 if ( nTuples > 0 || ! results[i].expr ) {
768 // first iteration or no expression to clone,
769 // push empty tuple expression
770 newResult.parent = i;
771 std::list<Expression*> emptyList;
772 newResult.expr.reset( new TupleExpr( emptyList ) );
773 argType = newResult.expr->get_result();
774 } else {
775 // clone result to collect tuple
776 newResult.parent = results[i].parent;
777 newResult.cost = results[i].cost;
778 newResult.tupleStart = results[i].tupleStart;
779 newResult.expr.reset( results[i].expr->clone() );
780 argType = newResult.expr->get_result();
781
782 if ( results[i].tupleStart > 0 && Tuples::isTtype( argType ) ) {
783 // the case where a ttype value is passed directly is special,
784 // e.g. for argument forwarding purposes
785 // xxx - what if passing multiple arguments, last of which is
786 // ttype?
787 // xxx - what would happen if unify was changed so that unifying
788 // tuple
789 // types flattened both before unifying lists? then pass in
790 // TupleType (ttype) below.
791 --newResult.tupleStart;
792 } else {
793 // collapse leftover arguments into tuple
794 newResult.endTuple( results );
795 argType = newResult.expr->get_result();
796 }
797 }
798
799 // check unification for ttype before adding to final
800 if ( unify( ttype, argType, newResult.env, newResult.need, newResult.have,
801 newResult.openVars, indexer ) ) {
802 finalResults.push_back( move(newResult) );
803 }
804
805 continue;
806 }
807
808 // add each possible next argument
809 for ( std::size_t j = 0; j < args[nextArg].size(); ++j ) {
810 const ExplodedActual& expl = args[nextArg][j];
811
812 // fresh copies of parent parameters for this iteration
813 TypeEnvironment env = results[i].env;
814 OpenVarSet openVars = results[i].openVars;
815
816 env.addActual( expl.env, openVars );
817
818 // skip empty tuple arguments by (near-)cloning parent into next gen
819 if ( expl.exprs.empty() ) {
820 results.emplace_back(
821 results[i], move(env), copy(results[i].need),
822 copy(results[i].have), move(openVars), nextArg + 1, expl.cost );
823
824 continue;
825 }
826
827 // add new result
828 results.emplace_back(
829 i, expl.exprs.front().get(), move(env), copy(results[i].need),
830 copy(results[i].have), move(openVars), nextArg + 1,
831 nTuples, expl.cost, expl.exprs.size() == 1 ? 0 : 1, j );
832 }
833 }
834
835 // reset for next round
836 genStart = genEnd;
837 nTuples = 0;
838 } while ( genEnd != results.size() );
839
840 // splice final results onto results
841 for ( std::size_t i = 0; i < finalResults.size(); ++i ) {
842 results.push_back( move(finalResults[i]) );
843 }
844 return ! finalResults.empty();
845 }
846
847 // iterate each current subresult
848 std::size_t genEnd = results.size();
849 for ( std::size_t i = genStart; i < genEnd; ++i ) {
850 auto nextArg = results[i].nextArg;
851
852 // use remainder of exploded tuple if present
853 if ( results[i].hasExpl() ) {
854 const ExplodedActual& expl = results[i].getExpl( args );
855 Expression* expr = expl.exprs[results[i].nextExpl].get();
856
857 TypeEnvironment env = results[i].env;
858 AssertionSet need = results[i].need, have = results[i].have;
859 OpenVarSet openVars = results[i].openVars;
860
861 Type* actualType = expr->get_result();
862
863 PRINT(
864 std::cerr << "formal type is ";
865 formalType->print( std::cerr );
866 std::cerr << std::endl << "actual type is ";
867 actualType->print( std::cerr );
868 std::cerr << std::endl;
869 )
870
871 if ( unify( formalType, actualType, env, need, have, openVars, indexer ) ) {
872 unsigned nextExpl = results[i].nextExpl + 1;
873 if ( nextExpl == expl.exprs.size() ) {
874 nextExpl = 0;
875 }
876
877 results.emplace_back(
878 i, expr, move(env), move(need), move(have), move(openVars), nextArg,
879 nTuples, Cost::zero, nextExpl, results[i].explAlt );
880 }
881
882 continue;
883 }
884
885 // use default initializers if out of arguments
886 if ( nextArg >= args.size() ) {
887 if ( ConstantExpr* cnstExpr = getDefaultValue( initializer ) ) {
888 if ( Constant* cnst = dynamic_cast<Constant*>( cnstExpr->get_constant() ) ) {
889 TypeEnvironment env = results[i].env;
890 AssertionSet need = results[i].need, have = results[i].have;
891 OpenVarSet openVars = results[i].openVars;
892
893 if ( unify( formalType, cnst->get_type(), env, need, have, openVars,
894 indexer ) ) {
895 results.emplace_back(
896 i, new DefaultArgExpr( cnstExpr ), move(env), move(need), move(have),
897 move(openVars), nextArg, nTuples );
898 }
899 }
900 }
901
902 continue;
903 }
904
905 // Check each possible next argument
906 for ( std::size_t j = 0; j < args[nextArg].size(); ++j ) {
907 const ExplodedActual& expl = args[nextArg][j];
908
909 // fresh copies of parent parameters for this iteration
910 TypeEnvironment env = results[i].env;
911 AssertionSet need = results[i].need, have = results[i].have;
912 OpenVarSet openVars = results[i].openVars;
913
914 env.addActual( expl.env, openVars );
915
916 // skip empty tuple arguments by (near-)cloning parent into next gen
917 if ( expl.exprs.empty() ) {
918 results.emplace_back(
919 results[i], move(env), move(need), move(have), move(openVars),
920 nextArg + 1, expl.cost );
921
922 continue;
923 }
924
925 // consider only first exploded actual
926 Expression* expr = expl.exprs.front().get();
927 Type* actualType = expr->result->clone();
928
929 PRINT(
930 std::cerr << "formal type is ";
931 formalType->print( std::cerr );
932 std::cerr << std::endl << "actual type is ";
933 actualType->print( std::cerr );
934 std::cerr << std::endl;
935 )
936
937 // attempt to unify types
938 if ( unify( formalType, actualType, env, need, have, openVars, indexer ) ) {
939 // add new result
940 results.emplace_back(
941 i, expr, move(env), move(need), move(have), move(openVars), nextArg + 1,
942 nTuples, expl.cost, expl.exprs.size() == 1 ? 0 : 1, j );
943 }
944 }
945 }
946
947 // reset for next parameter
948 genStart = genEnd;
949
950 return genEnd != results.size();
951 }
952
953 template<typename OutputIterator>
954 void AlternativeFinder::Finder::validateFunctionAlternative( const Alternative &func, ArgPack& result,
955 const std::vector<ArgPack>& results, OutputIterator out ) {
956 ApplicationExpr *appExpr = new ApplicationExpr( func.expr->clone() );
957 // sum cost and accumulate actuals
958 std::list<Expression*>& args = appExpr->args;
959 Cost cost = func.cost;
960 const ArgPack* pack = &result;
961 while ( pack->expr ) {
962 args.push_front( pack->expr->clone() );
963 cost += pack->cost;
964 pack = &results[pack->parent];
965 }
966 // build and validate new alternative
967 Alternative newAlt( appExpr, result.env, cost );
968 PRINT(
969 std::cerr << "instantiate function success: " << appExpr << std::endl;
970 std::cerr << "need assertions:" << std::endl;
971 printAssertionSet( result.need, std::cerr, 8 );
972 )
973 inferParameters( result.need, result.have, newAlt, result.openVars, out );
974 }
975
976 template<typename OutputIterator>
977 void AlternativeFinder::Finder::makeFunctionAlternatives( const Alternative &func,
978 FunctionType *funcType, const ExplodedArgs &args, OutputIterator out ) {
979 OpenVarSet funcOpenVars;
980 AssertionSet funcNeed, funcHave;
981 TypeEnvironment funcEnv( func.env );
982 makeUnifiableVars( funcType, funcOpenVars, funcNeed );
983 // add all type variables as open variables now so that those not used in the parameter
984 // list are still considered open.
985 funcEnv.add( funcType->forall );
986
987 if ( targetType && ! targetType->isVoid() && ! funcType->returnVals.empty() ) {
988 // attempt to narrow based on expected target type
989 Type * returnType = funcType->returnVals.front()->get_type();
990 if ( ! unify( returnType, targetType, funcEnv, funcNeed, funcHave, funcOpenVars,
991 indexer ) ) {
992 // unification failed, don't pursue this function alternative
993 return;
994 }
995 }
996
997 // iteratively build matches, one parameter at a time
998 std::vector<ArgPack> results;
999 results.push_back( ArgPack{ funcEnv, funcNeed, funcHave, funcOpenVars } );
1000 std::size_t genStart = 0;
1001
1002 for ( DeclarationWithType* formal : funcType->parameters ) {
1003 ObjectDecl* obj = strict_dynamic_cast< ObjectDecl* >( formal );
1004 if ( ! instantiateArgument(
1005 obj->type, obj->init, args, results, genStart, indexer ) )
1006 return;
1007 }
1008
1009 if ( funcType->get_isVarArgs() ) {
1010 // append any unused arguments to vararg pack
1011 std::size_t genEnd;
1012 do {
1013 genEnd = results.size();
1014
1015 // iterate results
1016 for ( std::size_t i = genStart; i < genEnd; ++i ) {
1017 auto nextArg = results[i].nextArg;
1018
1019 // use remainder of exploded tuple if present
1020 if ( results[i].hasExpl() ) {
1021 const ExplodedActual& expl = results[i].getExpl( args );
1022
1023 unsigned nextExpl = results[i].nextExpl + 1;
1024 if ( nextExpl == expl.exprs.size() ) {
1025 nextExpl = 0;
1026 }
1027
1028 results.emplace_back(
1029 i, expl.exprs[results[i].nextExpl].get(), copy(results[i].env),
1030 copy(results[i].need), copy(results[i].have),
1031 copy(results[i].openVars), nextArg, 0, Cost::zero, nextExpl,
1032 results[i].explAlt );
1033
1034 continue;
1035 }
1036
1037 // finish result when out of arguments
1038 if ( nextArg >= args.size() ) {
1039 validateFunctionAlternative( func, results[i], results, out );
1040
1041 continue;
1042 }
1043
1044 // add each possible next argument
1045 for ( std::size_t j = 0; j < args[nextArg].size(); ++j ) {
1046 const ExplodedActual& expl = args[nextArg][j];
1047
1048 // fresh copies of parent parameters for this iteration
1049 TypeEnvironment env = results[i].env;
1050 OpenVarSet openVars = results[i].openVars;
1051
1052 env.addActual( expl.env, openVars );
1053
1054 // skip empty tuple arguments by (near-)cloning parent into next gen
1055 if ( expl.exprs.empty() ) {
1056 results.emplace_back(
1057 results[i], move(env), copy(results[i].need),
1058 copy(results[i].have), move(openVars), nextArg + 1, expl.cost );
1059
1060 continue;
1061 }
1062
1063 // add new result
1064 results.emplace_back(
1065 i, expl.exprs.front().get(), move(env), copy(results[i].need),
1066 copy(results[i].have), move(openVars), nextArg + 1, 0,
1067 expl.cost, expl.exprs.size() == 1 ? 0 : 1, j );
1068 }
1069 }
1070
1071 genStart = genEnd;
1072 } while ( genEnd != results.size() );
1073 } else {
1074 // filter out results that don't use all the arguments
1075 for ( std::size_t i = genStart; i < results.size(); ++i ) {
1076 ArgPack& result = results[i];
1077 if ( ! result.hasExpl() && result.nextArg >= args.size() ) {
1078 validateFunctionAlternative( func, result, results, out );
1079 }
1080 }
1081 }
1082 }
1083
1084 void AlternativeFinder::Finder::postvisit( UntypedExpr *untypedExpr ) {
1085 AlternativeFinder funcFinder( indexer, env );
1086 funcFinder.findWithAdjustment( untypedExpr->function );
1087 // if there are no function alternatives, then proceeding is a waste of time.
1088 // xxx - findWithAdjustment throws, so this check and others like it shouldn't be necessary.
1089 if ( funcFinder.alternatives.empty() ) return;
1090
1091 std::vector< AlternativeFinder > argAlternatives;
1092 altFinder.findSubExprs( untypedExpr->begin_args(), untypedExpr->end_args(),
1093 back_inserter( argAlternatives ) );
1094
1095 // take care of possible tuple assignments
1096 // if not tuple assignment, assignment is taken care of as a normal function call
1097 Tuples::handleTupleAssignment( altFinder, untypedExpr, argAlternatives );
1098
1099 // find function operators
1100 static NameExpr *opExpr = new NameExpr( "?()" );
1101 AlternativeFinder funcOpFinder( indexer, env );
1102 // it's ok if there aren't any defined function ops
1103 funcOpFinder.maybeFind( opExpr );
1104 PRINT(
1105 std::cerr << "known function ops:" << std::endl;
1106 printAlts( funcOpFinder.alternatives, std::cerr, 1 );
1107 )
1108
1109 // pre-explode arguments
1110 ExplodedArgs argExpansions;
1111 argExpansions.reserve( argAlternatives.size() );
1112
1113 for ( const AlternativeFinder& arg : argAlternatives ) {
1114 argExpansions.emplace_back();
1115 auto& argE = argExpansions.back();
1116 // argE.reserve( arg.alternatives.size() );
1117
1118 for ( const Alternative& actual : arg ) {
1119 argE.emplace_back( actual, indexer );
1120 }
1121 }
1122
1123 AltList candidates;
1124 SemanticErrorException errors;
1125 for ( AltList::iterator func = funcFinder.alternatives.begin(); func != funcFinder.alternatives.end(); ++func ) {
1126 try {
1127 PRINT(
1128 std::cerr << "working on alternative: " << std::endl;
1129 func->print( std::cerr, 8 );
1130 )
1131 // check if the type is pointer to function
1132 if ( PointerType *pointer = dynamic_cast< PointerType* >( func->expr->result->stripReferences() ) ) {
1133 if ( FunctionType *function = dynamic_cast< FunctionType* >( pointer->base ) ) {
1134 Alternative newFunc( *func );
1135 referenceToRvalueConversion( newFunc.expr, newFunc.cost );
1136 makeFunctionAlternatives( newFunc, function, argExpansions,
1137 std::back_inserter( candidates ) );
1138 }
1139 } else if ( TypeInstType *typeInst = dynamic_cast< TypeInstType* >( func->expr->result->stripReferences() ) ) { // handle ftype (e.g. *? on function pointer)
1140 if ( const EqvClass *eqvClass = func->env.lookup( typeInst->name ) ) {
1141 if ( FunctionType *function = dynamic_cast< FunctionType* >( eqvClass->type ) ) {
1142 Alternative newFunc( *func );
1143 referenceToRvalueConversion( newFunc.expr, newFunc.cost );
1144 makeFunctionAlternatives( newFunc, function, argExpansions,
1145 std::back_inserter( candidates ) );
1146 } // if
1147 } // if
1148 }
1149 } catch ( SemanticErrorException &e ) {
1150 errors.append( e );
1151 }
1152 } // for
1153
1154 // try each function operator ?() with each function alternative
1155 if ( ! funcOpFinder.alternatives.empty() ) {
1156 // add exploded function alternatives to front of argument list
1157 std::vector<ExplodedActual> funcE;
1158 funcE.reserve( funcFinder.alternatives.size() );
1159 for ( const Alternative& actual : funcFinder ) {
1160 funcE.emplace_back( actual, indexer );
1161 }
1162 argExpansions.insert( argExpansions.begin(), move(funcE) );
1163
1164 for ( AltList::iterator funcOp = funcOpFinder.alternatives.begin();
1165 funcOp != funcOpFinder.alternatives.end(); ++funcOp ) {
1166 try {
1167 // check if type is a pointer to function
1168 if ( PointerType* pointer = dynamic_cast<PointerType*>(
1169 funcOp->expr->result->stripReferences() ) ) {
1170 if ( FunctionType* function =
1171 dynamic_cast<FunctionType*>( pointer->base ) ) {
1172 Alternative newFunc( *funcOp );
1173 referenceToRvalueConversion( newFunc.expr, newFunc.cost );
1174 makeFunctionAlternatives( newFunc, function, argExpansions,
1175 std::back_inserter( candidates ) );
1176 }
1177 }
1178 } catch ( SemanticErrorException &e ) {
1179 errors.append( e );
1180 }
1181 }
1182 }
1183
1184 // Implement SFINAE; resolution errors are only errors if there aren't any non-erroneous resolutions
1185 if ( candidates.empty() && ! errors.isEmpty() ) { throw errors; }
1186
1187 // compute conversionsion costs
1188 for ( Alternative& withFunc : candidates ) {
1189 Cost cvtCost = computeApplicationConversionCost( withFunc, indexer );
1190
1191 PRINT(
1192 ApplicationExpr *appExpr = strict_dynamic_cast< ApplicationExpr* >( withFunc.expr );
1193 PointerType *pointer = strict_dynamic_cast< PointerType* >( appExpr->function->result );
1194 FunctionType *function = strict_dynamic_cast< FunctionType* >( pointer->base );
1195 std::cerr << "Case +++++++++++++ " << appExpr->function << std::endl;
1196 std::cerr << "formals are:" << std::endl;
1197 printAll( function->parameters, std::cerr, 8 );
1198 std::cerr << "actuals are:" << std::endl;
1199 printAll( appExpr->args, std::cerr, 8 );
1200 std::cerr << "bindings are:" << std::endl;
1201 withFunc.env.print( std::cerr, 8 );
1202 std::cerr << "cost is: " << withFunc.cost << std::endl;
1203 std::cerr << "cost of conversion is:" << cvtCost << std::endl;
1204 )
1205 if ( cvtCost != Cost::infinity ) {
1206 withFunc.cvtCost = cvtCost;
1207 alternatives.push_back( withFunc );
1208 } // if
1209 } // for
1210
1211 candidates = move(alternatives);
1212
1213 // use a new list so that alternatives are not examined by addAnonConversions twice.
1214 AltList winners;
1215 findMinCost( candidates.begin(), candidates.end(), std::back_inserter( winners ) );
1216
1217 // function may return struct or union value, in which case we need to add alternatives
1218 // for implicitconversions to each of the anonymous members, must happen after findMinCost
1219 // since anon conversions are never the cheapest expression
1220 for ( const Alternative & alt : winners ) {
1221 addAnonConversions( alt );
1222 }
1223 spliceBegin( alternatives, winners );
1224
1225 if ( alternatives.empty() && targetType && ! targetType->isVoid() ) {
1226 // xxx - this is a temporary hack. If resolution is unsuccessful with a target type, try again without a
1227 // target type, since it will sometimes succeed when it wouldn't easily with target type binding. For example,
1228 // forall( otype T ) lvalue T ?[?]( T *, ptrdiff_t );
1229 // const char * x = "hello world";
1230 // unsigned char ch = x[0];
1231 // Fails with simple return type binding. First, T is bound to unsigned char, then (x: const char *) is unified
1232 // with unsigned char *, which fails because pointer base types must be unified exactly. The new resolver should
1233 // fix this issue in a more robust way.
1234 targetType = nullptr;
1235 postvisit( untypedExpr );
1236 }
1237 }
1238
1239 bool isLvalue( Expression *expr ) {
1240 // xxx - recurse into tuples?
1241 return expr->result && ( expr->result->get_lvalue() || dynamic_cast< ReferenceType * >( expr->result ) );
1242 }
1243
1244 void AlternativeFinder::Finder::postvisit( AddressExpr *addressExpr ) {
1245 AlternativeFinder finder( indexer, env );
1246 finder.find( addressExpr->get_arg() );
1247 for ( Alternative& alt : finder.alternatives ) {
1248 if ( isLvalue( alt.expr ) ) {
1249 alternatives.push_back(
1250 Alternative{ new AddressExpr( alt.expr->clone() ), alt.env, alt.cost } );
1251 } // if
1252 } // for
1253 }
1254
1255 void AlternativeFinder::Finder::postvisit( LabelAddressExpr * expr ) {
1256 alternatives.push_back( Alternative{ expr->clone(), env, Cost::zero } );
1257 }
1258
1259 Expression * restructureCast( Expression * argExpr, Type * toType, bool isGenerated ) {
1260 if ( argExpr->get_result()->size() > 1 && ! toType->isVoid() && ! dynamic_cast<ReferenceType *>( toType ) ) {
1261 // Argument expression is a tuple and the target type is not void and not a reference type.
1262 // Cast each member of the tuple to its corresponding target type, producing the tuple of those
1263 // cast expressions. If there are more components of the tuple than components in the target type,
1264 // then excess components do not come out in the result expression (but UniqueExprs ensure that
1265 // side effects will still be done).
1266 if ( Tuples::maybeImpureIgnoreUnique( argExpr ) ) {
1267 // expressions which may contain side effects require a single unique instance of the expression.
1268 argExpr = new UniqueExpr( argExpr );
1269 }
1270 std::list< Expression * > componentExprs;
1271 for ( unsigned int i = 0; i < toType->size(); i++ ) {
1272 // cast each component
1273 TupleIndexExpr * idx = new TupleIndexExpr( argExpr->clone(), i );
1274 componentExprs.push_back( restructureCast( idx, toType->getComponent( i ), isGenerated ) );
1275 }
1276 delete argExpr;
1277 assert( componentExprs.size() > 0 );
1278 // produce the tuple of casts
1279 return new TupleExpr( componentExprs );
1280 } else {
1281 // handle normally
1282 CastExpr * ret = new CastExpr( argExpr, toType->clone() );
1283 ret->isGenerated = isGenerated;
1284 return ret;
1285 }
1286 }
1287
1288 void AlternativeFinder::Finder::postvisit( CastExpr *castExpr ) {
1289 Type *& toType = castExpr->get_result();
1290 assert( toType );
1291 toType = resolveTypeof( toType, indexer );
1292 SymTab::validateType( toType, &indexer );
1293 adjustExprType( toType, env, indexer );
1294
1295 AlternativeFinder finder( indexer, env );
1296 finder.targetType = toType;
1297 finder.findWithAdjustment( castExpr->arg );
1298
1299 AltList candidates;
1300 for ( Alternative & alt : finder.alternatives ) {
1301 AssertionSet needAssertions, haveAssertions;
1302 OpenVarSet openVars;
1303
1304 alt.env.extractOpenVars( openVars );
1305
1306 // It's possible that a cast can throw away some values in a multiply-valued expression. (An example is a
1307 // cast-to-void, which casts from one value to zero.) Figure out the prefix of the subexpression results
1308 // that are cast directly. The candidate is invalid if it has fewer results than there are types to cast
1309 // to.
1310 int discardedValues = alt.expr->result->size() - castExpr->result->size();
1311 if ( discardedValues < 0 ) continue;
1312 // xxx - may need to go into tuple types and extract relevant types and use unifyList. Note that currently, this does not
1313 // allow casting a tuple to an atomic type (e.g. (int)([1, 2, 3]))
1314 // unification run for side-effects
1315 unify( castExpr->result, alt.expr->result, alt.env, needAssertions,
1316 haveAssertions, openVars, indexer );
1317 Cost thisCost = castCost( alt.expr->result, castExpr->result, indexer,
1318 alt.env );
1319 PRINT(
1320 std::cerr << "working on cast with result: " << castExpr->result << std::endl;
1321 std::cerr << "and expr type: " << alt.expr->result << std::endl;
1322 std::cerr << "env: " << alt.env << std::endl;
1323 )
1324 if ( thisCost != Cost::infinity ) {
1325 PRINT(
1326 std::cerr << "has finite cost." << std::endl;
1327 )
1328 // count one safe conversion for each value that is thrown away
1329 thisCost.incSafe( discardedValues );
1330 Alternative newAlt( restructureCast( alt.expr->clone(), toType, castExpr->isGenerated ), alt.env,
1331 alt.cost, thisCost );
1332 inferParameters( needAssertions, haveAssertions, newAlt, openVars,
1333 back_inserter( candidates ) );
1334 } // if
1335 } // for
1336
1337 // findMinCost selects the alternatives with the lowest "cost" members, but has the side effect of copying the
1338 // cvtCost member to the cost member (since the old cost is now irrelevant). Thus, calling findMinCost twice
1339 // selects first based on argument cost, then on conversion cost.
1340 AltList minArgCost;
1341 findMinCost( candidates.begin(), candidates.end(), std::back_inserter( minArgCost ) );
1342 findMinCost( minArgCost.begin(), minArgCost.end(), std::back_inserter( alternatives ) );
1343 }
1344
1345 void AlternativeFinder::Finder::postvisit( VirtualCastExpr * castExpr ) {
1346 assertf( castExpr->get_result(), "Implicate virtual cast targets not yet supported." );
1347 AlternativeFinder finder( indexer, env );
1348 // don't prune here, since it's guaranteed all alternatives will have the same type
1349 finder.findWithoutPrune( castExpr->get_arg() );
1350 for ( Alternative & alt : finder.alternatives ) {
1351 alternatives.push_back( Alternative(
1352 new VirtualCastExpr( alt.expr->clone(), castExpr->get_result()->clone() ),
1353 alt.env, alt.cost ) );
1354 }
1355 }
1356
1357 namespace {
1358 /// Gets name from untyped member expression (member must be NameExpr)
1359 const std::string& get_member_name( UntypedMemberExpr *memberExpr ) {
1360 NameExpr * nameExpr = dynamic_cast< NameExpr * >( memberExpr->get_member() );
1361 assert( nameExpr );
1362 return nameExpr->get_name();
1363 }
1364 }
1365
1366 void AlternativeFinder::Finder::postvisit( UntypedMemberExpr *memberExpr ) {
1367 AlternativeFinder funcFinder( indexer, env );
1368 funcFinder.findWithAdjustment( memberExpr->get_aggregate() );
1369 for ( AltList::const_iterator agg = funcFinder.alternatives.begin(); agg != funcFinder.alternatives.end(); ++agg ) {
1370 // it's okay for the aggregate expression to have reference type -- cast it to the base type to treat the aggregate as the referenced value
1371 Cost cost = agg->cost;
1372 Expression * aggrExpr = agg->expr->clone();
1373 referenceToRvalueConversion( aggrExpr, cost );
1374 std::unique_ptr<Expression> guard( aggrExpr );
1375
1376 // find member of the given type
1377 if ( StructInstType *structInst = dynamic_cast< StructInstType* >( aggrExpr->get_result() ) ) {
1378 addAggMembers( structInst, aggrExpr, cost, agg->env, get_member_name(memberExpr) );
1379 } else if ( UnionInstType *unionInst = dynamic_cast< UnionInstType* >( aggrExpr->get_result() ) ) {
1380 addAggMembers( unionInst, aggrExpr, cost, agg->env, get_member_name(memberExpr) );
1381 } else if ( TupleType * tupleType = dynamic_cast< TupleType * >( aggrExpr->get_result() ) ) {
1382 addTupleMembers( tupleType, aggrExpr, cost, agg->env, memberExpr->get_member() );
1383 } // if
1384 } // for
1385 }
1386
1387 void AlternativeFinder::Finder::postvisit( MemberExpr *memberExpr ) {
1388 alternatives.push_back( Alternative( memberExpr->clone(), env, Cost::zero ) );
1389 }
1390
1391 void AlternativeFinder::Finder::postvisit( NameExpr *nameExpr ) {
1392 std::list< SymTab::Indexer::IdData > declList;
1393 indexer.lookupId( nameExpr->name, declList );
1394 PRINT( std::cerr << "nameExpr is " << nameExpr->name << std::endl; )
1395 for ( auto & data : declList ) {
1396 Cost cost = Cost::zero;
1397 Expression * newExpr = data.combine( cost );
1398
1399 // addAnonAlternatives uses vector::push_back, which invalidates references to existing elements, so
1400 // can't construct in place and use vector::back
1401 Alternative newAlt( newExpr, env, Cost::zero, cost );
1402 PRINT(
1403 std::cerr << "decl is ";
1404 data.id->print( std::cerr );
1405 std::cerr << std::endl;
1406 std::cerr << "newExpr is ";
1407 newExpr->print( std::cerr );
1408 std::cerr << std::endl;
1409 )
1410 renameTypes( newAlt.expr );
1411 addAnonConversions( newAlt ); // add anonymous member interpretations whenever an aggregate value type is seen as a name expression.
1412 alternatives.push_back( std::move(newAlt) );
1413 } // for
1414 }
1415
1416 void AlternativeFinder::Finder::postvisit( VariableExpr *variableExpr ) {
1417 // not sufficient to clone here, because variable's type may have changed
1418 // since the VariableExpr was originally created.
1419 alternatives.push_back( Alternative( new VariableExpr( variableExpr->var ), env, Cost::zero ) );
1420 }
1421
1422 void AlternativeFinder::Finder::postvisit( ConstantExpr *constantExpr ) {
1423 alternatives.push_back( Alternative( constantExpr->clone(), env, Cost::zero ) );
1424 }
1425
1426 void AlternativeFinder::Finder::postvisit( SizeofExpr *sizeofExpr ) {
1427 if ( sizeofExpr->get_isType() ) {
1428 Type * newType = sizeofExpr->get_type()->clone();
1429 alternatives.push_back( Alternative( new SizeofExpr( resolveTypeof( newType, indexer ) ), env, Cost::zero ) );
1430 } else {
1431 // find all alternatives for the argument to sizeof
1432 AlternativeFinder finder( indexer, env );
1433 finder.find( sizeofExpr->get_expr() );
1434 // find the lowest cost alternative among the alternatives, otherwise ambiguous
1435 AltList winners;
1436 findMinCost( finder.alternatives.begin(), finder.alternatives.end(), back_inserter( winners ) );
1437 if ( winners.size() != 1 ) {
1438 SemanticError( sizeofExpr->get_expr(), "Ambiguous expression in sizeof operand: " );
1439 } // if
1440 // return the lowest cost alternative for the argument
1441 Alternative &choice = winners.front();
1442 referenceToRvalueConversion( choice.expr, choice.cost );
1443 alternatives.push_back( Alternative( new SizeofExpr( choice.expr->clone() ), choice.env, Cost::zero ) );
1444 } // if
1445 }
1446
1447 void AlternativeFinder::Finder::postvisit( AlignofExpr *alignofExpr ) {
1448 if ( alignofExpr->get_isType() ) {
1449 Type * newType = alignofExpr->get_type()->clone();
1450 alternatives.push_back( Alternative( new AlignofExpr( resolveTypeof( newType, indexer ) ), env, Cost::zero ) );
1451 } else {
1452 // find all alternatives for the argument to sizeof
1453 AlternativeFinder finder( indexer, env );
1454 finder.find( alignofExpr->get_expr() );
1455 // find the lowest cost alternative among the alternatives, otherwise ambiguous
1456 AltList winners;
1457 findMinCost( finder.alternatives.begin(), finder.alternatives.end(), back_inserter( winners ) );
1458 if ( winners.size() != 1 ) {
1459 SemanticError( alignofExpr->get_expr(), "Ambiguous expression in alignof operand: " );
1460 } // if
1461 // return the lowest cost alternative for the argument
1462 Alternative &choice = winners.front();
1463 referenceToRvalueConversion( choice.expr, choice.cost );
1464 alternatives.push_back( Alternative( new AlignofExpr( choice.expr->clone() ), choice.env, Cost::zero ) );
1465 } // if
1466 }
1467
1468 template< typename StructOrUnionType >
1469 void AlternativeFinder::Finder::addOffsetof( StructOrUnionType *aggInst, const std::string &name ) {
1470 std::list< Declaration* > members;
1471 aggInst->lookup( name, members );
1472 for ( std::list< Declaration* >::const_iterator i = members.begin(); i != members.end(); ++i ) {
1473 if ( DeclarationWithType *dwt = dynamic_cast< DeclarationWithType* >( *i ) ) {
1474 alternatives.push_back( Alternative( new OffsetofExpr( aggInst->clone(), dwt ), env, Cost::zero ) );
1475 renameTypes( alternatives.back().expr );
1476 } else {
1477 assert( false );
1478 }
1479 }
1480 }
1481
1482 void AlternativeFinder::Finder::postvisit( UntypedOffsetofExpr *offsetofExpr ) {
1483 AlternativeFinder funcFinder( indexer, env );
1484 // xxx - resolveTypeof?
1485 if ( StructInstType *structInst = dynamic_cast< StructInstType* >( offsetofExpr->get_type() ) ) {
1486 addOffsetof( structInst, offsetofExpr->member );
1487 } else if ( UnionInstType *unionInst = dynamic_cast< UnionInstType* >( offsetofExpr->get_type() ) ) {
1488 addOffsetof( unionInst, offsetofExpr->member );
1489 }
1490 }
1491
1492 void AlternativeFinder::Finder::postvisit( OffsetofExpr *offsetofExpr ) {
1493 alternatives.push_back( Alternative( offsetofExpr->clone(), env, Cost::zero ) );
1494 }
1495
1496 void AlternativeFinder::Finder::postvisit( OffsetPackExpr *offsetPackExpr ) {
1497 alternatives.push_back( Alternative( offsetPackExpr->clone(), env, Cost::zero ) );
1498 }
1499
1500 namespace {
1501 void resolveAttr( SymTab::Indexer::IdData data, FunctionType *function, Type *argType, const TypeEnvironment &env, AlternativeFinder & finder ) {
1502 // assume no polymorphism
1503 // assume no implicit conversions
1504 assert( function->get_parameters().size() == 1 );
1505 PRINT(
1506 std::cerr << "resolvAttr: funcDecl is ";
1507 data.id->print( std::cerr );
1508 std::cerr << " argType is ";
1509 argType->print( std::cerr );
1510 std::cerr << std::endl;
1511 )
1512 const SymTab::Indexer & indexer = finder.get_indexer();
1513 AltList & alternatives = finder.get_alternatives();
1514 if ( typesCompatibleIgnoreQualifiers( argType, function->get_parameters().front()->get_type(), indexer, env ) ) {
1515 Cost cost = Cost::zero;
1516 Expression * newExpr = data.combine( cost );
1517 alternatives.push_back( Alternative( new AttrExpr( newExpr, argType->clone() ), env, Cost::zero, cost ) );
1518 for ( DeclarationWithType * retVal : function->returnVals ) {
1519 alternatives.back().expr->result = retVal->get_type()->clone();
1520 } // for
1521 } // if
1522 }
1523 }
1524
1525 void AlternativeFinder::Finder::postvisit( AttrExpr *attrExpr ) {
1526 // assume no 'pointer-to-attribute'
1527 NameExpr *nameExpr = dynamic_cast< NameExpr* >( attrExpr->get_attr() );
1528 assert( nameExpr );
1529 std::list< SymTab::Indexer::IdData > attrList;
1530 indexer.lookupId( nameExpr->get_name(), attrList );
1531 if ( attrExpr->get_isType() || attrExpr->get_expr() ) {
1532 for ( auto & data : attrList ) {
1533 DeclarationWithType * id = data.id;
1534 // check if the type is function
1535 if ( FunctionType *function = dynamic_cast< FunctionType* >( id->get_type() ) ) {
1536 // assume exactly one parameter
1537 if ( function->get_parameters().size() == 1 ) {
1538 if ( attrExpr->get_isType() ) {
1539 resolveAttr( data, function, attrExpr->get_type(), env, altFinder);
1540 } else {
1541 AlternativeFinder finder( indexer, env );
1542 finder.find( attrExpr->get_expr() );
1543 for ( AltList::iterator choice = finder.alternatives.begin(); choice != finder.alternatives.end(); ++choice ) {
1544 if ( choice->expr->get_result()->size() == 1 ) {
1545 resolveAttr(data, function, choice->expr->get_result(), choice->env, altFinder );
1546 } // fi
1547 } // for
1548 } // if
1549 } // if
1550 } // if
1551 } // for
1552 } else {
1553 for ( auto & data : attrList ) {
1554 Cost cost = Cost::zero;
1555 Expression * newExpr = data.combine( cost );
1556 alternatives.push_back( Alternative( newExpr, env, Cost::zero, cost ) );
1557 renameTypes( alternatives.back().expr );
1558 } // for
1559 } // if
1560 }
1561
1562 void AlternativeFinder::Finder::postvisit( LogicalExpr *logicalExpr ) {
1563 AlternativeFinder firstFinder( indexer, env );
1564 firstFinder.findWithAdjustment( logicalExpr->get_arg1() );
1565 if ( firstFinder.alternatives.empty() ) return;
1566 AlternativeFinder secondFinder( indexer, env );
1567 secondFinder.findWithAdjustment( logicalExpr->get_arg2() );
1568 if ( secondFinder.alternatives.empty() ) return;
1569 for ( const Alternative & first : firstFinder.alternatives ) {
1570 for ( const Alternative & second : secondFinder.alternatives ) {
1571 TypeEnvironment compositeEnv;
1572 compositeEnv.simpleCombine( first.env );
1573 compositeEnv.simpleCombine( second.env );
1574
1575 LogicalExpr *newExpr = new LogicalExpr( first.expr->clone(), second.expr->clone(), logicalExpr->get_isAnd() );
1576 alternatives.push_back( Alternative( newExpr, compositeEnv, first.cost + second.cost ) );
1577 }
1578 }
1579 }
1580
1581 void AlternativeFinder::Finder::postvisit( ConditionalExpr *conditionalExpr ) {
1582 // find alternatives for condition
1583 AlternativeFinder firstFinder( indexer, env );
1584 firstFinder.findWithAdjustment( conditionalExpr->arg1 );
1585 if ( firstFinder.alternatives.empty() ) return;
1586 // find alternatives for true expression
1587 AlternativeFinder secondFinder( indexer, env );
1588 secondFinder.findWithAdjustment( conditionalExpr->arg2 );
1589 if ( secondFinder.alternatives.empty() ) return;
1590 // find alterantives for false expression
1591 AlternativeFinder thirdFinder( indexer, env );
1592 thirdFinder.findWithAdjustment( conditionalExpr->arg3 );
1593 if ( thirdFinder.alternatives.empty() ) return;
1594 for ( const Alternative & first : firstFinder.alternatives ) {
1595 for ( const Alternative & second : secondFinder.alternatives ) {
1596 for ( const Alternative & third : thirdFinder.alternatives ) {
1597 TypeEnvironment compositeEnv;
1598 compositeEnv.simpleCombine( first.env );
1599 compositeEnv.simpleCombine( second.env );
1600 compositeEnv.simpleCombine( third.env );
1601
1602 // unify true and false types, then infer parameters to produce new alternatives
1603 OpenVarSet openVars;
1604 AssertionSet needAssertions, haveAssertions;
1605 Alternative newAlt( 0, compositeEnv, first.cost + second.cost + third.cost );
1606 Type* commonType = nullptr;
1607 if ( unify( second.expr->result, third.expr->result, newAlt.env, needAssertions, haveAssertions, openVars, indexer, commonType ) ) {
1608 ConditionalExpr *newExpr = new ConditionalExpr( first.expr->clone(), second.expr->clone(), third.expr->clone() );
1609 newExpr->result = commonType ? commonType : second.expr->result->clone();
1610 // convert both options to the conditional result type
1611 newAlt.cost += computeExpressionConversionCost( newExpr->arg2, newExpr->result, indexer, newAlt.env );
1612 newAlt.cost += computeExpressionConversionCost( newExpr->arg3, newExpr->result, indexer, newAlt.env );
1613 newAlt.expr = newExpr;
1614 inferParameters( needAssertions, haveAssertions, newAlt, openVars, back_inserter( alternatives ) );
1615 } // if
1616 } // for
1617 } // for
1618 } // for
1619 }
1620
1621 void AlternativeFinder::Finder::postvisit( CommaExpr *commaExpr ) {
1622 TypeEnvironment newEnv( env );
1623 Expression *newFirstArg = resolveInVoidContext( commaExpr->get_arg1(), indexer, newEnv );
1624 AlternativeFinder secondFinder( indexer, newEnv );
1625 secondFinder.findWithAdjustment( commaExpr->get_arg2() );
1626 for ( const Alternative & alt : secondFinder.alternatives ) {
1627 alternatives.push_back( Alternative( new CommaExpr( newFirstArg->clone(), alt.expr->clone() ), alt.env, alt.cost ) );
1628 } // for
1629 delete newFirstArg;
1630 }
1631
1632 void AlternativeFinder::Finder::postvisit( RangeExpr * rangeExpr ) {
1633 // resolve low and high, accept alternatives whose low and high types unify
1634 AlternativeFinder firstFinder( indexer, env );
1635 firstFinder.findWithAdjustment( rangeExpr->low );
1636 if ( firstFinder.alternatives.empty() ) return;
1637 AlternativeFinder secondFinder( indexer, env );
1638 secondFinder.findWithAdjustment( rangeExpr->high );
1639 if ( secondFinder.alternatives.empty() ) return;
1640 for ( const Alternative & first : firstFinder.alternatives ) {
1641 for ( const Alternative & second : secondFinder.alternatives ) {
1642 TypeEnvironment compositeEnv;
1643 compositeEnv.simpleCombine( first.env );
1644 compositeEnv.simpleCombine( second.env );
1645 OpenVarSet openVars;
1646 AssertionSet needAssertions, haveAssertions;
1647 Alternative newAlt( 0, compositeEnv, first.cost + second.cost );
1648 Type* commonType = nullptr;
1649 if ( unify( first.expr->result, second.expr->result, newAlt.env, needAssertions, haveAssertions, openVars, indexer, commonType ) ) {
1650 RangeExpr * newExpr = new RangeExpr( first.expr->clone(), second.expr->clone() );
1651 newExpr->result = commonType ? commonType : first.expr->result->clone();
1652 newAlt.expr = newExpr;
1653 inferParameters( needAssertions, haveAssertions, newAlt, openVars, back_inserter( alternatives ) );
1654 } // if
1655 } // for
1656 } // for
1657 }
1658
1659 void AlternativeFinder::Finder::postvisit( UntypedTupleExpr *tupleExpr ) {
1660 std::vector< AlternativeFinder > subExprAlternatives;
1661 altFinder.findSubExprs( tupleExpr->get_exprs().begin(), tupleExpr->get_exprs().end(),
1662 back_inserter( subExprAlternatives ) );
1663 std::vector< AltList > possibilities;
1664 combos( subExprAlternatives.begin(), subExprAlternatives.end(),
1665 back_inserter( possibilities ) );
1666 for ( const AltList& alts : possibilities ) {
1667 std::list< Expression * > exprs;
1668 makeExprList( alts, exprs );
1669
1670 TypeEnvironment compositeEnv;
1671 simpleCombineEnvironments( alts.begin(), alts.end(), compositeEnv );
1672 alternatives.push_back(
1673 Alternative{ new TupleExpr( exprs ), compositeEnv, sumCost( alts ) } );
1674 } // for
1675 }
1676
1677 void AlternativeFinder::Finder::postvisit( TupleExpr *tupleExpr ) {
1678 alternatives.push_back( Alternative( tupleExpr->clone(), env, Cost::zero ) );
1679 }
1680
1681 void AlternativeFinder::Finder::postvisit( ImplicitCopyCtorExpr * impCpCtorExpr ) {
1682 alternatives.push_back( Alternative( impCpCtorExpr->clone(), env, Cost::zero ) );
1683 }
1684
1685 void AlternativeFinder::Finder::postvisit( ConstructorExpr * ctorExpr ) {
1686 AlternativeFinder finder( indexer, env );
1687 // don't prune here, since it's guaranteed all alternatives will have the same type
1688 // (giving the alternatives different types is half of the point of ConstructorExpr nodes)
1689 finder.findWithoutPrune( ctorExpr->get_callExpr() );
1690 for ( Alternative & alt : finder.alternatives ) {
1691 alternatives.push_back( Alternative( new ConstructorExpr( alt.expr->clone() ), alt.env, alt.cost ) );
1692 }
1693 }
1694
1695 void AlternativeFinder::Finder::postvisit( TupleIndexExpr *tupleExpr ) {
1696 alternatives.push_back( Alternative( tupleExpr->clone(), env, Cost::zero ) );
1697 }
1698
1699 void AlternativeFinder::Finder::postvisit( TupleAssignExpr *tupleAssignExpr ) {
1700 alternatives.push_back( Alternative( tupleAssignExpr->clone(), env, Cost::zero ) );
1701 }
1702
1703 void AlternativeFinder::Finder::postvisit( UniqueExpr *unqExpr ) {
1704 AlternativeFinder finder( indexer, env );
1705 finder.findWithAdjustment( unqExpr->get_expr() );
1706 for ( Alternative & alt : finder.alternatives ) {
1707 // ensure that the id is passed on to the UniqueExpr alternative so that the expressions are "linked"
1708 UniqueExpr * newUnqExpr = new UniqueExpr( alt.expr->clone(), unqExpr->get_id() );
1709 alternatives.push_back( Alternative( newUnqExpr, alt.env, alt.cost ) );
1710 }
1711 }
1712
1713 void AlternativeFinder::Finder::postvisit( StmtExpr *stmtExpr ) {
1714 StmtExpr * newStmtExpr = stmtExpr->clone();
1715 ResolvExpr::resolveStmtExpr( newStmtExpr, indexer );
1716 // xxx - this env is almost certainly wrong, and needs to somehow contain the combined environments from all of the statements in the stmtExpr...
1717 alternatives.push_back( Alternative( newStmtExpr, env, Cost::zero ) );
1718 }
1719
1720 void AlternativeFinder::Finder::postvisit( UntypedInitExpr *initExpr ) {
1721 // handle each option like a cast
1722 AltList candidates;
1723 PRINT(
1724 std::cerr << "untyped init expr: " << initExpr << std::endl;
1725 )
1726 // O(N^2) checks of d-types with e-types
1727 for ( InitAlternative & initAlt : initExpr->get_initAlts() ) {
1728 Type * toType = resolveTypeof( initAlt.type->clone(), indexer );
1729 SymTab::validateType( toType, &indexer );
1730 adjustExprType( toType, env, indexer );
1731 // Ideally the call to findWithAdjustment could be moved out of the loop, but unfortunately it currently has to occur inside or else
1732 // polymorphic return types are not properly bound to the initialization type, since return type variables are only open for the duration of resolving
1733 // the UntypedExpr. This is only actually an issue in initialization contexts that allow more than one possible initialization type, but it is still suboptimal.
1734 AlternativeFinder finder( indexer, env );
1735 finder.targetType = toType;
1736 finder.findWithAdjustment( initExpr->expr );
1737 for ( Alternative & alt : finder.get_alternatives() ) {
1738 TypeEnvironment newEnv( alt.env );
1739 AssertionSet needAssertions, haveAssertions;
1740 OpenVarSet openVars; // find things in env that don't have a "representative type" and claim those are open vars?
1741 PRINT(
1742 std::cerr << " @ " << toType << " " << initAlt.designation << std::endl;
1743 )
1744 // It's possible that a cast can throw away some values in a multiply-valued expression. (An example is a
1745 // cast-to-void, which casts from one value to zero.) Figure out the prefix of the subexpression results
1746 // that are cast directly. The candidate is invalid if it has fewer results than there are types to cast
1747 // to.
1748 int discardedValues = alt.expr->result->size() - toType->size();
1749 if ( discardedValues < 0 ) continue;
1750 // xxx - may need to go into tuple types and extract relevant types and use unifyList. Note that currently, this does not
1751 // allow casting a tuple to an atomic type (e.g. (int)([1, 2, 3]))
1752 // unification run for side-effects
1753 unify( toType, alt.expr->result, newEnv, needAssertions, haveAssertions, openVars, indexer ); // xxx - do some inspecting on this line... why isn't result bound to initAlt.type??
1754
1755 Cost thisCost = castCost( alt.expr->result, toType, indexer, newEnv );
1756 if ( thisCost != Cost::infinity ) {
1757 // count one safe conversion for each value that is thrown away
1758 thisCost.incSafe( discardedValues );
1759 Alternative newAlt( new InitExpr( restructureCast( alt.expr->clone(), toType, true ), initAlt.designation->clone() ), newEnv, alt.cost, thisCost );
1760 inferParameters( needAssertions, haveAssertions, newAlt, openVars, back_inserter( candidates ) );
1761 }
1762 }
1763 }
1764
1765 // findMinCost selects the alternatives with the lowest "cost" members, but has the side effect of copying the
1766 // cvtCost member to the cost member (since the old cost is now irrelevant). Thus, calling findMinCost twice
1767 // selects first based on argument cost, then on conversion cost.
1768 AltList minArgCost;
1769 findMinCost( candidates.begin(), candidates.end(), std::back_inserter( minArgCost ) );
1770 findMinCost( minArgCost.begin(), minArgCost.end(), std::back_inserter( alternatives ) );
1771 }
1772
1773 void AlternativeFinder::Finder::postvisit( InitExpr * ) {
1774 assertf( false, "AlternativeFinder should never see a resolved InitExpr." );
1775 }
1776
1777 void AlternativeFinder::Finder::postvisit( DeletedExpr * ) {
1778 assertf( false, "AlternativeFinder should never see a DeletedExpr." );
1779 }
1780
1781 void AlternativeFinder::Finder::postvisit( GenericExpr * ) {
1782 assertf( false, "_Generic is not yet supported." );
1783 }
1784} // namespace ResolvExpr
1785
1786// Local Variables: //
1787// tab-width: 4 //
1788// mode: c++ //
1789// compile-command: "make install" //
1790// End: //
Note: See TracBrowser for help on using the repository browser.