source: src/ResolvExpr/AlternativeFinder.cc@ 41e16b1

ADT aaron-thesis arm-eh ast-experimental cleanup-dtors deferred_resn demangler enum forall-pointer-decay jacob/cs343-translation jenkins-sandbox new-ast new-ast-unique-expr new-env no_list persistent-indexer pthread-emulation qualifiedEnum with_gc
Last change on this file since 41e16b1 was 5de1e2c, checked in by Rob Schluntz <rschlunt@…>, 7 years ago

Fix memory error from caused by vector::push_back [fixes #90]

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