source: src/ResolvExpr/AlternativeFinder.cc@ 184557e

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

Merge remote-tracking branch 'origin/with_gc' into new-env

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