source: src/ResolvExpr/AlternativeFinder.cc@ cb7caf8

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

Add AST support for _Generic, along with C codegen

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