1 | // |
---|
2 | // Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo |
---|
3 | // |
---|
4 | // The contents of this file are covered under the licence agreement in the |
---|
5 | // file "LICENCE" distributed with Cforall. |
---|
6 | // |
---|
7 | // AlternativeFinder.cc -- |
---|
8 | // |
---|
9 | // Author : Richard C. Bilson |
---|
10 | // Created On : Sat May 16 23:52:08 2015 |
---|
11 | // Last Modified By : Peter A. Buhr |
---|
12 | // Last Modified On : Mon Aug 28 13:47:24 2017 |
---|
13 | // Update Count : 32 |
---|
14 | // |
---|
15 | |
---|
16 | #include <algorithm> // for copy |
---|
17 | #include <cassert> // for strict_dynamic_cast, assert, assertf |
---|
18 | #include <iostream> // for operator<<, cerr, ostream, endl |
---|
19 | #include <iterator> // for back_insert_iterator, back_inserter |
---|
20 | #include <list> // for _List_iterator, list, _List_const_... |
---|
21 | #include <map> // for _Rb_tree_iterator, map, _Rb_tree_c... |
---|
22 | #include <memory> // for allocator_traits<>::value_type |
---|
23 | #include <utility> // for pair |
---|
24 | |
---|
25 | #include "Alternative.h" // for AltList, Alternative |
---|
26 | #include "AlternativeFinder.h" |
---|
27 | #include "Common/SemanticError.h" // for SemanticError |
---|
28 | #include "Common/utility.h" // for deleteAll, printAll, CodeLocation |
---|
29 | #include "Cost.h" // for Cost, Cost::zero, operator<<, Cost... |
---|
30 | #include "InitTweak/InitTweak.h" // for getFunctionName |
---|
31 | #include "RenameVars.h" // for RenameVars, global_renamer |
---|
32 | #include "ResolveTypeof.h" // for resolveTypeof |
---|
33 | #include "Resolver.h" // for resolveStmtExpr |
---|
34 | #include "SymTab/Indexer.h" // for Indexer |
---|
35 | #include "SymTab/Mangler.h" // for Mangler |
---|
36 | #include "SymTab/Validate.h" // for validateType |
---|
37 | #include "SynTree/Constant.h" // for Constant |
---|
38 | #include "SynTree/Declaration.h" // for DeclarationWithType, TypeDecl, Dec... |
---|
39 | #include "SynTree/Expression.h" // for Expression, CastExpr, NameExpr |
---|
40 | #include "SynTree/Initializer.h" // for SingleInit, operator<<, Designation |
---|
41 | #include "SynTree/SynTree.h" // for UniqueId |
---|
42 | #include "SynTree/Type.h" // for Type, FunctionType, PointerType |
---|
43 | #include "Tuples/Explode.h" // for explode |
---|
44 | #include "Tuples/Tuples.h" // for isTtype, handleTupleAssignment |
---|
45 | #include "Unify.h" // for unify |
---|
46 | #include "typeops.h" // for adjustExprType, polyCost, castCost |
---|
47 | |
---|
48 | extern bool resolvep; |
---|
49 | #define PRINT( text ) if ( resolvep ) { text } |
---|
50 | //#define DEBUG_COST |
---|
51 | |
---|
52 | namespace ResolvExpr { |
---|
53 | Expression *resolveInVoidContext( Expression *expr, const SymTab::Indexer &indexer, TypeEnvironment &env ) { |
---|
54 | CastExpr *castToVoid = new CastExpr( expr ); |
---|
55 | |
---|
56 | AlternativeFinder finder( indexer, env ); |
---|
57 | finder.findWithAdjustment( castToVoid ); |
---|
58 | |
---|
59 | // it's a property of the language that a cast expression has either 1 or 0 interpretations; if it has 0 |
---|
60 | // interpretations, an exception has already been thrown. |
---|
61 | assert( finder.get_alternatives().size() == 1 ); |
---|
62 | CastExpr *newExpr = dynamic_cast< CastExpr* >( finder.get_alternatives().front().expr ); |
---|
63 | assert( newExpr ); |
---|
64 | env = finder.get_alternatives().front().env; |
---|
65 | return newExpr->get_arg()->clone(); |
---|
66 | } |
---|
67 | |
---|
68 | Cost sumCost( const AltList &in ) { |
---|
69 | Cost total = Cost::zero; |
---|
70 | for ( AltList::const_iterator i = in.begin(); i != in.end(); ++i ) { |
---|
71 | total += i->cost; |
---|
72 | } |
---|
73 | return total; |
---|
74 | } |
---|
75 | |
---|
76 | namespace { |
---|
77 | void printAlts( const AltList &list, std::ostream &os, unsigned int indentAmt = 0 ) { |
---|
78 | Indenter indent = { Indenter::tabsize, indentAmt }; |
---|
79 | for ( AltList::const_iterator i = list.begin(); i != list.end(); ++i ) { |
---|
80 | i->print( os, indent ); |
---|
81 | os << std::endl; |
---|
82 | } |
---|
83 | } |
---|
84 | |
---|
85 | void makeExprList( const AltList &in, std::list< Expression* > &out ) { |
---|
86 | for ( AltList::const_iterator i = in.begin(); i != in.end(); ++i ) { |
---|
87 | out.push_back( i->expr->clone() ); |
---|
88 | } |
---|
89 | } |
---|
90 | |
---|
91 | struct PruneStruct { |
---|
92 | bool isAmbiguous; |
---|
93 | AltList::iterator candidate; |
---|
94 | PruneStruct() {} |
---|
95 | PruneStruct( AltList::iterator candidate ): isAmbiguous( false ), candidate( candidate ) {} |
---|
96 | }; |
---|
97 | |
---|
98 | /// Prunes a list of alternatives down to those that have the minimum conversion cost for a given return type; skips ambiguous interpretations |
---|
99 | template< typename InputIterator, typename OutputIterator > |
---|
100 | void pruneAlternatives( InputIterator begin, InputIterator end, OutputIterator out ) { |
---|
101 | // select the alternatives that have the minimum conversion cost for a particular set of result types |
---|
102 | std::map< std::string, PruneStruct > selected; |
---|
103 | for ( AltList::iterator candidate = begin; candidate != end; ++candidate ) { |
---|
104 | PruneStruct current( candidate ); |
---|
105 | std::string mangleName; |
---|
106 | { |
---|
107 | Type * newType = candidate->expr->get_result()->clone(); |
---|
108 | candidate->env.apply( newType ); |
---|
109 | mangleName = SymTab::Mangler::mangle( newType ); |
---|
110 | delete newType; |
---|
111 | } |
---|
112 | std::map< std::string, PruneStruct >::iterator mapPlace = selected.find( mangleName ); |
---|
113 | if ( mapPlace != selected.end() ) { |
---|
114 | if ( candidate->cost < mapPlace->second.candidate->cost ) { |
---|
115 | PRINT( |
---|
116 | std::cerr << "cost " << candidate->cost << " beats " << mapPlace->second.candidate->cost << std::endl; |
---|
117 | ) |
---|
118 | selected[ mangleName ] = current; |
---|
119 | } else if ( candidate->cost == mapPlace->second.candidate->cost ) { |
---|
120 | PRINT( |
---|
121 | std::cerr << "marking ambiguous" << std::endl; |
---|
122 | ) |
---|
123 | mapPlace->second.isAmbiguous = true; |
---|
124 | } else { |
---|
125 | PRINT( |
---|
126 | std::cerr << "cost " << candidate->cost << " loses to " << mapPlace->second.candidate->cost << std::endl; |
---|
127 | ) |
---|
128 | } |
---|
129 | } else { |
---|
130 | selected[ mangleName ] = current; |
---|
131 | } |
---|
132 | } |
---|
133 | |
---|
134 | // accept the alternatives that were unambiguous |
---|
135 | for ( std::map< std::string, PruneStruct >::iterator target = selected.begin(); target != selected.end(); ++target ) { |
---|
136 | if ( ! target->second.isAmbiguous ) { |
---|
137 | Alternative &alt = *target->second.candidate; |
---|
138 | alt.env.applyFree( alt.expr->get_result() ); |
---|
139 | *out++ = alt; |
---|
140 | } |
---|
141 | } |
---|
142 | } |
---|
143 | |
---|
144 | void renameTypes( Expression *expr ) { |
---|
145 | expr->get_result()->accept( global_renamer ); |
---|
146 | } |
---|
147 | } // namespace |
---|
148 | |
---|
149 | void referenceToRvalueConversion( Expression *& expr ) { |
---|
150 | if ( dynamic_cast< ReferenceType * >( expr->get_result() ) ) { |
---|
151 | // cast away reference from expr |
---|
152 | expr = new CastExpr( expr, expr->get_result()->stripReferences()->clone() ); |
---|
153 | } |
---|
154 | } |
---|
155 | |
---|
156 | template< typename InputIterator, typename OutputIterator > |
---|
157 | void AlternativeFinder::findSubExprs( InputIterator begin, InputIterator end, OutputIterator out ) { |
---|
158 | while ( begin != end ) { |
---|
159 | AlternativeFinder finder( indexer, env ); |
---|
160 | finder.findWithAdjustment( *begin ); |
---|
161 | // XXX either this |
---|
162 | //Designators::fixDesignations( finder, (*begin++)->get_argName() ); |
---|
163 | // or XXX this |
---|
164 | begin++; |
---|
165 | PRINT( |
---|
166 | std::cerr << "findSubExprs" << std::endl; |
---|
167 | printAlts( finder.alternatives, std::cerr ); |
---|
168 | ) |
---|
169 | *out++ = finder; |
---|
170 | } |
---|
171 | } |
---|
172 | |
---|
173 | AlternativeFinder::AlternativeFinder( const SymTab::Indexer &indexer, const TypeEnvironment &env ) |
---|
174 | : indexer( indexer ), env( env ) { |
---|
175 | } |
---|
176 | |
---|
177 | void AlternativeFinder::find( Expression *expr, bool adjust, bool prune, bool failFast ) { |
---|
178 | expr->accept( *this ); |
---|
179 | if ( failFast && alternatives.empty() ) { |
---|
180 | throw SemanticError( "No reasonable alternatives for expression ", expr ); |
---|
181 | } |
---|
182 | if ( prune ) { |
---|
183 | auto oldsize = alternatives.size(); |
---|
184 | PRINT( |
---|
185 | std::cerr << "alternatives before prune:" << std::endl; |
---|
186 | printAlts( alternatives, std::cerr ); |
---|
187 | ) |
---|
188 | AltList::iterator oldBegin = alternatives.begin(); |
---|
189 | pruneAlternatives( alternatives.begin(), alternatives.end(), front_inserter( alternatives ) ); |
---|
190 | if ( failFast && alternatives.begin() == oldBegin ) { |
---|
191 | std::ostringstream stream; |
---|
192 | AltList winners; |
---|
193 | findMinCost( alternatives.begin(), alternatives.end(), back_inserter( winners ) ); |
---|
194 | stream << "Cannot choose between " << winners.size() << " alternatives for expression\n"; |
---|
195 | expr->print( stream ); |
---|
196 | stream << "Alternatives are:\n"; |
---|
197 | printAlts( winners, stream, 1 ); |
---|
198 | throw SemanticError( stream.str() ); |
---|
199 | } |
---|
200 | alternatives.erase( oldBegin, alternatives.end() ); |
---|
201 | PRINT( |
---|
202 | std::cerr << "there are " << oldsize << " alternatives before elimination" << std::endl; |
---|
203 | ) |
---|
204 | PRINT( |
---|
205 | std::cerr << "there are " << alternatives.size() << " alternatives after elimination" << std::endl; |
---|
206 | ) |
---|
207 | } |
---|
208 | // adjust types after pruning so that types substituted by pruneAlternatives are correctly adjusted |
---|
209 | for ( AltList::iterator i = alternatives.begin(); i != alternatives.end(); ++i ) { |
---|
210 | if ( adjust ) { |
---|
211 | adjustExprType( i->expr->get_result(), i->env, indexer ); |
---|
212 | } |
---|
213 | } |
---|
214 | |
---|
215 | // Central location to handle gcc extension keyword, etc. for all expression types. |
---|
216 | for ( Alternative &iter: alternatives ) { |
---|
217 | iter.expr->set_extension( expr->get_extension() ); |
---|
218 | iter.expr->location = expr->location; |
---|
219 | } // for |
---|
220 | } |
---|
221 | |
---|
222 | void AlternativeFinder::findWithAdjustment( Expression *expr ) { |
---|
223 | find( expr, true ); |
---|
224 | } |
---|
225 | |
---|
226 | void AlternativeFinder::findWithoutPrune( Expression * expr ) { |
---|
227 | find( expr, true, false ); |
---|
228 | } |
---|
229 | |
---|
230 | void AlternativeFinder::maybeFind( Expression * expr ) { |
---|
231 | find( expr, true, true, false ); |
---|
232 | } |
---|
233 | |
---|
234 | void AlternativeFinder::addAnonConversions( const Alternative & alt ) { |
---|
235 | // adds anonymous member interpretations whenever an aggregate value type is seen. |
---|
236 | // 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 |
---|
237 | std::unique_ptr<Expression> aggrExpr( alt.expr->clone() ); |
---|
238 | alt.env.apply( aggrExpr->get_result() ); |
---|
239 | Type * aggrType = aggrExpr->get_result(); |
---|
240 | if ( dynamic_cast< ReferenceType * >( aggrType ) ) { |
---|
241 | aggrType = aggrType->stripReferences(); |
---|
242 | aggrExpr.reset( new CastExpr( aggrExpr.release(), aggrType->clone() ) ); |
---|
243 | } |
---|
244 | |
---|
245 | if ( StructInstType *structInst = dynamic_cast< StructInstType* >( aggrExpr->get_result() ) ) { |
---|
246 | NameExpr nameExpr( "" ); |
---|
247 | addAggMembers( structInst, aggrExpr.get(), alt.cost+Cost::safe, alt.env, &nameExpr ); |
---|
248 | } else if ( UnionInstType *unionInst = dynamic_cast< UnionInstType* >( aggrExpr->get_result() ) ) { |
---|
249 | NameExpr nameExpr( "" ); |
---|
250 | addAggMembers( unionInst, aggrExpr.get(), alt.cost+Cost::safe, alt.env, &nameExpr ); |
---|
251 | } // if |
---|
252 | } |
---|
253 | |
---|
254 | template< typename StructOrUnionType > |
---|
255 | void AlternativeFinder::addAggMembers( StructOrUnionType *aggInst, Expression *expr, const Cost &newCost, const TypeEnvironment & env, Expression * member ) { |
---|
256 | // by this point, member must be a name expr |
---|
257 | NameExpr * nameExpr = dynamic_cast< NameExpr * >( member ); |
---|
258 | if ( ! nameExpr ) return; |
---|
259 | const std::string & name = nameExpr->get_name(); |
---|
260 | std::list< Declaration* > members; |
---|
261 | aggInst->lookup( name, members ); |
---|
262 | |
---|
263 | for ( std::list< Declaration* >::const_iterator i = members.begin(); i != members.end(); ++i ) { |
---|
264 | if ( DeclarationWithType *dwt = dynamic_cast< DeclarationWithType* >( *i ) ) { |
---|
265 | alternatives.push_back( Alternative( new MemberExpr( dwt, expr->clone() ), env, newCost ) ); |
---|
266 | renameTypes( alternatives.back().expr ); |
---|
267 | addAnonConversions( alternatives.back() ); // add anonymous member interpretations whenever an aggregate value type is seen as a member expression. |
---|
268 | } else { |
---|
269 | assert( false ); |
---|
270 | } |
---|
271 | } |
---|
272 | } |
---|
273 | |
---|
274 | void AlternativeFinder::addTupleMembers( TupleType * tupleType, Expression *expr, const Cost &newCost, const TypeEnvironment & env, Expression * member ) { |
---|
275 | if ( ConstantExpr * constantExpr = dynamic_cast< ConstantExpr * >( member ) ) { |
---|
276 | // get the value of the constant expression as an int, must be between 0 and the length of the tuple type to have meaning |
---|
277 | // xxx - this should be improved by memoizing the value of constant exprs |
---|
278 | // during parsing and reusing that information here. |
---|
279 | std::stringstream ss( constantExpr->get_constant()->get_value() ); |
---|
280 | int val = 0; |
---|
281 | std::string tmp; |
---|
282 | if ( ss >> val && ! (ss >> tmp) ) { |
---|
283 | if ( val >= 0 && (unsigned int)val < tupleType->size() ) { |
---|
284 | alternatives.push_back( Alternative( new TupleIndexExpr( expr->clone(), val ), env, newCost ) ); |
---|
285 | } // if |
---|
286 | } // if |
---|
287 | } else if ( NameExpr * nameExpr = dynamic_cast< NameExpr * >( member ) ) { |
---|
288 | // xxx - temporary hack until 0/1 are int constants |
---|
289 | if ( nameExpr->get_name() == "0" || nameExpr->get_name() == "1" ) { |
---|
290 | std::stringstream ss( nameExpr->get_name() ); |
---|
291 | int val; |
---|
292 | ss >> val; |
---|
293 | alternatives.push_back( Alternative( new TupleIndexExpr( expr->clone(), val ), env, newCost ) ); |
---|
294 | } |
---|
295 | } // if |
---|
296 | } |
---|
297 | |
---|
298 | void AlternativeFinder::visit( ApplicationExpr *applicationExpr ) { |
---|
299 | alternatives.push_back( Alternative( applicationExpr->clone(), env, Cost::zero ) ); |
---|
300 | } |
---|
301 | |
---|
302 | Cost computeConversionCost( Type * actualType, Type * formalType, const SymTab::Indexer &indexer, const TypeEnvironment & env ) { |
---|
303 | PRINT( |
---|
304 | std::cerr << std::endl << "converting "; |
---|
305 | actualType->print( std::cerr, 8 ); |
---|
306 | std::cerr << std::endl << " to "; |
---|
307 | formalType->print( std::cerr, 8 ); |
---|
308 | std::cerr << std::endl << "environment is: "; |
---|
309 | env.print( std::cerr, 8 ); |
---|
310 | std::cerr << std::endl; |
---|
311 | ) |
---|
312 | Cost convCost = conversionCost( actualType, formalType, indexer, env ); |
---|
313 | PRINT( |
---|
314 | std::cerr << std::endl << "cost is" << convCost << std::endl; |
---|
315 | ) |
---|
316 | if ( convCost == Cost::infinity ) { |
---|
317 | return convCost; |
---|
318 | } |
---|
319 | convCost.incPoly( polyCost( formalType, env, indexer ) + polyCost( actualType, env, indexer ) ); |
---|
320 | return convCost; |
---|
321 | } |
---|
322 | |
---|
323 | Cost computeExpressionConversionCost( Expression *& actualExpr, Type * formalType, const SymTab::Indexer &indexer, const TypeEnvironment & env ) { |
---|
324 | Cost convCost = computeConversionCost( actualExpr->result, formalType, indexer, env ); |
---|
325 | |
---|
326 | // if there is a non-zero conversion cost, ignoring poly cost, then the expression requires conversion. |
---|
327 | // ignore poly cost for now, since this requires resolution of the cast to infer parameters and this |
---|
328 | // does not currently work for the reason stated below. |
---|
329 | Cost tmpCost = convCost; |
---|
330 | tmpCost.incPoly( -tmpCost.get_polyCost() ); |
---|
331 | if ( tmpCost != Cost::zero ) { |
---|
332 | // if ( convCost != Cost::zero ) { |
---|
333 | Type *newType = formalType->clone(); |
---|
334 | env.apply( newType ); |
---|
335 | actualExpr = new CastExpr( actualExpr, newType ); |
---|
336 | // 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 |
---|
337 | // inconsistent, once this is fixed it should be possible to resolve the cast. |
---|
338 | // 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. |
---|
339 | |
---|
340 | // AlternativeFinder finder( indexer, env ); |
---|
341 | // finder.findWithAdjustment( actualExpr ); |
---|
342 | // assertf( finder.get_alternatives().size() > 0, "Somehow castable expression failed to find alternatives." ); |
---|
343 | // assertf( finder.get_alternatives().size() == 1, "Somehow got multiple alternatives for known cast expression." ); |
---|
344 | // Alternative & alt = finder.get_alternatives().front(); |
---|
345 | // delete actualExpr; |
---|
346 | // actualExpr = alt.expr->clone(); |
---|
347 | } |
---|
348 | return convCost; |
---|
349 | } |
---|
350 | |
---|
351 | Cost computeApplicationConversionCost( Alternative &alt, const SymTab::Indexer &indexer ) { |
---|
352 | ApplicationExpr *appExpr = strict_dynamic_cast< ApplicationExpr* >( alt.expr ); |
---|
353 | PointerType *pointer = strict_dynamic_cast< PointerType* >( appExpr->get_function()->get_result() ); |
---|
354 | FunctionType *function = strict_dynamic_cast< FunctionType* >( pointer->get_base() ); |
---|
355 | |
---|
356 | Cost convCost = Cost::zero; |
---|
357 | std::list< DeclarationWithType* >& formals = function->get_parameters(); |
---|
358 | std::list< DeclarationWithType* >::iterator formal = formals.begin(); |
---|
359 | std::list< Expression* >& actuals = appExpr->get_args(); |
---|
360 | |
---|
361 | for ( std::list< Expression* >::iterator actualExpr = actuals.begin(); actualExpr != actuals.end(); ++actualExpr ) { |
---|
362 | Type * actualType = (*actualExpr)->get_result(); |
---|
363 | PRINT( |
---|
364 | std::cerr << "actual expression:" << std::endl; |
---|
365 | (*actualExpr)->print( std::cerr, 8 ); |
---|
366 | std::cerr << "--- results are" << std::endl; |
---|
367 | actualType->print( std::cerr, 8 ); |
---|
368 | ) |
---|
369 | if ( formal == formals.end() ) { |
---|
370 | if ( function->get_isVarArgs() ) { |
---|
371 | convCost.incUnsafe(); |
---|
372 | // convert reference-typed expressions to value-typed expressions |
---|
373 | referenceToRvalueConversion( *actualExpr ); |
---|
374 | continue; |
---|
375 | } else { |
---|
376 | return Cost::infinity; |
---|
377 | } |
---|
378 | } |
---|
379 | Type * formalType = (*formal)->get_type(); |
---|
380 | PRINT( |
---|
381 | std::cerr << std::endl << "converting "; |
---|
382 | actualType->print( std::cerr, 8 ); |
---|
383 | std::cerr << std::endl << " to "; |
---|
384 | formalType->print( std::cerr, 8 ); |
---|
385 | std::cerr << std::endl << "environment is: "; |
---|
386 | alt.env.print( std::cerr, 8 ); |
---|
387 | std::cerr << std::endl; |
---|
388 | ) |
---|
389 | convCost += computeExpressionConversionCost( *actualExpr, formalType, indexer, alt.env ); |
---|
390 | ++formal; // can't be in for-loop update because of the continue |
---|
391 | } |
---|
392 | if ( formal != formals.end() ) { |
---|
393 | return Cost::infinity; |
---|
394 | } |
---|
395 | |
---|
396 | for ( InferredParams::const_iterator assert = appExpr->get_inferParams().begin(); assert != appExpr->get_inferParams().end(); ++assert ) { |
---|
397 | convCost += computeConversionCost( assert->second.actualType, assert->second.formalType, indexer, alt.env ); |
---|
398 | } |
---|
399 | |
---|
400 | return convCost; |
---|
401 | } |
---|
402 | |
---|
403 | /// Adds type variables to the open variable set and marks their assertions |
---|
404 | void makeUnifiableVars( Type *type, OpenVarSet &unifiableVars, AssertionSet &needAssertions ) { |
---|
405 | for ( Type::ForallList::const_iterator tyvar = type->get_forall().begin(); tyvar != type->get_forall().end(); ++tyvar ) { |
---|
406 | unifiableVars[ (*tyvar)->get_name() ] = TypeDecl::Data{ *tyvar }; |
---|
407 | for ( std::list< DeclarationWithType* >::iterator assert = (*tyvar)->get_assertions().begin(); assert != (*tyvar)->get_assertions().end(); ++assert ) { |
---|
408 | needAssertions[ *assert ].isUsed = true; |
---|
409 | } |
---|
410 | /// needAssertions.insert( needAssertions.end(), (*tyvar)->get_assertions().begin(), (*tyvar)->get_assertions().end() ); |
---|
411 | } |
---|
412 | } |
---|
413 | |
---|
414 | /// instantiate a single argument by matching actuals from [actualIt, actualEnd) against formalType, |
---|
415 | /// producing expression(s) in out and their total cost in cost. |
---|
416 | template< typename AltIterator, typename OutputIterator > |
---|
417 | bool instantiateArgument( Type * formalType, Initializer * defaultValue, AltIterator & actualIt, AltIterator actualEnd, OpenVarSet & openVars, TypeEnvironment & resultEnv, AssertionSet & resultNeed, AssertionSet & resultHave, const SymTab::Indexer & indexer, Cost & cost, OutputIterator out ) { |
---|
418 | if ( TupleType * tupleType = dynamic_cast< TupleType * >( formalType ) ) { |
---|
419 | // formalType is a TupleType - group actuals into a TupleExpr whose type unifies with the TupleType |
---|
420 | std::list< Expression * > exprs; |
---|
421 | for ( Type * type : *tupleType ) { |
---|
422 | if ( ! instantiateArgument( type, defaultValue, actualIt, actualEnd, openVars, resultEnv, resultNeed, resultHave, indexer, cost, back_inserter( exprs ) ) ) { |
---|
423 | deleteAll( exprs ); |
---|
424 | return false; |
---|
425 | } |
---|
426 | } |
---|
427 | *out++ = new TupleExpr( exprs ); |
---|
428 | } else if ( TypeInstType * ttype = Tuples::isTtype( formalType ) ) { |
---|
429 | // xxx - mixing default arguments with variadic?? |
---|
430 | std::list< Expression * > exprs; |
---|
431 | for ( ; actualIt != actualEnd; ++actualIt ) { |
---|
432 | exprs.push_back( actualIt->expr->clone() ); |
---|
433 | cost += actualIt->cost; |
---|
434 | } |
---|
435 | Expression * arg = nullptr; |
---|
436 | if ( exprs.size() == 1 && Tuples::isTtype( exprs.front()->get_result() ) ) { |
---|
437 | // the case where a ttype value is passed directly is special, e.g. for argument forwarding purposes |
---|
438 | // xxx - what if passing multiple arguments, last of which is ttype? |
---|
439 | // xxx - what would happen if unify was changed so that unifying tuple types flattened both before unifying lists? then pass in TupleType(ttype) below. |
---|
440 | arg = exprs.front(); |
---|
441 | } else { |
---|
442 | arg = new TupleExpr( exprs ); |
---|
443 | } |
---|
444 | assert( arg && arg->get_result() ); |
---|
445 | if ( ! unify( ttype, arg->get_result(), resultEnv, resultNeed, resultHave, openVars, indexer ) ) { |
---|
446 | return false; |
---|
447 | } |
---|
448 | *out++ = arg; |
---|
449 | } else if ( actualIt != actualEnd ) { |
---|
450 | // both actualType and formalType are atomic (non-tuple) types - if they unify |
---|
451 | // then accept actual as an argument, otherwise return false (fail to instantiate argument) |
---|
452 | Expression * actual = actualIt->expr; |
---|
453 | Type * actualType = actual->get_result(); |
---|
454 | |
---|
455 | PRINT( |
---|
456 | std::cerr << "formal type is "; |
---|
457 | formalType->print( std::cerr ); |
---|
458 | std::cerr << std::endl << "actual type is "; |
---|
459 | actualType->print( std::cerr ); |
---|
460 | std::cerr << std::endl; |
---|
461 | ) |
---|
462 | if ( ! unify( formalType, actualType, resultEnv, resultNeed, resultHave, openVars, indexer ) ) { |
---|
463 | // std::cerr << "unify failed" << std::endl; |
---|
464 | return false; |
---|
465 | } |
---|
466 | // move the expression from the alternative to the output iterator |
---|
467 | *out++ = actual; |
---|
468 | actualIt->expr = nullptr; |
---|
469 | cost += actualIt->cost; |
---|
470 | ++actualIt; |
---|
471 | } else { |
---|
472 | // End of actuals - Handle default values |
---|
473 | if ( SingleInit *si = dynamic_cast<SingleInit *>( defaultValue )) { |
---|
474 | if ( CastExpr * castExpr = dynamic_cast< CastExpr * >( si->get_value() ) ) { |
---|
475 | // so far, only constant expressions are accepted as default values |
---|
476 | if ( ConstantExpr *cnstexpr = dynamic_cast<ConstantExpr *>( castExpr->get_arg() ) ) { |
---|
477 | if ( Constant *cnst = dynamic_cast<Constant *>( cnstexpr->get_constant() ) ) { |
---|
478 | if ( unify( formalType, cnst->get_type(), resultEnv, resultNeed, resultHave, openVars, indexer ) ) { |
---|
479 | *out++ = cnstexpr->clone(); |
---|
480 | return true; |
---|
481 | } // if |
---|
482 | } // if |
---|
483 | } // if |
---|
484 | } |
---|
485 | } // if |
---|
486 | return false; |
---|
487 | } // if |
---|
488 | return true; |
---|
489 | } |
---|
490 | |
---|
491 | bool AlternativeFinder::instantiateFunction( std::list< DeclarationWithType* >& formals, const AltList &actuals, bool isVarArgs, OpenVarSet& openVars, TypeEnvironment &resultEnv, AssertionSet &resultNeed, AssertionSet &resultHave, AltList & out ) { |
---|
492 | simpleCombineEnvironments( actuals.begin(), actuals.end(), resultEnv ); |
---|
493 | // make sure we don't widen any existing bindings |
---|
494 | for ( TypeEnvironment::iterator i = resultEnv.begin(); i != resultEnv.end(); ++i ) { |
---|
495 | i->allowWidening = false; |
---|
496 | } |
---|
497 | resultEnv.extractOpenVars( openVars ); |
---|
498 | |
---|
499 | // flatten actuals so that each actual has an atomic (non-tuple) type |
---|
500 | AltList exploded; |
---|
501 | Tuples::explode( actuals, indexer, back_inserter( exploded ) ); |
---|
502 | |
---|
503 | AltList::iterator actualExpr = exploded.begin(); |
---|
504 | AltList::iterator actualEnd = exploded.end(); |
---|
505 | for ( DeclarationWithType * formal : formals ) { |
---|
506 | // match flattened actuals with formal parameters - actuals will be grouped to match |
---|
507 | // with formals as appropriate |
---|
508 | Cost cost = Cost::zero; |
---|
509 | std::list< Expression * > newExprs; |
---|
510 | ObjectDecl * obj = strict_dynamic_cast< ObjectDecl * >( formal ); |
---|
511 | if ( ! instantiateArgument( obj->get_type(), obj->get_init(), actualExpr, actualEnd, openVars, resultEnv, resultNeed, resultHave, indexer, cost, back_inserter( newExprs ) ) ) { |
---|
512 | deleteAll( newExprs ); |
---|
513 | return false; |
---|
514 | } |
---|
515 | // success - produce argument as a new alternative |
---|
516 | assert( newExprs.size() == 1 ); |
---|
517 | out.push_back( Alternative( newExprs.front(), resultEnv, cost ) ); |
---|
518 | } |
---|
519 | if ( actualExpr != actualEnd ) { |
---|
520 | // there are still actuals remaining, but we've run out of formal parameters to match against |
---|
521 | // this is okay only if the function is variadic |
---|
522 | if ( ! isVarArgs ) { |
---|
523 | return false; |
---|
524 | } |
---|
525 | out.splice( out.end(), exploded, actualExpr, actualEnd ); |
---|
526 | } |
---|
527 | return true; |
---|
528 | } |
---|
529 | |
---|
530 | // /// Map of declaration uniqueIds (intended to be the assertions in an AssertionSet) to their parents and the number of times they've been included |
---|
531 | //typedef std::unordered_map< UniqueId, std::unordered_map< UniqueId, unsigned > > AssertionParentSet; |
---|
532 | |
---|
533 | static const int recursionLimit = /*10*/ 4; ///< Limit to depth of recursion satisfaction |
---|
534 | //static const unsigned recursionParentLimit = 1; ///< Limit to the number of times an assertion can recursively use itself |
---|
535 | |
---|
536 | void addToIndexer( AssertionSet &assertSet, SymTab::Indexer &indexer ) { |
---|
537 | for ( AssertionSet::iterator i = assertSet.begin(); i != assertSet.end(); ++i ) { |
---|
538 | if ( i->second.isUsed ) { |
---|
539 | indexer.addId( i->first ); |
---|
540 | } |
---|
541 | } |
---|
542 | } |
---|
543 | |
---|
544 | template< typename ForwardIterator, typename OutputIterator > |
---|
545 | void inferRecursive( ForwardIterator begin, ForwardIterator end, const Alternative &newAlt, OpenVarSet &openVars, const SymTab::Indexer &decls, const AssertionSet &newNeed, /*const AssertionParentSet &needParents,*/ |
---|
546 | int level, const SymTab::Indexer &indexer, OutputIterator out ) { |
---|
547 | if ( begin == end ) { |
---|
548 | if ( newNeed.empty() ) { |
---|
549 | PRINT( |
---|
550 | std::cerr << "all assertions satisfied, output alternative: "; |
---|
551 | newAlt.print( std::cerr ); |
---|
552 | std::cerr << std::endl; |
---|
553 | ); |
---|
554 | *out++ = newAlt; |
---|
555 | return; |
---|
556 | } else if ( level >= recursionLimit ) { |
---|
557 | throw SemanticError( "Too many recursive assertions" ); |
---|
558 | } else { |
---|
559 | AssertionSet newerNeed; |
---|
560 | PRINT( |
---|
561 | std::cerr << "recursing with new set:" << std::endl; |
---|
562 | printAssertionSet( newNeed, std::cerr, 8 ); |
---|
563 | ) |
---|
564 | inferRecursive( newNeed.begin(), newNeed.end(), newAlt, openVars, decls, newerNeed, /*needParents,*/ level+1, indexer, out ); |
---|
565 | return; |
---|
566 | } |
---|
567 | } |
---|
568 | |
---|
569 | ForwardIterator cur = begin++; |
---|
570 | if ( ! cur->second.isUsed ) { |
---|
571 | inferRecursive( begin, end, newAlt, openVars, decls, newNeed, /*needParents,*/ level, indexer, out ); |
---|
572 | return; // xxx - should this continue? previously this wasn't here, and it looks like it should be |
---|
573 | } |
---|
574 | DeclarationWithType *curDecl = cur->first; |
---|
575 | |
---|
576 | PRINT( |
---|
577 | std::cerr << "inferRecursive: assertion is "; |
---|
578 | curDecl->print( std::cerr ); |
---|
579 | std::cerr << std::endl; |
---|
580 | ) |
---|
581 | std::list< DeclarationWithType* > candidates; |
---|
582 | decls.lookupId( curDecl->get_name(), candidates ); |
---|
583 | /// if ( candidates.empty() ) { std::cerr << "no candidates!" << std::endl; } |
---|
584 | for ( std::list< DeclarationWithType* >::const_iterator candidate = candidates.begin(); candidate != candidates.end(); ++candidate ) { |
---|
585 | PRINT( |
---|
586 | std::cerr << "inferRecursive: candidate is "; |
---|
587 | (*candidate)->print( std::cerr ); |
---|
588 | std::cerr << std::endl; |
---|
589 | ) |
---|
590 | |
---|
591 | AssertionSet newHave, newerNeed( newNeed ); |
---|
592 | TypeEnvironment newEnv( newAlt.env ); |
---|
593 | OpenVarSet newOpenVars( openVars ); |
---|
594 | Type *adjType = (*candidate)->get_type()->clone(); |
---|
595 | adjustExprType( adjType, newEnv, indexer ); |
---|
596 | adjType->accept( global_renamer ); |
---|
597 | PRINT( |
---|
598 | std::cerr << "unifying "; |
---|
599 | curDecl->get_type()->print( std::cerr ); |
---|
600 | std::cerr << " with "; |
---|
601 | adjType->print( std::cerr ); |
---|
602 | std::cerr << std::endl; |
---|
603 | ) |
---|
604 | if ( unify( curDecl->get_type(), adjType, newEnv, newerNeed, newHave, newOpenVars, indexer ) ) { |
---|
605 | PRINT( |
---|
606 | std::cerr << "success!" << std::endl; |
---|
607 | ) |
---|
608 | SymTab::Indexer newDecls( decls ); |
---|
609 | addToIndexer( newHave, newDecls ); |
---|
610 | Alternative newerAlt( newAlt ); |
---|
611 | newerAlt.env = newEnv; |
---|
612 | assertf( (*candidate)->get_uniqueId(), "Assertion candidate does not have a unique ID: %s", toString( *candidate ).c_str() ); |
---|
613 | DeclarationWithType *candDecl = static_cast< DeclarationWithType* >( Declaration::declFromId( (*candidate)->get_uniqueId() ) ); |
---|
614 | |
---|
615 | // everything with an empty idChain was pulled in by the current assertion. |
---|
616 | // add current assertion's idChain + current assertion's ID so that the correct inferParameters can be found. |
---|
617 | for ( auto & a : newerNeed ) { |
---|
618 | if ( a.second.idChain.empty() ) { |
---|
619 | a.second.idChain = cur->second.idChain; |
---|
620 | a.second.idChain.push_back( curDecl->get_uniqueId() ); |
---|
621 | } |
---|
622 | } |
---|
623 | |
---|
624 | //AssertionParentSet newNeedParents( needParents ); |
---|
625 | // skip repeatingly-self-recursive assertion satisfaction |
---|
626 | // DOESN'T WORK: grandchild nodes conflict with their cousins |
---|
627 | //if ( newNeedParents[ curDecl->get_uniqueId() ][ candDecl->get_uniqueId() ]++ > recursionParentLimit ) continue; |
---|
628 | Expression *varExpr = new VariableExpr( candDecl ); |
---|
629 | delete varExpr->get_result(); |
---|
630 | varExpr->set_result( adjType->clone() ); |
---|
631 | PRINT( |
---|
632 | std::cerr << "satisfying assertion " << curDecl->get_uniqueId() << " "; |
---|
633 | curDecl->print( std::cerr ); |
---|
634 | std::cerr << " with declaration " << (*candidate)->get_uniqueId() << " "; |
---|
635 | (*candidate)->print( std::cerr ); |
---|
636 | std::cerr << std::endl; |
---|
637 | ) |
---|
638 | // 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). |
---|
639 | InferredParams * inferParameters = &newerAlt.expr->get_inferParams(); |
---|
640 | for ( UniqueId id : cur->second.idChain ) { |
---|
641 | inferParameters = (*inferParameters)[ id ].inferParams.get(); |
---|
642 | } |
---|
643 | // XXX: this is a memory leak, but adjType can't be deleted because it might contain assertions |
---|
644 | (*inferParameters)[ curDecl->get_uniqueId() ] = ParamEntry( (*candidate)->get_uniqueId(), adjType->clone(), curDecl->get_type()->clone(), varExpr ); |
---|
645 | inferRecursive( begin, end, newerAlt, newOpenVars, newDecls, newerNeed, /*newNeedParents,*/ level, indexer, out ); |
---|
646 | } else { |
---|
647 | delete adjType; |
---|
648 | } |
---|
649 | } |
---|
650 | } |
---|
651 | |
---|
652 | template< typename OutputIterator > |
---|
653 | void AlternativeFinder::inferParameters( const AssertionSet &need, AssertionSet &have, const Alternative &newAlt, OpenVarSet &openVars, OutputIterator out ) { |
---|
654 | // PRINT( |
---|
655 | // std::cerr << "inferParameters: assertions needed are" << std::endl; |
---|
656 | // printAll( need, std::cerr, 8 ); |
---|
657 | // ) |
---|
658 | SymTab::Indexer decls( indexer ); |
---|
659 | // PRINT( |
---|
660 | // std::cerr << "============= original indexer" << std::endl; |
---|
661 | // indexer.print( std::cerr ); |
---|
662 | // std::cerr << "============= new indexer" << std::endl; |
---|
663 | // decls.print( std::cerr ); |
---|
664 | // ) |
---|
665 | addToIndexer( have, decls ); |
---|
666 | AssertionSet newNeed; |
---|
667 | //AssertionParentSet needParents; |
---|
668 | PRINT( |
---|
669 | std::cerr << "env is: " << std::endl; |
---|
670 | newAlt.env.print( std::cerr, 0 ); |
---|
671 | std::cerr << std::endl; |
---|
672 | ) |
---|
673 | |
---|
674 | inferRecursive( need.begin(), need.end(), newAlt, openVars, decls, newNeed, /*needParents,*/ 0, indexer, out ); |
---|
675 | // PRINT( |
---|
676 | // std::cerr << "declaration 14 is "; |
---|
677 | // Declaration::declFromId |
---|
678 | // *out++ = newAlt; |
---|
679 | // ) |
---|
680 | } |
---|
681 | |
---|
682 | template< typename OutputIterator > |
---|
683 | void AlternativeFinder::makeFunctionAlternatives( const Alternative &func, FunctionType *funcType, const AltList &actualAlt, OutputIterator out ) { |
---|
684 | OpenVarSet openVars; |
---|
685 | AssertionSet resultNeed, resultHave; |
---|
686 | TypeEnvironment resultEnv( func.env ); |
---|
687 | makeUnifiableVars( funcType, openVars, resultNeed ); |
---|
688 | resultEnv.add( funcType->get_forall() ); // add all type variables as open variables now so that those not used in the parameter list are still considered open |
---|
689 | AltList instantiatedActuals; // filled by instantiate function |
---|
690 | if ( targetType && ! targetType->isVoid() && ! funcType->get_returnVals().empty() ) { |
---|
691 | // attempt to narrow based on expected target type |
---|
692 | Type * returnType = funcType->get_returnVals().front()->get_type(); |
---|
693 | if ( ! unify( returnType, targetType, resultEnv, resultNeed, resultHave, openVars, indexer ) ) { |
---|
694 | // unification failed, don't pursue this alternative |
---|
695 | return; |
---|
696 | } |
---|
697 | } |
---|
698 | |
---|
699 | if ( instantiateFunction( funcType->get_parameters(), actualAlt, funcType->get_isVarArgs(), openVars, resultEnv, resultNeed, resultHave, instantiatedActuals ) ) { |
---|
700 | ApplicationExpr *appExpr = new ApplicationExpr( func.expr->clone() ); |
---|
701 | Alternative newAlt( appExpr, resultEnv, sumCost( instantiatedActuals ) ); |
---|
702 | makeExprList( instantiatedActuals, appExpr->get_args() ); |
---|
703 | PRINT( |
---|
704 | std::cerr << "instantiate function success: " << appExpr << std::endl; |
---|
705 | std::cerr << "need assertions:" << std::endl; |
---|
706 | printAssertionSet( resultNeed, std::cerr, 8 ); |
---|
707 | ) |
---|
708 | inferParameters( resultNeed, resultHave, newAlt, openVars, out ); |
---|
709 | } |
---|
710 | } |
---|
711 | |
---|
712 | void AlternativeFinder::visit( UntypedExpr *untypedExpr ) { |
---|
713 | AlternativeFinder funcFinder( indexer, env ); |
---|
714 | funcFinder.findWithAdjustment( untypedExpr->get_function() ); |
---|
715 | // if there are no function alternatives, then proceeding is a waste of time. |
---|
716 | if ( funcFinder.alternatives.empty() ) return; |
---|
717 | |
---|
718 | std::list< AlternativeFinder > argAlternatives; |
---|
719 | findSubExprs( untypedExpr->begin_args(), untypedExpr->end_args(), back_inserter( argAlternatives ) ); |
---|
720 | |
---|
721 | std::list< AltList > possibilities; |
---|
722 | combos( argAlternatives.begin(), argAlternatives.end(), back_inserter( possibilities ) ); |
---|
723 | |
---|
724 | // take care of possible tuple assignments |
---|
725 | // if not tuple assignment, assignment is taken care of as a normal function call |
---|
726 | Tuples::handleTupleAssignment( *this, untypedExpr, possibilities ); |
---|
727 | |
---|
728 | // find function operators |
---|
729 | static NameExpr *opExpr = new NameExpr( "?()" ); |
---|
730 | AlternativeFinder funcOpFinder( indexer, env ); |
---|
731 | // it's ok if there aren't any defined function ops |
---|
732 | funcOpFinder.maybeFind( opExpr); |
---|
733 | PRINT( |
---|
734 | std::cerr << "known function ops:" << std::endl; |
---|
735 | printAlts( funcOpFinder.alternatives, std::cerr, 1 ); |
---|
736 | ) |
---|
737 | |
---|
738 | AltList candidates; |
---|
739 | SemanticError errors; |
---|
740 | for ( AltList::iterator func = funcFinder.alternatives.begin(); func != funcFinder.alternatives.end(); ++func ) { |
---|
741 | try { |
---|
742 | PRINT( |
---|
743 | std::cerr << "working on alternative: " << std::endl; |
---|
744 | func->print( std::cerr, 8 ); |
---|
745 | ) |
---|
746 | // check if the type is pointer to function |
---|
747 | if ( PointerType *pointer = dynamic_cast< PointerType* >( func->expr->get_result()->stripReferences() ) ) { |
---|
748 | if ( FunctionType *function = dynamic_cast< FunctionType* >( pointer->get_base() ) ) { |
---|
749 | Alternative newFunc( *func ); |
---|
750 | referenceToRvalueConversion( newFunc.expr ); |
---|
751 | for ( std::list< AltList >::iterator actualAlt = possibilities.begin(); actualAlt != possibilities.end(); ++actualAlt ) { |
---|
752 | // XXX |
---|
753 | //Designators::check_alternative( function, *actualAlt ); |
---|
754 | makeFunctionAlternatives( newFunc, function, *actualAlt, std::back_inserter( candidates ) ); |
---|
755 | } |
---|
756 | } |
---|
757 | } else if ( TypeInstType *typeInst = dynamic_cast< TypeInstType* >( func->expr->get_result()->stripReferences() ) ) { // handle ftype (e.g. *? on function pointer) |
---|
758 | EqvClass eqvClass; |
---|
759 | if ( func->env.lookup( typeInst->get_name(), eqvClass ) && eqvClass.type ) { |
---|
760 | if ( FunctionType *function = dynamic_cast< FunctionType* >( eqvClass.type ) ) { |
---|
761 | Alternative newFunc( *func ); |
---|
762 | referenceToRvalueConversion( newFunc.expr ); |
---|
763 | for ( std::list< AltList >::iterator actualAlt = possibilities.begin(); actualAlt != possibilities.end(); ++actualAlt ) { |
---|
764 | makeFunctionAlternatives( newFunc, function, *actualAlt, std::back_inserter( candidates ) ); |
---|
765 | } // for |
---|
766 | } // if |
---|
767 | } // if |
---|
768 | } |
---|
769 | |
---|
770 | // try each function operator ?() with the current function alternative and each of the argument combinations |
---|
771 | for ( AltList::iterator funcOp = funcOpFinder.alternatives.begin(); funcOp != funcOpFinder.alternatives.end(); ++funcOp ) { |
---|
772 | // check if the type is pointer to function |
---|
773 | if ( PointerType *pointer = dynamic_cast< PointerType* >( funcOp->expr->get_result()->stripReferences() ) ) { |
---|
774 | if ( FunctionType *function = dynamic_cast< FunctionType* >( pointer->get_base() ) ) { |
---|
775 | Alternative newFunc( *funcOp ); |
---|
776 | referenceToRvalueConversion( newFunc.expr ); |
---|
777 | for ( std::list< AltList >::iterator actualAlt = possibilities.begin(); actualAlt != possibilities.end(); ++actualAlt ) { |
---|
778 | AltList currentAlt; |
---|
779 | currentAlt.push_back( *func ); |
---|
780 | currentAlt.insert( currentAlt.end(), actualAlt->begin(), actualAlt->end() ); |
---|
781 | makeFunctionAlternatives( newFunc, function, currentAlt, std::back_inserter( candidates ) ); |
---|
782 | } // for |
---|
783 | } // if |
---|
784 | } // if |
---|
785 | } // for |
---|
786 | } catch ( SemanticError &e ) { |
---|
787 | errors.append( e ); |
---|
788 | } |
---|
789 | } // for |
---|
790 | |
---|
791 | // Implement SFINAE; resolution errors are only errors if there aren't any non-erroneous resolutions |
---|
792 | if ( candidates.empty() && ! errors.isEmpty() ) { throw errors; } |
---|
793 | |
---|
794 | // compute conversionsion costs |
---|
795 | for ( AltList::iterator withFunc = candidates.begin(); withFunc != candidates.end(); ++withFunc ) { |
---|
796 | Cost cvtCost = computeApplicationConversionCost( *withFunc, indexer ); |
---|
797 | |
---|
798 | PRINT( |
---|
799 | ApplicationExpr *appExpr = strict_dynamic_cast< ApplicationExpr* >( withFunc->expr ); |
---|
800 | PointerType *pointer = strict_dynamic_cast< PointerType* >( appExpr->get_function()->get_result() ); |
---|
801 | FunctionType *function = strict_dynamic_cast< FunctionType* >( pointer->get_base() ); |
---|
802 | std::cerr << "Case +++++++++++++ " << appExpr->get_function() << std::endl; |
---|
803 | std::cerr << "formals are:" << std::endl; |
---|
804 | printAll( function->get_parameters(), std::cerr, 8 ); |
---|
805 | std::cerr << "actuals are:" << std::endl; |
---|
806 | printAll( appExpr->get_args(), std::cerr, 8 ); |
---|
807 | std::cerr << "bindings are:" << std::endl; |
---|
808 | withFunc->env.print( std::cerr, 8 ); |
---|
809 | std::cerr << "cost of conversion is:" << cvtCost << std::endl; |
---|
810 | ) |
---|
811 | if ( cvtCost != Cost::infinity ) { |
---|
812 | withFunc->cvtCost = cvtCost; |
---|
813 | alternatives.push_back( *withFunc ); |
---|
814 | } // if |
---|
815 | } // for |
---|
816 | |
---|
817 | candidates.clear(); |
---|
818 | candidates.splice( candidates.end(), alternatives ); |
---|
819 | |
---|
820 | findMinCost( candidates.begin(), candidates.end(), std::back_inserter( alternatives ) ); |
---|
821 | |
---|
822 | // function may return struct or union value, in which case we need to add alternatives for implicit |
---|
823 | // conversions to each of the anonymous members, must happen after findMinCost since anon conversions |
---|
824 | // are never the cheapest expression |
---|
825 | for ( const Alternative & alt : alternatives ) { |
---|
826 | addAnonConversions( alt ); |
---|
827 | } |
---|
828 | |
---|
829 | if ( alternatives.empty() && targetType && ! targetType->isVoid() ) { |
---|
830 | // xxx - this is a temporary hack. If resolution is unsuccessful with a target type, try again without a |
---|
831 | // target type, since it will sometimes succeed when it wouldn't easily with target type binding. For example, |
---|
832 | // forall( otype T ) lvalue T ?[?]( T *, ptrdiff_t ); |
---|
833 | // const char * x = "hello world"; |
---|
834 | // unsigned char ch = x[0]; |
---|
835 | // Fails with simple return type binding. First, T is bound to unsigned char, then (x: const char *) is unified |
---|
836 | // with unsigned char *, which fails because pointer base types must be unified exactly. The new resolver should |
---|
837 | // fix this issue in a more robust way. |
---|
838 | targetType = nullptr; |
---|
839 | visit( untypedExpr ); |
---|
840 | } |
---|
841 | } |
---|
842 | |
---|
843 | bool isLvalue( Expression *expr ) { |
---|
844 | // xxx - recurse into tuples? |
---|
845 | return expr->result && ( expr->get_result()->get_lvalue() || dynamic_cast< ReferenceType * >( expr->get_result() ) ); |
---|
846 | } |
---|
847 | |
---|
848 | void AlternativeFinder::visit( AddressExpr *addressExpr ) { |
---|
849 | AlternativeFinder finder( indexer, env ); |
---|
850 | finder.find( addressExpr->get_arg() ); |
---|
851 | for ( std::list< Alternative >::iterator i = finder.alternatives.begin(); i != finder.alternatives.end(); ++i ) { |
---|
852 | if ( isLvalue( i->expr ) ) { |
---|
853 | alternatives.push_back( Alternative( new AddressExpr( i->expr->clone() ), i->env, i->cost ) ); |
---|
854 | } // if |
---|
855 | } // for |
---|
856 | } |
---|
857 | |
---|
858 | void AlternativeFinder::visit( LabelAddressExpr * expr ) { |
---|
859 | alternatives.push_back( Alternative( expr->clone(), env, Cost::zero) ); |
---|
860 | } |
---|
861 | |
---|
862 | Expression * restructureCast( Expression * argExpr, Type * toType ) { |
---|
863 | if ( argExpr->get_result()->size() > 1 && ! toType->isVoid() && ! dynamic_cast<ReferenceType *>( toType ) ) { |
---|
864 | // Argument expression is a tuple and the target type is not void and not a reference type. |
---|
865 | // Cast each member of the tuple to its corresponding target type, producing the tuple of those |
---|
866 | // cast expressions. If there are more components of the tuple than components in the target type, |
---|
867 | // then excess components do not come out in the result expression (but UniqueExprs ensure that |
---|
868 | // side effects will still be done). |
---|
869 | if ( Tuples::maybeImpureIgnoreUnique( argExpr ) ) { |
---|
870 | // expressions which may contain side effects require a single unique instance of the expression. |
---|
871 | argExpr = new UniqueExpr( argExpr ); |
---|
872 | } |
---|
873 | std::list< Expression * > componentExprs; |
---|
874 | for ( unsigned int i = 0; i < toType->size(); i++ ) { |
---|
875 | // cast each component |
---|
876 | TupleIndexExpr * idx = new TupleIndexExpr( argExpr->clone(), i ); |
---|
877 | componentExprs.push_back( restructureCast( idx, toType->getComponent( i ) ) ); |
---|
878 | } |
---|
879 | delete argExpr; |
---|
880 | assert( componentExprs.size() > 0 ); |
---|
881 | // produce the tuple of casts |
---|
882 | return new TupleExpr( componentExprs ); |
---|
883 | } else { |
---|
884 | // handle normally |
---|
885 | return new CastExpr( argExpr, toType->clone() ); |
---|
886 | } |
---|
887 | } |
---|
888 | |
---|
889 | void AlternativeFinder::visit( CastExpr *castExpr ) { |
---|
890 | Type *& toType = castExpr->get_result(); |
---|
891 | assert( toType ); |
---|
892 | toType = resolveTypeof( toType, indexer ); |
---|
893 | SymTab::validateType( toType, &indexer ); |
---|
894 | adjustExprType( toType, env, indexer ); |
---|
895 | |
---|
896 | AlternativeFinder finder( indexer, env ); |
---|
897 | finder.targetType = toType; |
---|
898 | finder.findWithAdjustment( castExpr->get_arg() ); |
---|
899 | |
---|
900 | AltList candidates; |
---|
901 | for ( std::list< Alternative >::iterator i = finder.alternatives.begin(); i != finder.alternatives.end(); ++i ) { |
---|
902 | AssertionSet needAssertions, haveAssertions; |
---|
903 | OpenVarSet openVars; |
---|
904 | |
---|
905 | // It's possible that a cast can throw away some values in a multiply-valued expression. (An example is a |
---|
906 | // cast-to-void, which casts from one value to zero.) Figure out the prefix of the subexpression results |
---|
907 | // that are cast directly. The candidate is invalid if it has fewer results than there are types to cast |
---|
908 | // to. |
---|
909 | int discardedValues = i->expr->get_result()->size() - castExpr->get_result()->size(); |
---|
910 | if ( discardedValues < 0 ) continue; |
---|
911 | // xxx - may need to go into tuple types and extract relevant types and use unifyList. Note that currently, this does not |
---|
912 | // allow casting a tuple to an atomic type (e.g. (int)([1, 2, 3])) |
---|
913 | // unification run for side-effects |
---|
914 | unify( castExpr->get_result(), i->expr->get_result(), i->env, needAssertions, haveAssertions, openVars, indexer ); |
---|
915 | Cost thisCost = castCost( i->expr->get_result(), castExpr->get_result(), indexer, i->env ); |
---|
916 | if ( thisCost != Cost::infinity ) { |
---|
917 | // count one safe conversion for each value that is thrown away |
---|
918 | thisCost.incSafe( discardedValues ); |
---|
919 | Alternative newAlt( restructureCast( i->expr->clone(), toType ), i->env, i->cost, thisCost ); |
---|
920 | inferParameters( needAssertions, haveAssertions, newAlt, openVars, back_inserter( candidates ) ); |
---|
921 | } // if |
---|
922 | } // for |
---|
923 | |
---|
924 | // findMinCost selects the alternatives with the lowest "cost" members, but has the side effect of copying the |
---|
925 | // cvtCost member to the cost member (since the old cost is now irrelevant). Thus, calling findMinCost twice |
---|
926 | // selects first based on argument cost, then on conversion cost. |
---|
927 | AltList minArgCost; |
---|
928 | findMinCost( candidates.begin(), candidates.end(), std::back_inserter( minArgCost ) ); |
---|
929 | findMinCost( minArgCost.begin(), minArgCost.end(), std::back_inserter( alternatives ) ); |
---|
930 | } |
---|
931 | |
---|
932 | void AlternativeFinder::visit( VirtualCastExpr * castExpr ) { |
---|
933 | assertf( castExpr->get_result(), "Implicate virtual cast targets not yet supported." ); |
---|
934 | AlternativeFinder finder( indexer, env ); |
---|
935 | // don't prune here, since it's guaranteed all alternatives will have the same type |
---|
936 | finder.findWithoutPrune( castExpr->get_arg() ); |
---|
937 | for ( Alternative & alt : finder.alternatives ) { |
---|
938 | alternatives.push_back( Alternative( |
---|
939 | new VirtualCastExpr( alt.expr->clone(), castExpr->get_result()->clone() ), |
---|
940 | alt.env, alt.cost ) ); |
---|
941 | } |
---|
942 | } |
---|
943 | |
---|
944 | void AlternativeFinder::visit( UntypedMemberExpr *memberExpr ) { |
---|
945 | AlternativeFinder funcFinder( indexer, env ); |
---|
946 | funcFinder.findWithAdjustment( memberExpr->get_aggregate() ); |
---|
947 | for ( AltList::const_iterator agg = funcFinder.alternatives.begin(); agg != funcFinder.alternatives.end(); ++agg ) { |
---|
948 | // 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 |
---|
949 | std::unique_ptr<Expression> aggrExpr( agg->expr->clone() ); |
---|
950 | Type * aggrType = aggrExpr->get_result(); |
---|
951 | if ( dynamic_cast< ReferenceType * >( aggrType ) ) { |
---|
952 | aggrType = aggrType->stripReferences(); |
---|
953 | aggrExpr.reset( new CastExpr( aggrExpr.release(), aggrType->clone() ) ); |
---|
954 | } |
---|
955 | // find member of the given type |
---|
956 | if ( StructInstType *structInst = dynamic_cast< StructInstType* >( aggrExpr->get_result() ) ) { |
---|
957 | addAggMembers( structInst, aggrExpr.get(), agg->cost, agg->env, memberExpr->get_member() ); |
---|
958 | } else if ( UnionInstType *unionInst = dynamic_cast< UnionInstType* >( aggrExpr->get_result() ) ) { |
---|
959 | addAggMembers( unionInst, aggrExpr.get(), agg->cost, agg->env, memberExpr->get_member() ); |
---|
960 | } else if ( TupleType * tupleType = dynamic_cast< TupleType * >( aggrExpr->get_result() ) ) { |
---|
961 | addTupleMembers( tupleType, aggrExpr.get(), agg->cost, agg->env, memberExpr->get_member() ); |
---|
962 | } // if |
---|
963 | } // for |
---|
964 | } |
---|
965 | |
---|
966 | void AlternativeFinder::visit( MemberExpr *memberExpr ) { |
---|
967 | alternatives.push_back( Alternative( memberExpr->clone(), env, Cost::zero ) ); |
---|
968 | } |
---|
969 | |
---|
970 | void AlternativeFinder::visit( NameExpr *nameExpr ) { |
---|
971 | std::list< DeclarationWithType* > declList; |
---|
972 | indexer.lookupId( nameExpr->get_name(), declList ); |
---|
973 | PRINT( std::cerr << "nameExpr is " << nameExpr->get_name() << std::endl; ) |
---|
974 | for ( std::list< DeclarationWithType* >::iterator i = declList.begin(); i != declList.end(); ++i ) { |
---|
975 | VariableExpr newExpr( *i ); |
---|
976 | alternatives.push_back( Alternative( newExpr.clone(), env, Cost::zero ) ); |
---|
977 | PRINT( |
---|
978 | std::cerr << "decl is "; |
---|
979 | (*i)->print( std::cerr ); |
---|
980 | std::cerr << std::endl; |
---|
981 | std::cerr << "newExpr is "; |
---|
982 | newExpr.print( std::cerr ); |
---|
983 | std::cerr << std::endl; |
---|
984 | ) |
---|
985 | renameTypes( alternatives.back().expr ); |
---|
986 | addAnonConversions( alternatives.back() ); // add anonymous member interpretations whenever an aggregate value type is seen as a name expression. |
---|
987 | } // for |
---|
988 | } |
---|
989 | |
---|
990 | void AlternativeFinder::visit( VariableExpr *variableExpr ) { |
---|
991 | // not sufficient to clone here, because variable's type may have changed |
---|
992 | // since the VariableExpr was originally created. |
---|
993 | alternatives.push_back( Alternative( new VariableExpr( variableExpr->get_var() ), env, Cost::zero ) ); |
---|
994 | } |
---|
995 | |
---|
996 | void AlternativeFinder::visit( ConstantExpr *constantExpr ) { |
---|
997 | alternatives.push_back( Alternative( constantExpr->clone(), env, Cost::zero ) ); |
---|
998 | } |
---|
999 | |
---|
1000 | void AlternativeFinder::visit( SizeofExpr *sizeofExpr ) { |
---|
1001 | if ( sizeofExpr->get_isType() ) { |
---|
1002 | Type * newType = sizeofExpr->get_type()->clone(); |
---|
1003 | alternatives.push_back( Alternative( new SizeofExpr( resolveTypeof( newType, indexer ) ), env, Cost::zero ) ); |
---|
1004 | } else { |
---|
1005 | // find all alternatives for the argument to sizeof |
---|
1006 | AlternativeFinder finder( indexer, env ); |
---|
1007 | finder.find( sizeofExpr->get_expr() ); |
---|
1008 | // find the lowest cost alternative among the alternatives, otherwise ambiguous |
---|
1009 | AltList winners; |
---|
1010 | findMinCost( finder.alternatives.begin(), finder.alternatives.end(), back_inserter( winners ) ); |
---|
1011 | if ( winners.size() != 1 ) { |
---|
1012 | throw SemanticError( "Ambiguous expression in sizeof operand: ", sizeofExpr->get_expr() ); |
---|
1013 | } // if |
---|
1014 | // return the lowest cost alternative for the argument |
---|
1015 | Alternative &choice = winners.front(); |
---|
1016 | referenceToRvalueConversion( choice.expr ); |
---|
1017 | alternatives.push_back( Alternative( new SizeofExpr( choice.expr->clone() ), choice.env, Cost::zero ) ); |
---|
1018 | } // if |
---|
1019 | } |
---|
1020 | |
---|
1021 | void AlternativeFinder::visit( AlignofExpr *alignofExpr ) { |
---|
1022 | if ( alignofExpr->get_isType() ) { |
---|
1023 | Type * newType = alignofExpr->get_type()->clone(); |
---|
1024 | alternatives.push_back( Alternative( new AlignofExpr( resolveTypeof( newType, indexer ) ), env, Cost::zero ) ); |
---|
1025 | } else { |
---|
1026 | // find all alternatives for the argument to sizeof |
---|
1027 | AlternativeFinder finder( indexer, env ); |
---|
1028 | finder.find( alignofExpr->get_expr() ); |
---|
1029 | // find the lowest cost alternative among the alternatives, otherwise ambiguous |
---|
1030 | AltList winners; |
---|
1031 | findMinCost( finder.alternatives.begin(), finder.alternatives.end(), back_inserter( winners ) ); |
---|
1032 | if ( winners.size() != 1 ) { |
---|
1033 | throw SemanticError( "Ambiguous expression in alignof operand: ", alignofExpr->get_expr() ); |
---|
1034 | } // if |
---|
1035 | // return the lowest cost alternative for the argument |
---|
1036 | Alternative &choice = winners.front(); |
---|
1037 | referenceToRvalueConversion( choice.expr ); |
---|
1038 | alternatives.push_back( Alternative( new AlignofExpr( choice.expr->clone() ), choice.env, Cost::zero ) ); |
---|
1039 | } // if |
---|
1040 | } |
---|
1041 | |
---|
1042 | template< typename StructOrUnionType > |
---|
1043 | void AlternativeFinder::addOffsetof( StructOrUnionType *aggInst, const std::string &name ) { |
---|
1044 | std::list< Declaration* > members; |
---|
1045 | aggInst->lookup( name, members ); |
---|
1046 | for ( std::list< Declaration* >::const_iterator i = members.begin(); i != members.end(); ++i ) { |
---|
1047 | if ( DeclarationWithType *dwt = dynamic_cast< DeclarationWithType* >( *i ) ) { |
---|
1048 | alternatives.push_back( Alternative( new OffsetofExpr( aggInst->clone(), dwt ), env, Cost::zero ) ); |
---|
1049 | renameTypes( alternatives.back().expr ); |
---|
1050 | } else { |
---|
1051 | assert( false ); |
---|
1052 | } |
---|
1053 | } |
---|
1054 | } |
---|
1055 | |
---|
1056 | void AlternativeFinder::visit( UntypedOffsetofExpr *offsetofExpr ) { |
---|
1057 | AlternativeFinder funcFinder( indexer, env ); |
---|
1058 | // xxx - resolveTypeof? |
---|
1059 | if ( StructInstType *structInst = dynamic_cast< StructInstType* >( offsetofExpr->get_type() ) ) { |
---|
1060 | addOffsetof( structInst, offsetofExpr->get_member() ); |
---|
1061 | } else if ( UnionInstType *unionInst = dynamic_cast< UnionInstType* >( offsetofExpr->get_type() ) ) { |
---|
1062 | addOffsetof( unionInst, offsetofExpr->get_member() ); |
---|
1063 | } |
---|
1064 | } |
---|
1065 | |
---|
1066 | void AlternativeFinder::visit( OffsetofExpr *offsetofExpr ) { |
---|
1067 | alternatives.push_back( Alternative( offsetofExpr->clone(), env, Cost::zero ) ); |
---|
1068 | } |
---|
1069 | |
---|
1070 | void AlternativeFinder::visit( OffsetPackExpr *offsetPackExpr ) { |
---|
1071 | alternatives.push_back( Alternative( offsetPackExpr->clone(), env, Cost::zero ) ); |
---|
1072 | } |
---|
1073 | |
---|
1074 | void AlternativeFinder::resolveAttr( DeclarationWithType *funcDecl, FunctionType *function, Type *argType, const TypeEnvironment &env ) { |
---|
1075 | // assume no polymorphism |
---|
1076 | // assume no implicit conversions |
---|
1077 | assert( function->get_parameters().size() == 1 ); |
---|
1078 | PRINT( |
---|
1079 | std::cerr << "resolvAttr: funcDecl is "; |
---|
1080 | funcDecl->print( std::cerr ); |
---|
1081 | std::cerr << " argType is "; |
---|
1082 | argType->print( std::cerr ); |
---|
1083 | std::cerr << std::endl; |
---|
1084 | ) |
---|
1085 | if ( typesCompatibleIgnoreQualifiers( argType, function->get_parameters().front()->get_type(), indexer, env ) ) { |
---|
1086 | alternatives.push_back( Alternative( new AttrExpr( new VariableExpr( funcDecl ), argType->clone() ), env, Cost::zero ) ); |
---|
1087 | for ( std::list< DeclarationWithType* >::iterator i = function->get_returnVals().begin(); i != function->get_returnVals().end(); ++i ) { |
---|
1088 | alternatives.back().expr->set_result( (*i)->get_type()->clone() ); |
---|
1089 | } // for |
---|
1090 | } // if |
---|
1091 | } |
---|
1092 | |
---|
1093 | void AlternativeFinder::visit( AttrExpr *attrExpr ) { |
---|
1094 | // assume no 'pointer-to-attribute' |
---|
1095 | NameExpr *nameExpr = dynamic_cast< NameExpr* >( attrExpr->get_attr() ); |
---|
1096 | assert( nameExpr ); |
---|
1097 | std::list< DeclarationWithType* > attrList; |
---|
1098 | indexer.lookupId( nameExpr->get_name(), attrList ); |
---|
1099 | if ( attrExpr->get_isType() || attrExpr->get_expr() ) { |
---|
1100 | for ( std::list< DeclarationWithType* >::iterator i = attrList.begin(); i != attrList.end(); ++i ) { |
---|
1101 | // check if the type is function |
---|
1102 | if ( FunctionType *function = dynamic_cast< FunctionType* >( (*i)->get_type() ) ) { |
---|
1103 | // assume exactly one parameter |
---|
1104 | if ( function->get_parameters().size() == 1 ) { |
---|
1105 | if ( attrExpr->get_isType() ) { |
---|
1106 | resolveAttr( *i, function, attrExpr->get_type(), env ); |
---|
1107 | } else { |
---|
1108 | AlternativeFinder finder( indexer, env ); |
---|
1109 | finder.find( attrExpr->get_expr() ); |
---|
1110 | for ( AltList::iterator choice = finder.alternatives.begin(); choice != finder.alternatives.end(); ++choice ) { |
---|
1111 | if ( choice->expr->get_result()->size() == 1 ) { |
---|
1112 | resolveAttr(*i, function, choice->expr->get_result(), choice->env ); |
---|
1113 | } // fi |
---|
1114 | } // for |
---|
1115 | } // if |
---|
1116 | } // if |
---|
1117 | } // if |
---|
1118 | } // for |
---|
1119 | } else { |
---|
1120 | for ( std::list< DeclarationWithType* >::iterator i = attrList.begin(); i != attrList.end(); ++i ) { |
---|
1121 | VariableExpr newExpr( *i ); |
---|
1122 | alternatives.push_back( Alternative( newExpr.clone(), env, Cost::zero ) ); |
---|
1123 | renameTypes( alternatives.back().expr ); |
---|
1124 | } // for |
---|
1125 | } // if |
---|
1126 | } |
---|
1127 | |
---|
1128 | void AlternativeFinder::visit( LogicalExpr *logicalExpr ) { |
---|
1129 | AlternativeFinder firstFinder( indexer, env ); |
---|
1130 | firstFinder.findWithAdjustment( logicalExpr->get_arg1() ); |
---|
1131 | for ( AltList::const_iterator first = firstFinder.alternatives.begin(); first != firstFinder.alternatives.end(); ++first ) { |
---|
1132 | AlternativeFinder secondFinder( indexer, first->env ); |
---|
1133 | secondFinder.findWithAdjustment( logicalExpr->get_arg2() ); |
---|
1134 | for ( AltList::const_iterator second = secondFinder.alternatives.begin(); second != secondFinder.alternatives.end(); ++second ) { |
---|
1135 | LogicalExpr *newExpr = new LogicalExpr( first->expr->clone(), second->expr->clone(), logicalExpr->get_isAnd() ); |
---|
1136 | alternatives.push_back( Alternative( newExpr, second->env, first->cost + second->cost ) ); |
---|
1137 | } |
---|
1138 | } |
---|
1139 | } |
---|
1140 | |
---|
1141 | void AlternativeFinder::visit( ConditionalExpr *conditionalExpr ) { |
---|
1142 | // find alternatives for condition |
---|
1143 | AlternativeFinder firstFinder( indexer, env ); |
---|
1144 | firstFinder.findWithAdjustment( conditionalExpr->get_arg1() ); |
---|
1145 | for ( AltList::const_iterator first = firstFinder.alternatives.begin(); first != firstFinder.alternatives.end(); ++first ) { |
---|
1146 | // find alternatives for true expression |
---|
1147 | AlternativeFinder secondFinder( indexer, first->env ); |
---|
1148 | secondFinder.findWithAdjustment( conditionalExpr->get_arg2() ); |
---|
1149 | for ( AltList::const_iterator second = secondFinder.alternatives.begin(); second != secondFinder.alternatives.end(); ++second ) { |
---|
1150 | // find alterantives for false expression |
---|
1151 | AlternativeFinder thirdFinder( indexer, second->env ); |
---|
1152 | thirdFinder.findWithAdjustment( conditionalExpr->get_arg3() ); |
---|
1153 | for ( AltList::const_iterator third = thirdFinder.alternatives.begin(); third != thirdFinder.alternatives.end(); ++third ) { |
---|
1154 | // unify true and false types, then infer parameters to produce new alternatives |
---|
1155 | OpenVarSet openVars; |
---|
1156 | AssertionSet needAssertions, haveAssertions; |
---|
1157 | Alternative newAlt( 0, third->env, first->cost + second->cost + third->cost ); |
---|
1158 | Type* commonType = nullptr; |
---|
1159 | if ( unify( second->expr->get_result(), third->expr->get_result(), newAlt.env, needAssertions, haveAssertions, openVars, indexer, commonType ) ) { |
---|
1160 | ConditionalExpr *newExpr = new ConditionalExpr( first->expr->clone(), second->expr->clone(), third->expr->clone() ); |
---|
1161 | newExpr->set_result( commonType ? commonType : second->expr->get_result()->clone() ); |
---|
1162 | // convert both options to the conditional result type |
---|
1163 | newAlt.cost += computeExpressionConversionCost( newExpr->arg2, newExpr->result, indexer, newAlt.env ); |
---|
1164 | newAlt.cost += computeExpressionConversionCost( newExpr->arg3, newExpr->result, indexer, newAlt.env ); |
---|
1165 | newAlt.expr = newExpr; |
---|
1166 | inferParameters( needAssertions, haveAssertions, newAlt, openVars, back_inserter( alternatives ) ); |
---|
1167 | } // if |
---|
1168 | } // for |
---|
1169 | } // for |
---|
1170 | } // for |
---|
1171 | } |
---|
1172 | |
---|
1173 | void AlternativeFinder::visit( CommaExpr *commaExpr ) { |
---|
1174 | TypeEnvironment newEnv( env ); |
---|
1175 | Expression *newFirstArg = resolveInVoidContext( commaExpr->get_arg1(), indexer, newEnv ); |
---|
1176 | AlternativeFinder secondFinder( indexer, newEnv ); |
---|
1177 | secondFinder.findWithAdjustment( commaExpr->get_arg2() ); |
---|
1178 | for ( AltList::const_iterator alt = secondFinder.alternatives.begin(); alt != secondFinder.alternatives.end(); ++alt ) { |
---|
1179 | alternatives.push_back( Alternative( new CommaExpr( newFirstArg->clone(), alt->expr->clone() ), alt->env, alt->cost ) ); |
---|
1180 | } // for |
---|
1181 | delete newFirstArg; |
---|
1182 | } |
---|
1183 | |
---|
1184 | void AlternativeFinder::visit( RangeExpr * rangeExpr ) { |
---|
1185 | // resolve low and high, accept alternatives whose low and high types unify |
---|
1186 | AlternativeFinder firstFinder( indexer, env ); |
---|
1187 | firstFinder.findWithAdjustment( rangeExpr->get_low() ); |
---|
1188 | for ( AltList::const_iterator first = firstFinder.alternatives.begin(); first != firstFinder.alternatives.end(); ++first ) { |
---|
1189 | AlternativeFinder secondFinder( indexer, first->env ); |
---|
1190 | secondFinder.findWithAdjustment( rangeExpr->get_high() ); |
---|
1191 | for ( AltList::const_iterator second = secondFinder.alternatives.begin(); second != secondFinder.alternatives.end(); ++second ) { |
---|
1192 | OpenVarSet openVars; |
---|
1193 | AssertionSet needAssertions, haveAssertions; |
---|
1194 | Alternative newAlt( 0, second->env, first->cost + second->cost ); |
---|
1195 | Type* commonType = nullptr; |
---|
1196 | if ( unify( first->expr->get_result(), second->expr->get_result(), newAlt.env, needAssertions, haveAssertions, openVars, indexer, commonType ) ) { |
---|
1197 | RangeExpr *newExpr = new RangeExpr( first->expr->clone(), second->expr->clone() ); |
---|
1198 | newExpr->set_result( commonType ? commonType : first->expr->get_result()->clone() ); |
---|
1199 | newAlt.expr = newExpr; |
---|
1200 | inferParameters( needAssertions, haveAssertions, newAlt, openVars, back_inserter( alternatives ) ); |
---|
1201 | } // if |
---|
1202 | } // for |
---|
1203 | } // for |
---|
1204 | } |
---|
1205 | |
---|
1206 | void AlternativeFinder::visit( UntypedTupleExpr *tupleExpr ) { |
---|
1207 | std::list< AlternativeFinder > subExprAlternatives; |
---|
1208 | findSubExprs( tupleExpr->get_exprs().begin(), tupleExpr->get_exprs().end(), back_inserter( subExprAlternatives ) ); |
---|
1209 | std::list< AltList > possibilities; |
---|
1210 | combos( subExprAlternatives.begin(), subExprAlternatives.end(), back_inserter( possibilities ) ); |
---|
1211 | for ( std::list< AltList >::const_iterator i = possibilities.begin(); i != possibilities.end(); ++i ) { |
---|
1212 | std::list< Expression * > exprs; |
---|
1213 | makeExprList( *i, exprs ); |
---|
1214 | |
---|
1215 | TypeEnvironment compositeEnv; |
---|
1216 | simpleCombineEnvironments( i->begin(), i->end(), compositeEnv ); |
---|
1217 | alternatives.push_back( Alternative( new TupleExpr( exprs ) , compositeEnv, sumCost( *i ) ) ); |
---|
1218 | } // for |
---|
1219 | } |
---|
1220 | |
---|
1221 | void AlternativeFinder::visit( TupleExpr *tupleExpr ) { |
---|
1222 | alternatives.push_back( Alternative( tupleExpr->clone(), env, Cost::zero ) ); |
---|
1223 | } |
---|
1224 | |
---|
1225 | void AlternativeFinder::visit( ImplicitCopyCtorExpr * impCpCtorExpr ) { |
---|
1226 | alternatives.push_back( Alternative( impCpCtorExpr->clone(), env, Cost::zero ) ); |
---|
1227 | } |
---|
1228 | |
---|
1229 | void AlternativeFinder::visit( ConstructorExpr * ctorExpr ) { |
---|
1230 | AlternativeFinder finder( indexer, env ); |
---|
1231 | // don't prune here, since it's guaranteed all alternatives will have the same type |
---|
1232 | // (giving the alternatives different types is half of the point of ConstructorExpr nodes) |
---|
1233 | finder.findWithoutPrune( ctorExpr->get_callExpr() ); |
---|
1234 | for ( Alternative & alt : finder.alternatives ) { |
---|
1235 | alternatives.push_back( Alternative( new ConstructorExpr( alt.expr->clone() ), alt.env, alt.cost ) ); |
---|
1236 | } |
---|
1237 | } |
---|
1238 | |
---|
1239 | void AlternativeFinder::visit( TupleIndexExpr *tupleExpr ) { |
---|
1240 | alternatives.push_back( Alternative( tupleExpr->clone(), env, Cost::zero ) ); |
---|
1241 | } |
---|
1242 | |
---|
1243 | void AlternativeFinder::visit( TupleAssignExpr *tupleAssignExpr ) { |
---|
1244 | alternatives.push_back( Alternative( tupleAssignExpr->clone(), env, Cost::zero ) ); |
---|
1245 | } |
---|
1246 | |
---|
1247 | void AlternativeFinder::visit( UniqueExpr *unqExpr ) { |
---|
1248 | AlternativeFinder finder( indexer, env ); |
---|
1249 | finder.findWithAdjustment( unqExpr->get_expr() ); |
---|
1250 | for ( Alternative & alt : finder.alternatives ) { |
---|
1251 | // ensure that the id is passed on to the UniqueExpr alternative so that the expressions are "linked" |
---|
1252 | UniqueExpr * newUnqExpr = new UniqueExpr( alt.expr->clone(), unqExpr->get_id() ); |
---|
1253 | alternatives.push_back( Alternative( newUnqExpr, alt.env, alt.cost ) ); |
---|
1254 | } |
---|
1255 | } |
---|
1256 | |
---|
1257 | void AlternativeFinder::visit( StmtExpr *stmtExpr ) { |
---|
1258 | StmtExpr * newStmtExpr = stmtExpr->clone(); |
---|
1259 | ResolvExpr::resolveStmtExpr( newStmtExpr, indexer ); |
---|
1260 | // xxx - this env is almost certainly wrong, and needs to somehow contain the combined environments from all of the statements in the stmtExpr... |
---|
1261 | alternatives.push_back( Alternative( newStmtExpr, env, Cost::zero ) ); |
---|
1262 | } |
---|
1263 | |
---|
1264 | void AlternativeFinder::visit( UntypedInitExpr *initExpr ) { |
---|
1265 | // handle each option like a cast |
---|
1266 | AltList candidates; |
---|
1267 | PRINT( std::cerr << "untyped init expr: " << initExpr << std::endl; ) |
---|
1268 | // O(N^2) checks of d-types with e-types |
---|
1269 | for ( InitAlternative & initAlt : initExpr->get_initAlts() ) { |
---|
1270 | Type * toType = resolveTypeof( initAlt.type->clone(), indexer ); |
---|
1271 | SymTab::validateType( toType, &indexer ); |
---|
1272 | adjustExprType( toType, env, indexer ); |
---|
1273 | // Ideally the call to findWithAdjustment could be moved out of the loop, but unfortunately it currently has to occur inside or else |
---|
1274 | // polymorphic return types are not properly bound to the initialization type, since return type variables are only open for the duration of resolving |
---|
1275 | // the UntypedExpr. This is only actually an issue in initialization contexts that allow more than one possible initialization type, but it is still suboptimal. |
---|
1276 | AlternativeFinder finder( indexer, env ); |
---|
1277 | finder.targetType = toType; |
---|
1278 | finder.findWithAdjustment( initExpr->get_expr() ); |
---|
1279 | for ( Alternative & alt : finder.get_alternatives() ) { |
---|
1280 | TypeEnvironment newEnv( alt.env ); |
---|
1281 | AssertionSet needAssertions, haveAssertions; |
---|
1282 | OpenVarSet openVars; // find things in env that don't have a "representative type" and claim those are open vars? |
---|
1283 | PRINT( std::cerr << " @ " << toType << " " << initAlt.designation << std::endl; ) |
---|
1284 | // It's possible that a cast can throw away some values in a multiply-valued expression. (An example is a |
---|
1285 | // cast-to-void, which casts from one value to zero.) Figure out the prefix of the subexpression results |
---|
1286 | // that are cast directly. The candidate is invalid if it has fewer results than there are types to cast |
---|
1287 | // to. |
---|
1288 | int discardedValues = alt.expr->get_result()->size() - toType->size(); |
---|
1289 | if ( discardedValues < 0 ) continue; |
---|
1290 | // xxx - may need to go into tuple types and extract relevant types and use unifyList. Note that currently, this does not |
---|
1291 | // allow casting a tuple to an atomic type (e.g. (int)([1, 2, 3])) |
---|
1292 | // unification run for side-effects |
---|
1293 | unify( toType, alt.expr->get_result(), newEnv, needAssertions, haveAssertions, openVars, indexer ); // xxx - do some inspecting on this line... why isn't result bound to initAlt.type?? |
---|
1294 | |
---|
1295 | Cost thisCost = castCost( alt.expr->get_result(), toType, indexer, newEnv ); |
---|
1296 | if ( thisCost != Cost::infinity ) { |
---|
1297 | // count one safe conversion for each value that is thrown away |
---|
1298 | thisCost.incSafe( discardedValues ); |
---|
1299 | Alternative newAlt( new InitExpr( restructureCast( alt.expr->clone(), toType ), initAlt.designation->clone() ), newEnv, alt.cost, thisCost ); |
---|
1300 | inferParameters( needAssertions, haveAssertions, newAlt, openVars, back_inserter( candidates ) ); |
---|
1301 | } |
---|
1302 | } |
---|
1303 | } |
---|
1304 | |
---|
1305 | // findMinCost selects the alternatives with the lowest "cost" members, but has the side effect of copying the |
---|
1306 | // cvtCost member to the cost member (since the old cost is now irrelevant). Thus, calling findMinCost twice |
---|
1307 | // selects first based on argument cost, then on conversion cost. |
---|
1308 | AltList minArgCost; |
---|
1309 | findMinCost( candidates.begin(), candidates.end(), std::back_inserter( minArgCost ) ); |
---|
1310 | findMinCost( minArgCost.begin(), minArgCost.end(), std::back_inserter( alternatives ) ); |
---|
1311 | } |
---|
1312 | } // namespace ResolvExpr |
---|
1313 | |
---|
1314 | // Local Variables: // |
---|
1315 | // tab-width: 4 // |
---|
1316 | // mode: c++ // |
---|
1317 | // compile-command: "make install" // |
---|
1318 | // End: // |
---|