source: src/ResolvExpr/AlternativeFinder.cc@ 97397a26

new-env
Last change on this file since 97397a26 was 97397a26, checked in by Aaron Moss <a3moss@…>, 7 years ago

Merge branch 'with_gc' into new-env

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