source: src/ResolvExpr/AlternativeFinder.cc@ 04cccaf

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 no_list persistent-indexer pthread-emulation qualifiedEnum
Last change on this file since 04cccaf was 04cccaf, checked in by Rob Schluntz <rschlunt@…>, 7 years ago

Terminate assertion resolution early if alternative has infinite cost

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