source: src/ResolvExpr/AlternativeFinder.cc@ 9160cb2

new-env
Last change on this file since 9160cb2 was 9160cb2, checked in by Aaron Moss <a3moss@…>, 8 years ago

Breadth-first assertion resolution builds, eats all the memory

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