Changeset 2890212
- Timestamp:
- Jul 31, 2019, 3:23:04 PM (5 years ago)
- Branches:
- ADT, arm-eh, ast-experimental, enum, forall-pointer-decay, jacob/cs343-translation, master, new-ast, new-ast-unique-expr, pthread-emulation, qualifiedEnum
- Children:
- ae265b55, f49b3fc
- Parents:
- 504eb72
- Location:
- src
- Files:
-
- 9 edited
Legend:
- Unmodified
- Added
- Removed
-
src/AST/Expr.cpp
r504eb72 r2890212 20 20 #include <vector> 21 21 22 #include "Copy.hpp" // for shallowCopy 22 23 #include "Eval.hpp" // for call 23 24 #include "GenericSubstitution.hpp" … … 174 175 assert( var ); 175 176 assert( var->get_type() ); 176 result = var->get_type(); 177 add_qualifiers( result, CV::Lvalue ); 177 auto r = shallowCopy( var->get_type() ); 178 r->qualifiers |= CV::Lvalue; 179 result = r; 178 180 } 179 181 -
src/AST/Node.hpp
r504eb72 r2890212 96 96 assertf( 97 97 node->weak_count == 0, 98 "Error: mutating node with weak references to it will invalid edsome references"98 "Error: mutating node with weak references to it will invalidate some references" 99 99 ); 100 100 return node->clone(); … … 106 106 // skip mutate if equivalent 107 107 if ( node->*field == val ) return node; 108 108 109 109 // mutate and return 110 110 node_t * ret = mutate( node ); -
src/AST/TypeEnvironment.hpp
r504eb72 r2890212 38 38 /// Adding this comparison operator significantly improves assertion satisfaction run time for 39 39 /// some cases. The current satisfaction algorithm's speed partially depends on the order of 40 /// assertions. Assertions which have fewer possible matches should appear before assertions 41 /// which have more possible matches. This seems to imply that this could be further improved 42 /// by providing an indexer as an additional argument and ordering based on the number of 40 /// assertions. Assertions which have fewer possible matches should appear before assertions 41 /// which have more possible matches. This seems to imply that this could be further improved 42 /// by providing an indexer as an additional argument and ordering based on the number of 43 43 /// matches of the same kind (object, function) for the names of the declarations. 44 44 /// 45 /// I've seen a TU go from 54 minutes to 1 minute 34 seconds with the addition of this 45 /// I've seen a TU go from 54 minutes to 1 minute 34 seconds with the addition of this 46 46 /// comparator. 47 47 /// 48 /// Note: since this compares pointers for position, minor changes in the source file that 49 /// affect memory layout can alter compilation time in unpredictable ways. For example, the 50 /// placement of a line directive can reorder type pointers with respect to each other so that 51 /// assertions are seen in different orders, causing a potentially different number of 52 /// unification calls when resolving assertions. I've seen a TU go from 36 seconds to 27 53 /// seconds by reordering line directives alone, so it would be nice to fix this comparison so 54 /// that assertions compare more consistently. I've tried to modify this to compare on mangle 55 /// name instead of type as the second comparator, but this causes some assertions to never be 48 /// Note: since this compares pointers for position, minor changes in the source file that 49 /// affect memory layout can alter compilation time in unpredictable ways. For example, the 50 /// placement of a line directive can reorder type pointers with respect to each other so that 51 /// assertions are seen in different orders, causing a potentially different number of 52 /// unification calls when resolving assertions. I've seen a TU go from 36 seconds to 27 53 /// seconds by reordering line directives alone, so it would be nice to fix this comparison so 54 /// that assertions compare more consistently. I've tried to modify this to compare on mangle 55 /// name instead of type as the second comparator, but this causes some assertions to never be 56 56 /// recorded. More investigation is needed. 57 57 struct AssertCompare { … … 87 87 void print( std::ostream &, const OpenVarSet &, Indenter indent = {} ); 88 88 89 /// Represents an equivalence class of bound type variables, optionally with the concrete type 89 /// Represents an equivalence class of bound type variables, optionally with the concrete type 90 90 /// they bind to. 91 91 struct EqvClass { … … 96 96 97 97 EqvClass() : vars(), bound(), allowWidening( true ), data() {} 98 98 99 99 /// Copy-with-bound constructor 100 EqvClass( const EqvClass & o, const Type * b ) 100 EqvClass( const EqvClass & o, const Type * b ) 101 101 : vars( o.vars ), bound( b ), allowWidening( o.allowWidening ), data( o.data ) {} 102 102 … … 143 143 void writeToSubstitution( TypeSubstitution & sub ) const; 144 144 145 template< typename node_t , enum Node::ref_type ref_t>146 int apply( ptr_base< node_t, ref_t >& type ) const {145 template< typename node_t > 146 auto apply( node_t && type ) const { 147 147 TypeSubstitution sub; 148 148 writeToSubstitution( sub ); 149 return sub.apply( type);150 } 151 152 template< typename node_t , enum Node::ref_type ref_t>153 int applyFree( ptr_base< node_t, ref_t >& type ) const {149 return sub.apply( std::forward<node_t>(type) ); 150 } 151 152 template< typename node_t > 153 auto applyFree( node_t && type ) const { 154 154 TypeSubstitution sub; 155 155 writeToSubstitution( sub ); 156 return sub.applyFree( type);156 return sub.applyFree( std::forward<node_t>(type) ); 157 157 } 158 158 … … 173 173 void addActual( const TypeEnvironment & actualEnv, OpenVarSet & openVars ); 174 174 175 /// Binds the type class represented by `typeInst` to the type `bindTo`; will add the class if 175 /// Binds the type class represented by `typeInst` to the type `bindTo`; will add the class if 176 176 /// needed. Returns false on failure. 177 bool bindVar( 178 const TypeInstType * typeInst, const Type * bindTo, const TypeDecl::Data & data, 179 AssertionSet & need, AssertionSet & have, const OpenVarSet & openVars, 177 bool bindVar( 178 const TypeInstType * typeInst, const Type * bindTo, const TypeDecl::Data & data, 179 AssertionSet & need, AssertionSet & have, const OpenVarSet & openVars, 180 180 ResolvExpr::WidenMode widen, const SymbolTable & symtab ); 181 182 /// Binds the type classes represented by `var1` and `var2` together; will add one or both 181 182 /// Binds the type classes represented by `var1` and `var2` together; will add one or both 183 183 /// classes if needed. Returns false on failure. 184 bool bindVarToVar( 185 const TypeInstType * var1, const TypeInstType * var2, TypeDecl::Data && data, 186 AssertionSet & need, AssertionSet & have, const OpenVarSet & openVars, 184 bool bindVarToVar( 185 const TypeInstType * var1, const TypeInstType * var2, TypeDecl::Data && data, 186 AssertionSet & need, AssertionSet & have, const OpenVarSet & openVars, 187 187 ResolvExpr::WidenMode widen, const SymbolTable & symtab ); 188 188 … … 199 199 200 200 /// Unifies the type bound of `to` with the type bound of `from`, returning false if fails 201 bool mergeBound( 201 bool mergeBound( 202 202 EqvClass & to, const EqvClass & from, OpenVarSet & openVars, const SymbolTable & symtab ); 203 203 204 204 /// Merges two type classes from local environment, returning false if fails 205 bool mergeClasses( 206 ClassList::iterator to, ClassList::iterator from, OpenVarSet & openVars, 205 bool mergeClasses( 206 ClassList::iterator to, ClassList::iterator from, OpenVarSet & openVars, 207 207 const SymbolTable & symtab ); 208 208 -
src/AST/TypeSubstitution.cpp
r504eb72 r2890212 146 146 ptr<Type> newType = i->second; // force clone if needed 147 147 add_qualifiers( newType, inst->qualifiers ); 148 // Note: need to recursively apply substitution to the new type because normalize does not 148 // Note: need to recursively apply substitution to the new type because normalize does not 149 149 // substitute bound vars, but bound vars must be substituted when not in freeOnly mode. 150 150 newType = newType->accept( *visitor ); … … 159 159 } else { 160 160 subCount++; 161 delete nameExpr;162 161 return i->second; 163 162 } // if -
src/AST/TypeSubstitution.hpp
r504eb72 r2890212 44 44 TypeSubstitution &operator=( const TypeSubstitution &other ); 45 45 46 template< typename SynTreeClass > int apply( const SynTreeClass *& input ) const; 47 template< typename SynTreeClass > int applyFree( const SynTreeClass *& input ) const; 46 template< typename SynTreeClass > 47 struct ApplyResult { 48 const SynTreeClass * node; 49 int count; 50 }; 51 52 template< typename SynTreeClass > ApplyResult<SynTreeClass> apply( const SynTreeClass * input ) const; 53 template< typename SynTreeClass > ApplyResult<SynTreeClass> applyFree( const SynTreeClass * input ) const; 48 54 49 55 template< typename node_t, enum Node::ref_type ref_t > 50 56 int apply( ptr_base< node_t, ref_t > & input ) const { 51 57 const node_t * p = input.get(); 52 intret = apply(p);53 input = p;54 return ret ;58 auto ret = apply(p); 59 input = ret.node; 60 return ret.count; 55 61 } 56 62 … … 58 64 int applyFree( ptr_base< node_t, ref_t > & input ) const { 59 65 const node_t * p = input.get(); 60 intret = applyFree(p);61 input = p;62 return ret ;66 auto ret = applyFree(p); 67 input = ret.node; 68 return ret.count; 63 69 } 64 70 … … 175 181 176 182 template< typename SynTreeClass > 177 int TypeSubstitution::apply( const SynTreeClass *&input ) const {183 TypeSubstitution::ApplyResult<SynTreeClass> TypeSubstitution::apply( const SynTreeClass * input ) const { 178 184 assert( input ); 179 185 Pass<Substituter> sub( *this, false ); 180 186 input = strict_dynamic_cast< const SynTreeClass * >( input->accept( sub ) ); 181 /// std::cerr << "substitution result is: "; 182 /// newType->print( std::cerr ); 183 /// std::cerr << std::endl; 184 return sub.pass.subCount; 187 return { input, sub.pass.subCount }; 185 188 } 186 189 187 190 template< typename SynTreeClass > 188 int TypeSubstitution::applyFree( const SynTreeClass *&input ) const {191 TypeSubstitution::ApplyResult<SynTreeClass> TypeSubstitution::applyFree( const SynTreeClass * input ) const { 189 192 assert( input ); 190 193 Pass<Substituter> sub( *this, true ); 191 194 input = strict_dynamic_cast< const SynTreeClass * >( input->accept( sub ) ); 192 /// std::cerr << "substitution result is: "; 193 /// newType->print( std::cerr ); 194 /// std::cerr << std::endl; 195 return sub.pass.subCount; 195 return { input, sub.pass.subCount }; 196 196 } 197 197 -
src/ResolvExpr/CandidateFinder.cpp
r504eb72 r2890212 54 54 return new ast::CastExpr{ expr, expr->result->stripReferences() }; 55 55 } 56 56 57 57 return expr; 58 58 } … … 61 61 UniqueId globalResnSlot = 0; 62 62 63 Cost computeConversionCost( 64 const ast::Type * argType, const ast::Type * paramType, const ast::SymbolTable & symtab, 65 const ast::TypeEnvironment & env 63 Cost computeConversionCost( 64 const ast::Type * argType, const ast::Type * paramType, const ast::SymbolTable & symtab, 65 const ast::TypeEnvironment & env 66 66 ) { 67 67 PRINT( … … 107 107 108 108 /// Computes conversion cost for a given expression to a given type 109 const ast::Expr * computeExpressionConversionCost( 110 const ast::Expr * arg, const ast::Type * paramType, const ast::SymbolTable & symtab, const ast::TypeEnvironment & env, Cost & outCost 109 const ast::Expr * computeExpressionConversionCost( 110 const ast::Expr * arg, const ast::Type * paramType, const ast::SymbolTable & symtab, const ast::TypeEnvironment & env, Cost & outCost 111 111 ) { 112 112 Cost convCost = computeConversionCost( arg->result, paramType, symtab, env ); 113 113 outCost += convCost; 114 114 115 // If there is a non-zero conversion cost, ignoring poly cost, then the expression requires 116 // conversion. Ignore poly cost for now, since this requires resolution of the cast to 115 // If there is a non-zero conversion cost, ignoring poly cost, then the expression requires 116 // conversion. Ignore poly cost for now, since this requires resolution of the cast to 117 117 // infer parameters and this does not currently work for the reason stated below 118 118 Cost tmpCost = convCost; … … 123 123 return new ast::CastExpr{ arg, newType }; 124 124 125 // xxx - *should* be able to resolve this cast, but at the moment pointers are not 126 // castable to zero_t, but are implicitly convertible. This is clearly inconsistent, 125 // xxx - *should* be able to resolve this cast, but at the moment pointers are not 126 // castable to zero_t, but are implicitly convertible. This is clearly inconsistent, 127 127 // once this is fixed it should be possible to resolve the cast. 128 // xxx - this isn't working, it appears because type1 (parameter) is seen as widenable, 129 // but it shouldn't be because this makes the conversion from DT* to DT* since 128 // xxx - this isn't working, it appears because type1 (parameter) is seen as widenable, 129 // but it shouldn't be because this makes the conversion from DT* to DT* since 130 130 // commontype(zero_t, DT*) is DT*, rather than nothing 131 131 132 132 // CandidateFinder finder{ symtab, env }; 133 133 // finder.find( arg, ResolvMode::withAdjustment() ); 134 // assertf( finder.candidates.size() > 0, 134 // assertf( finder.candidates.size() > 0, 135 135 // "Somehow castable expression failed to find alternatives." ); 136 // assertf( finder.candidates.size() == 1, 136 // assertf( finder.candidates.size() == 1, 137 137 // "Somehow got multiple alternatives for known cast expression." ); 138 138 // return finder.candidates.front()->expr; … … 143 143 144 144 /// Computes conversion cost for a given candidate 145 Cost computeApplicationConversionCost( 146 CandidateRef cand, const ast::SymbolTable & symtab 145 Cost computeApplicationConversionCost( 146 CandidateRef cand, const ast::SymbolTable & symtab 147 147 ) { 148 148 auto appExpr = cand->expr.strict_as< ast::ApplicationExpr >(); … … 167 167 if ( function->isVarArgs ) { 168 168 convCost.incUnsafe(); 169 PRINT( std::cerr << "end of params with varargs function: inc unsafe: " 169 PRINT( std::cerr << "end of params with varargs function: inc unsafe: " 170 170 << convCost << std::endl; ; ) 171 171 // convert reference-typed expressions into value-typed expressions 172 cand->expr = ast::mutate_field_index( 173 appExpr, &ast::ApplicationExpr::args, i, 172 cand->expr = ast::mutate_field_index( 173 appExpr, &ast::ApplicationExpr::args, i, 174 174 referenceToRvalueConversion( args[i], convCost ) ); 175 175 continue; … … 180 180 // Default arguments should be free - don't include conversion cost. 181 181 // Unwrap them here because they are not relevant to the rest of the system 182 cand->expr = ast::mutate_field_index( 182 cand->expr = ast::mutate_field_index( 183 183 appExpr, &ast::ApplicationExpr::args, i, def->expr ); 184 184 ++param; … … 188 188 // mark conversion cost and also specialization cost of param type 189 189 const ast::Type * paramType = (*param)->get_type(); 190 cand->expr = ast::mutate_field_index( 191 appExpr, &ast::ApplicationExpr::args, i, 192 computeExpressionConversionCost( 190 cand->expr = ast::mutate_field_index( 191 appExpr, &ast::ApplicationExpr::args, i, 192 computeExpressionConversionCost( 193 193 args[i], paramType, symtab, cand->env, convCost ) ); 194 194 convCost.decSpec( specCost( paramType ) ); … … 198 198 if ( param != params.end() ) return Cost::infinity; 199 199 200 // specialization cost of return types can't be accounted for directly, it disables 200 // specialization cost of return types can't be accounted for directly, it disables 201 201 // otherwise-identical calls, like this example based on auto-newline in the I/O lib: 202 202 // … … 215 215 } 216 216 217 void makeUnifiableVars( 218 const ast::ParameterizedType * type, ast::OpenVarSet & unifiableVars, 219 ast::AssertionSet & need 217 void makeUnifiableVars( 218 const ast::ParameterizedType * type, ast::OpenVarSet & unifiableVars, 219 ast::AssertionSet & need 220 220 ) { 221 221 for ( const ast::TypeDecl * tyvar : type->forall ) { … … 254 254 255 255 ArgPack() 256 : parent( 0 ), expr(), cost( Cost::zero ), env(), need(), have(), open(), nextArg( 0 ), 256 : parent( 0 ), expr(), cost( Cost::zero ), env(), need(), have(), open(), nextArg( 0 ), 257 257 tupleStart( 0 ), nextExpl( 0 ), explAlt( 0 ) {} 258 259 ArgPack( 260 const ast::TypeEnvironment & env, const ast::AssertionSet & need, 258 259 ArgPack( 260 const ast::TypeEnvironment & env, const ast::AssertionSet & need, 261 261 const ast::AssertionSet & have, const ast::OpenVarSet & open ) 262 : parent( 0 ), expr(), cost( Cost::zero ), env( env ), need( need ), have( have ), 262 : parent( 0 ), expr(), cost( Cost::zero ), env( env ), need( need ), have( have ), 263 263 open( open ), nextArg( 0 ), tupleStart( 0 ), nextExpl( 0 ), explAlt( 0 ) {} 264 264 265 265 ArgPack( 266 std::size_t parent, const ast::Expr * expr, ast::TypeEnvironment && env, 267 ast::AssertionSet && need, ast::AssertionSet && have, ast::OpenVarSet && open, 268 unsigned nextArg, unsigned tupleStart = 0, Cost cost = Cost::zero, 266 std::size_t parent, const ast::Expr * expr, ast::TypeEnvironment && env, 267 ast::AssertionSet && need, ast::AssertionSet && have, ast::OpenVarSet && open, 268 unsigned nextArg, unsigned tupleStart = 0, Cost cost = Cost::zero, 269 269 unsigned nextExpl = 0, unsigned explAlt = 0 ) 270 270 : parent(parent), expr( expr ), cost( cost ), env( move( env ) ), need( move( need ) ), 271 271 have( move( have ) ), open( move( open ) ), nextArg( nextArg ), tupleStart( tupleStart ), 272 272 nextExpl( nextExpl ), explAlt( explAlt ) {} 273 273 274 274 ArgPack( 275 const ArgPack & o, ast::TypeEnvironment && env, ast::AssertionSet && need, 275 const ArgPack & o, ast::TypeEnvironment && env, ast::AssertionSet && need, 276 276 ast::AssertionSet && have, ast::OpenVarSet && open, unsigned nextArg, Cost added ) 277 : parent( o.parent ), expr( o.expr ), cost( o.cost + added ), env( move( env ) ), 278 need( move( need ) ), have( move( have ) ), open( move( open ) ), nextArg( nextArg ), 277 : parent( o.parent ), expr( o.expr ), cost( o.cost + added ), env( move( env ) ), 278 need( move( need ) ), have( move( have ) ), open( move( open ) ), nextArg( nextArg ), 279 279 tupleStart( o.tupleStart ), nextExpl( 0 ), explAlt( 0 ) {} 280 280 281 281 /// true if this pack is in the middle of an exploded argument 282 282 bool hasExpl() const { return nextExpl > 0; } … … 286 286 return args[ nextArg-1 ][ explAlt ]; 287 287 } 288 288 289 289 /// Ends a tuple expression, consolidating the appropriate args 290 290 void endTuple( const std::vector< ArgPack > & packs ) { … … 307 307 308 308 /// Instantiates an argument to match a parameter, returns false if no matching results left 309 bool instantiateArgument( 310 const ast::Type * paramType, const ast::Init * init, const ExplodedArgs_new & args, 311 std::vector< ArgPack > & results, std::size_t & genStart, const ast::SymbolTable & symtab, 312 unsigned nTuples = 0 309 bool instantiateArgument( 310 const ast::Type * paramType, const ast::Init * init, const ExplodedArgs_new & args, 311 std::vector< ArgPack > & results, std::size_t & genStart, const ast::SymbolTable & symtab, 312 unsigned nTuples = 0 313 313 ) { 314 314 if ( auto tupleType = dynamic_cast< const ast::TupleType * >( paramType ) ) { … … 318 318 // xxx - dropping initializer changes behaviour from previous, but seems correct 319 319 // ^^^ need to handle the case where a tuple has a default argument 320 if ( ! instantiateArgument( 320 if ( ! instantiateArgument( 321 321 type, nullptr, args, results, genStart, symtab, nTuples ) ) return false; 322 322 nTuples = 0; … … 329 329 } else if ( const ast::TypeInstType * ttype = Tuples::isTtype( paramType ) ) { 330 330 // paramType is a ttype, consumes all remaining arguments 331 331 332 332 // completed tuples; will be spliced to end of results to finish 333 333 std::vector< ArgPack > finalResults{}; … … 342 342 for ( std::size_t i = genStart; i < genEnd; ++i ) { 343 343 unsigned nextArg = results[i].nextArg; 344 344 345 345 // use next element of exploded tuple if present 346 346 if ( results[i].hasExpl() ) { … … 352 352 results.emplace_back( 353 353 i, expl.exprs[ results[i].nextExpl ], copy( results[i].env ), 354 copy( results[i].need ), copy( results[i].have ), 354 copy( results[i].need ), copy( results[i].have ), 355 355 copy( results[i].open ), nextArg, nTuples, Cost::zero, nextExpl, 356 356 results[i].explAlt ); … … 398 398 399 399 // check unification for ttype before adding to final 400 if ( 401 unify( 400 if ( 401 unify( 402 402 ttype, argType, newResult.env, newResult.need, newResult.have, 403 newResult.open, symtab ) 403 newResult.open, symtab ) 404 404 ) { 405 405 finalResults.emplace_back( move( newResult ) ); … … 422 422 if ( expl.exprs.empty() ) { 423 423 results.emplace_back( 424 results[i], move( env ), copy( results[i].need ), 424 results[i], move( env ), copy( results[i].need ), 425 425 copy( results[i].have ), move( open ), nextArg + 1, expl.cost ); 426 426 427 427 continue; 428 428 } … … 430 430 // add new result 431 431 results.emplace_back( 432 i, expl.exprs.front(), move( env ), copy( results[i].need ), 433 copy( results[i].have ), move( open ), nextArg + 1, nTuples, 432 i, expl.exprs.front(), move( env ), copy( results[i].need ), 433 copy( results[i].have ), move( open ), nextArg + 1, nTuples, 434 434 expl.cost, expl.exprs.size() == 1 ? 0 : 1, j ); 435 435 } … … 477 477 478 478 results.emplace_back( 479 i, expr, move( env ), move( need ), move( have ), move( open ), nextArg, 479 i, expr, move( env ), move( need ), move( have ), move( open ), nextArg, 480 480 nTuples, Cost::zero, nextExpl, results[i].explAlt ); 481 481 } … … 493 493 if ( unify( paramType, cnst->result, env, need, have, open, symtab ) ) { 494 494 results.emplace_back( 495 i, new ast::DefaultArgExpr{ cnst->location, cnst }, move( env ), 495 i, new ast::DefaultArgExpr{ cnst->location, cnst }, move( env ), 496 496 move( need ), move( have ), move( open ), nextArg, nTuples ); 497 497 } … … 515 515 if ( expl.exprs.empty() ) { 516 516 results.emplace_back( 517 results[i], move( env ), move( need ), move( have ), move( open ), 517 results[i], move( env ), move( need ), move( have ), move( open ), 518 518 nextArg + 1, expl.cost ); 519 519 520 520 continue; 521 521 } … … 537 537 // add new result 538 538 results.emplace_back( 539 i, expr, move( env ), move( need ), move( have ), move( open ), 539 i, expr, move( env ), move( need ), move( have ), move( open ), 540 540 nextArg + 1, nTuples, expl.cost, expl.exprs.size() == 1 ? 0 : 1, j ); 541 541 } … … 550 550 551 551 /// Generate a cast expression from `arg` to `toType` 552 const ast::Expr * restructureCast( 552 const ast::Expr * restructureCast( 553 553 ast::ptr< ast::Expr > & arg, const ast::Type * toType, ast::GeneratedFlag isGenerated = ast::GeneratedCast 554 554 ) { 555 if ( 556 arg->result->size() > 1 557 && ! toType->isVoid() 558 && ! dynamic_cast< const ast::ReferenceType * >( toType ) 555 if ( 556 arg->result->size() > 1 557 && ! toType->isVoid() 558 && ! dynamic_cast< const ast::ReferenceType * >( toType ) 559 559 ) { 560 // Argument is a tuple and the target type is neither void nor a reference. Cast each 561 // member of the tuple to its corresponding target type, producing the tuple of those 562 // cast expressions. If there are more components of the tuple than components in the 563 // target type, then excess components do not come out in the result expression (but 560 // Argument is a tuple and the target type is neither void nor a reference. Cast each 561 // member of the tuple to its corresponding target type, producing the tuple of those 562 // cast expressions. If there are more components of the tuple than components in the 563 // target type, then excess components do not come out in the result expression (but 564 564 // UniqueExpr ensures that the side effects will still be produced) 565 565 if ( Tuples::maybeImpureIgnoreUnique( arg ) ) { 566 // expressions which may contain side effects require a single unique instance of 566 // expressions which may contain side effects require a single unique instance of 567 567 // the expression 568 568 arg = new ast::UniqueExpr{ arg->location, arg }; … … 572 572 // cast each component 573 573 ast::ptr< ast::Expr > idx = new ast::TupleIndexExpr{ arg->location, arg, i }; 574 components.emplace_back( 574 components.emplace_back( 575 575 restructureCast( idx, toType->getComponent( i ), isGenerated ) ); 576 576 } … … 601 601 602 602 Finder( CandidateFinder & f ) 603 : symtab( f.localSyms ), selfFinder( f ), candidates( f.candidates ), tenv( f.env ), 603 : symtab( f.localSyms ), selfFinder( f ), candidates( f.candidates ), tenv( f.env ), 604 604 targetType( f.targetType ) {} 605 605 606 606 void previsit( const ast::Node * ) { visit_children = false; } 607 607 … … 638 638 639 639 /// Completes a function candidate with arguments located 640 void validateFunctionCandidate( 641 const CandidateRef & func, ArgPack & result, const std::vector< ArgPack > & results, 642 CandidateList & out 640 void validateFunctionCandidate( 641 const CandidateRef & func, ArgPack & result, const std::vector< ArgPack > & results, 642 CandidateList & out 643 643 ) { 644 ast::ApplicationExpr * appExpr = 644 ast::ApplicationExpr * appExpr = 645 645 new ast::ApplicationExpr{ func->expr->location, func->expr }; 646 646 // sum cost and accumulate arguments … … 656 656 appExpr->args = move( vargs ); 657 657 // build and validate new candidate 658 auto newCand = 658 auto newCand = 659 659 std::make_shared<Candidate>( appExpr, result.env, result.open, result.need, cost ); 660 660 PRINT( … … 668 668 /// Builds a list of candidates for a function, storing them in out 669 669 void makeFunctionCandidates( 670 const CandidateRef & func, const ast::FunctionType * funcType, 670 const CandidateRef & func, const ast::FunctionType * funcType, 671 671 const ExplodedArgs_new & args, CandidateList & out 672 672 ) { … … 675 675 ast::TypeEnvironment funcEnv{ func->env }; 676 676 makeUnifiableVars( funcType, funcOpen, funcNeed ); 677 // add all type variables as open variables now so that those not used in the 677 // add all type variables as open variables now so that those not used in the 678 678 // parameter list are still considered open 679 679 funcEnv.add( funcType->forall ); … … 682 682 // attempt to narrow based on expected target type 683 683 const ast::Type * returnType = funcType->returns.front()->get_type(); 684 if ( ! unify( 685 returnType, targetType, funcEnv, funcNeed, funcHave, funcOpen, symtab ) 684 if ( ! unify( 685 returnType, targetType, funcEnv, funcNeed, funcHave, funcOpen, symtab ) 686 686 ) { 687 687 // unification failed, do not pursue this candidate … … 697 697 for ( const ast::DeclWithType * param : funcType->params ) { 698 698 auto obj = strict_dynamic_cast< const ast::ObjectDecl * >( param ); 699 // Try adding the arguments corresponding to the current parameter to the existing 699 // Try adding the arguments corresponding to the current parameter to the existing 700 700 // matches 701 if ( ! instantiateArgument( 701 if ( ! instantiateArgument( 702 702 obj->type, obj->init, args, results, genStart, symtab ) ) return; 703 703 } … … 749 749 if ( expl.exprs.empty() ) { 750 750 results.emplace_back( 751 results[i], move( env ), copy( results[i].need ), 752 copy( results[i].have ), move( open ), nextArg + 1, 751 results[i], move( env ), copy( results[i].need ), 752 copy( results[i].have ), move( open ), nextArg + 1, 753 753 expl.cost ); 754 754 … … 759 759 results.emplace_back( 760 760 i, expl.exprs.front(), move( env ), copy( results[i].need ), 761 copy( results[i].have ), move( open ), nextArg + 1, 0, expl.cost, 761 copy( results[i].have ), move( open ), nextArg + 1, 0, expl.cost, 762 762 expl.exprs.size() == 1 ? 0 : 1, j ); 763 763 } … … 779 779 /// Adds implicit struct-conversions to the alternative list 780 780 void addAnonConversions( const CandidateRef & cand ) { 781 // adds anonymous member interpretations whenever an aggregate value type is seen. 782 // it's okay for the aggregate expression to have reference type -- cast it to the 781 // adds anonymous member interpretations whenever an aggregate value type is seen. 782 // it's okay for the aggregate expression to have reference type -- cast it to the 783 783 // base type to treat the aggregate as the referenced value 784 784 ast::ptr< ast::Expr > aggrExpr( cand->expr ); 785 785 ast::ptr< ast::Type > & aggrType = aggrExpr.get_and_mutate()->result; 786 786 cand->env.apply( aggrType ); 787 787 788 788 if ( aggrType.as< ast::ReferenceType >() ) { 789 789 aggrExpr = new ast::CastExpr{ aggrExpr, aggrType->stripReferences() }; … … 798 798 799 799 /// Adds aggregate member interpretations 800 void addAggMembers( 801 const ast::ReferenceToType * aggrInst, const ast::Expr * expr, 802 const Candidate & cand, const Cost & addedCost, const std::string & name 800 void addAggMembers( 801 const ast::ReferenceToType * aggrInst, const ast::Expr * expr, 802 const Candidate & cand, const Cost & addedCost, const std::string & name 803 803 ) { 804 804 for ( const ast::Decl * decl : aggrInst->lookup( name ) ) { 805 805 auto dwt = strict_dynamic_cast< const ast::DeclWithType * >( decl ); 806 CandidateRef newCand = std::make_shared<Candidate>( 806 CandidateRef newCand = std::make_shared<Candidate>( 807 807 cand, new ast::MemberExpr{ expr->location, dwt, expr }, addedCost ); 808 // add anonymous member interpretations whenever an aggregate value type is seen 808 // add anonymous member interpretations whenever an aggregate value type is seen 809 809 // as a member expression 810 810 addAnonConversions( newCand ); … … 814 814 815 815 /// Adds tuple member interpretations 816 void addTupleMembers( 817 const ast::TupleType * tupleType, const ast::Expr * expr, const Candidate & cand, 818 const Cost & addedCost, const ast::Expr * member 816 void addTupleMembers( 817 const ast::TupleType * tupleType, const ast::Expr * expr, const Candidate & cand, 818 const Cost & addedCost, const ast::Expr * member 819 819 ) { 820 820 if ( auto constantExpr = dynamic_cast< const ast::ConstantExpr * >( member ) ) { 821 // get the value of the constant expression as an int, must be between 0 and the 821 // get the value of the constant expression as an int, must be between 0 and the 822 822 // length of the tuple to have meaning 823 823 long long val = constantExpr->intValue(); 824 824 if ( val >= 0 && (unsigned long long)val < tupleType->size() ) { 825 825 addCandidate( 826 cand, new ast::TupleIndexExpr{ expr->location, expr, (unsigned)val }, 826 cand, new ast::TupleIndexExpr{ expr->location, expr, (unsigned)val }, 827 827 addedCost ); 828 828 } … … 836 836 if ( funcFinder.candidates.empty() ) return; 837 837 838 std::vector< CandidateFinder > argCandidates = 838 std::vector< CandidateFinder > argCandidates = 839 839 selfFinder.findSubExprs( untypedExpr->args ); 840 840 841 841 // take care of possible tuple assignments 842 842 // if not tuple assignment, handled as normal function call … … 876 876 if ( auto function = pointer->base.as< ast::FunctionType >() ) { 877 877 CandidateRef newFunc{ new Candidate{ *func } }; 878 newFunc->expr = 878 newFunc->expr = 879 879 referenceToRvalueConversion( newFunc->expr, newFunc->cost ); 880 880 makeFunctionCandidates( newFunc, function, argExpansions, found ); 881 881 } 882 } else if ( 883 auto inst = dynamic_cast< const ast::TypeInstType * >( funcResult ) 882 } else if ( 883 auto inst = dynamic_cast< const ast::TypeInstType * >( funcResult ) 884 884 ) { 885 885 if ( const ast::EqvClass * clz = func->env.lookup( inst->name ) ) { 886 886 if ( auto function = clz->bound.as< ast::FunctionType >() ) { 887 887 CandidateRef newFunc{ new Candidate{ *func } }; 888 newFunc->expr = 888 newFunc->expr = 889 889 referenceToRvalueConversion( newFunc->expr, newFunc->cost ); 890 890 makeFunctionCandidates( newFunc, function, argExpansions, found ); … … 900 900 std::vector< ExplodedArg > funcE; 901 901 funcE.reserve( funcFinder.candidates.size() ); 902 for ( const CandidateRef & func : funcFinder ) { 902 for ( const CandidateRef & func : funcFinder ) { 903 903 funcE.emplace_back( *func, symtab ); 904 904 } … … 912 912 if ( auto function = pointer->base.as< ast::FunctionType >() ) { 913 913 CandidateRef newOp{ new Candidate{ *op} }; 914 newOp->expr = 914 newOp->expr = 915 915 referenceToRvalueConversion( newOp->expr, newOp->cost ); 916 916 makeFunctionCandidates( newOp, function, argExpansions, found ); … … 921 921 } 922 922 923 // Implement SFINAE; resolution errors are only errors if there aren't any non-error 923 // Implement SFINAE; resolution errors are only errors if there aren't any non-error 924 924 // candidates 925 925 if ( found.empty() && ! errors.isEmpty() ) { throw errors; } … … 933 933 auto pointer = appExpr->func->result.strict_as< ast::PointerType >(); 934 934 auto function = pointer->base.strict_as< ast::FunctionType >(); 935 935 936 936 std::cerr << "Case +++++++++++++ " << appExpr->func << std::endl; 937 937 std::cerr << "parameters are:" << std::endl; … … 956 956 promoteCvtCost( winners ); 957 957 958 // function may return a struct/union value, in which case we need to add candidates 959 // for implicit conversions to each of the anonymous members, which must happen after 958 // function may return a struct/union value, in which case we need to add candidates 959 // for implicit conversions to each of the anonymous members, which must happen after 960 960 // `findMinCost`, since anon conversions are never the cheapest 961 961 for ( const CandidateRef & c : winners ) { … … 965 965 966 966 if ( candidates.empty() && targetType && ! targetType->isVoid() ) { 967 // If resolution is unsuccessful with a target type, try again without, since it 967 // If resolution is unsuccessful with a target type, try again without, since it 968 968 // will sometimes succeed when it wouldn't with a target type binding. 969 969 // For example: … … 1015 1015 cand->env.extractOpenVars( open ); 1016 1016 1017 // It is possible that a cast can throw away some values in a multiply-valued 1018 // expression, e.g. cast-to-void, one value to zero. Figure out the prefix of the 1019 // subexpression results that are cast directly. The candidate is invalid if it 1017 // It is possible that a cast can throw away some values in a multiply-valued 1018 // expression, e.g. cast-to-void, one value to zero. Figure out the prefix of the 1019 // subexpression results that are cast directly. The candidate is invalid if it 1020 1020 // has fewer results than there are types to cast to. 1021 1021 int discardedValues = cand->expr->result->size() - toType->size(); … … 1036 1036 // count one safe conversion for each value that is thrown away 1037 1037 thisCost.incSafe( discardedValues ); 1038 CandidateRef newCand = std::make_shared<Candidate>( 1039 restructureCast( cand->expr, toType, castExpr->isGenerated ), 1040 copy( cand->env ), move( open ), move( need ), cand->cost, 1038 CandidateRef newCand = std::make_shared<Candidate>( 1039 restructureCast( cand->expr, toType, castExpr->isGenerated ), 1040 copy( cand->env ), move( open ), move( need ), cand->cost, 1041 1041 cand->cost + thisCost ); 1042 1042 inferParameters( newCand, matches ); … … 1056 1056 finder.find( castExpr->arg, ResolvMode::withoutPrune() ); 1057 1057 for ( CandidateRef & r : finder.candidates ) { 1058 addCandidate( 1059 *r, 1058 addCandidate( 1059 *r, 1060 1060 new ast::VirtualCastExpr{ castExpr->location, r->expr, castExpr->result } ); 1061 1061 } … … 1066 1066 aggFinder.find( memberExpr->aggregate, ResolvMode::withAdjustment() ); 1067 1067 for ( CandidateRef & agg : aggFinder.candidates ) { 1068 // it's okay for the aggregate expression to have reference type -- cast it to the 1068 // it's okay for the aggregate expression to have reference type -- cast it to the 1069 1069 // base type to treat the aggregate as the referenced value 1070 1070 Cost addedCost = Cost::zero; … … 1073 1073 // find member of the given type 1074 1074 if ( auto structInst = agg->expr->result.as< ast::StructInstType >() ) { 1075 addAggMembers( 1075 addAggMembers( 1076 1076 structInst, agg->expr, *agg, addedCost, getMemberName( memberExpr ) ); 1077 1077 } else if ( auto unionInst = agg->expr->result.as< ast::UnionInstType >() ) { 1078 addAggMembers( 1078 addAggMembers( 1079 1079 unionInst, agg->expr, *agg, addedCost, getMemberName( memberExpr ) ); 1080 1080 } else if ( auto tupleType = agg->expr->result.as< ast::TupleType >() ) { … … 1096 1096 1097 1097 CandidateRef newCand = std::make_shared<Candidate>( 1098 newExpr, copy( tenv ), ast::OpenVarSet{}, ast::AssertionSet{}, Cost::zero, 1098 newExpr, copy( tenv ), ast::OpenVarSet{}, ast::AssertionSet{}, Cost::zero, 1099 1099 cost ); 1100 1100 PRINT( … … 1106 1106 std::cerr << std::endl; 1107 1107 ) 1108 newCand->expr = ast::mutate_field( 1109 newCand->expr.get(), &ast::Expr::result, 1108 newCand->expr = ast::mutate_field( 1109 newCand->expr.get(), &ast::Expr::result, 1110 1110 renameTyVars( newCand->expr->result ) ); 1111 // add anonymous member interpretations whenever an aggregate value type is seen 1111 // add anonymous member interpretations whenever an aggregate value type is seen 1112 1112 // as a name expression 1113 1113 addAnonConversions( newCand ); … … 1119 1119 // not sufficient to just pass `variableExpr` here, type might have changed since 1120 1120 // creation 1121 addCandidate( 1121 addCandidate( 1122 1122 new ast::VariableExpr{ variableExpr->location, variableExpr->var }, tenv ); 1123 1123 } … … 1129 1129 void postvisit( const ast::SizeofExpr * sizeofExpr ) { 1130 1130 if ( sizeofExpr->type ) { 1131 addCandidate( 1132 new ast::SizeofExpr{ 1133 sizeofExpr->location, resolveTypeof( sizeofExpr->type, symtab ) }, 1131 addCandidate( 1132 new ast::SizeofExpr{ 1133 sizeofExpr->location, resolveTypeof( sizeofExpr->type, symtab ) }, 1134 1134 tenv ); 1135 1135 } else { … … 1140 1140 CandidateList winners = findMinCost( finder.candidates ); 1141 1141 if ( winners.size() != 1 ) { 1142 SemanticError( 1142 SemanticError( 1143 1143 sizeofExpr->expr.get(), "Ambiguous expression in sizeof operand: " ); 1144 1144 } … … 1153 1153 void postvisit( const ast::AlignofExpr * alignofExpr ) { 1154 1154 if ( alignofExpr->type ) { 1155 addCandidate( 1156 new ast::AlignofExpr{ 1157 alignofExpr->location, resolveTypeof( alignofExpr->type, symtab ) }, 1155 addCandidate( 1156 new ast::AlignofExpr{ 1157 alignofExpr->location, resolveTypeof( alignofExpr->type, symtab ) }, 1158 1158 tenv ); 1159 1159 } else { … … 1164 1164 CandidateList winners = findMinCost( finder.candidates ); 1165 1165 if ( winners.size() != 1 ) { 1166 SemanticError( 1166 SemanticError( 1167 1167 alignofExpr->expr.get(), "Ambiguous expression in alignof operand: " ); 1168 1168 } … … 1171 1171 choice->expr = referenceToRvalueConversion( choice->expr, choice->cost ); 1172 1172 choice->cost = Cost::zero; 1173 addCandidate( 1173 addCandidate( 1174 1174 *choice, new ast::AlignofExpr{ alignofExpr->location, choice->expr } ); 1175 1175 } … … 1184 1184 for ( const ast::Decl * member : aggInst->lookup( offsetofExpr->member ) ) { 1185 1185 auto dwt = strict_dynamic_cast< const ast::DeclWithType * >( member ); 1186 addCandidate( 1186 addCandidate( 1187 1187 new ast::OffsetofExpr{ offsetofExpr->location, aggInst, dwt }, tenv ); 1188 1188 } … … 1217 1217 1218 1218 addCandidate( 1219 new ast::LogicalExpr{ 1219 new ast::LogicalExpr{ 1220 1220 logicalExpr->location, r1->expr, r2->expr, logicalExpr->isAnd }, 1221 1221 move( env ), move( open ), move( need ), r1->cost + r2->cost ); … … 1255 1255 ast::AssertionSet have; 1256 1256 1257 // unify true and false results, then infer parameters to produce new 1257 // unify true and false results, then infer parameters to produce new 1258 1258 // candidates 1259 1259 ast::ptr< ast::Type > common; 1260 if ( 1261 unify( 1262 r2->expr->result, r3->expr->result, env, need, have, open, symtab, 1263 common ) 1260 if ( 1261 unify( 1262 r2->expr->result, r3->expr->result, env, need, have, open, symtab, 1263 common ) 1264 1264 ) { 1265 1265 // generate typed expression 1266 ast::ConditionalExpr * newExpr = new ast::ConditionalExpr{ 1266 ast::ConditionalExpr * newExpr = new ast::ConditionalExpr{ 1267 1267 conditionalExpr->location, r1->expr, r2->expr, r3->expr }; 1268 1268 newExpr->result = common ? common : r2->expr->result; 1269 1269 // convert both options to result type 1270 1270 Cost cost = r1->cost + r2->cost + r3->cost; 1271 newExpr->arg2 = computeExpressionConversionCost( 1271 newExpr->arg2 = computeExpressionConversionCost( 1272 1272 newExpr->arg2, newExpr->result, symtab, env, cost ); 1273 1273 newExpr->arg3 = computeExpressionConversionCost( … … 1286 1286 ast::TypeEnvironment env{ tenv }; 1287 1287 ast::ptr< ast::Expr > arg1 = resolveInVoidContext( commaExpr->arg1, symtab, env ); 1288 1288 1289 1289 CandidateFinder finder2{ symtab, env }; 1290 1290 finder2.find( commaExpr->arg2, ResolvMode::withAdjustment() ); … … 1329 1329 1330 1330 ast::ptr< ast::Type > common; 1331 if ( 1332 unify( 1333 r1->expr->result, r2->expr->result, env, need, have, open, symtab, 1334 common ) 1331 if ( 1332 unify( 1333 r1->expr->result, r2->expr->result, env, need, have, open, symtab, 1334 common ) 1335 1335 ) { 1336 1336 // generate new expression 1337 ast::RangeExpr * newExpr = 1337 ast::RangeExpr * newExpr = 1338 1338 new ast::RangeExpr{ rangeExpr->location, r1->expr, r2->expr }; 1339 1339 newExpr->result = common ? common : r1->expr->result; 1340 1340 // add candidate 1341 1341 CandidateRef newCand = std::make_shared<Candidate>( 1342 newExpr, move( env ), move( open ), move( need ), 1342 newExpr, move( env ), move( open ), move( need ), 1343 1343 r1->cost + r2->cost ); 1344 1344 inferParameters( newCand, candidates ); … … 1349 1349 1350 1350 void postvisit( const ast::UntypedTupleExpr * tupleExpr ) { 1351 std::vector< CandidateFinder > subCandidates = 1351 std::vector< CandidateFinder > subCandidates = 1352 1352 selfFinder.findSubExprs( tupleExpr->exprs ); 1353 1353 std::vector< CandidateList > possibilities; … … 1369 1369 1370 1370 addCandidate( 1371 new ast::TupleExpr{ tupleExpr->location, move( exprs ) }, 1371 new ast::TupleExpr{ tupleExpr->location, move( exprs ) }, 1372 1372 move( env ), move( open ), move( need ), sumCost( subs ) ); 1373 1373 } … … 1411 1411 toType = SymTab::validateType( initExpr->location, toType, symtab ); 1412 1412 toType = adjustExprType( toType, tenv, symtab ); 1413 // The call to find must occur inside this loop, otherwise polymorphic return 1414 // types are not bound to the initialization type, since return type variables are 1415 // only open for the duration of resolving the UntypedExpr. 1413 // The call to find must occur inside this loop, otherwise polymorphic return 1414 // types are not bound to the initialization type, since return type variables are 1415 // only open for the duration of resolving the UntypedExpr. 1416 1416 CandidateFinder finder{ symtab, tenv, toType }; 1417 1417 finder.find( initExpr->expr, ResolvMode::withAdjustment() ); … … 1425 1425 ) 1426 1426 1427 // It is possible that a cast can throw away some values in a multiply-valued 1428 // expression, e.g. cast-to-void, one value to zero. Figure out the prefix of 1429 // the subexpression results that are cast directly. The candidate is invalid 1427 // It is possible that a cast can throw away some values in a multiply-valued 1428 // expression, e.g. cast-to-void, one value to zero. Figure out the prefix of 1429 // the subexpression results that are cast directly. The candidate is invalid 1430 1430 // if it has fewer results than there are types to cast to. 1431 1431 int discardedValues = cand->expr->result->size() - toType->size(); … … 1435 1435 unify( toType, cand->expr->result, env, need, have, open, symtab ); 1436 1436 Cost thisCost = castCost( cand->expr->result, toType, symtab, env ); 1437 1437 1438 1438 if ( thisCost != Cost::infinity ) { 1439 1439 // count one safe conversion for each value that is thrown away 1440 1440 thisCost.incSafe( discardedValues ); 1441 CandidateRef newCand = std::make_shared<Candidate>( 1442 new ast::InitExpr{ 1443 initExpr->location, restructureCast( cand->expr, toType ), 1444 initAlt.designation }, 1441 CandidateRef newCand = std::make_shared<Candidate>( 1442 new ast::InitExpr{ 1443 initExpr->location, restructureCast( cand->expr, toType ), 1444 initAlt.designation }, 1445 1445 copy( cand->env ), move( open ), move( need ), cand->cost, thisCost ); 1446 1446 inferParameters( newCand, matches ); … … 1468 1468 }; 1469 1469 1470 /// Prunes a list of candidates down to those that have the minimum conversion cost for a given 1470 /// Prunes a list of candidates down to those that have the minimum conversion cost for a given 1471 1471 /// return type. Skips ambiguous candidates. 1472 1472 CandidateList pruneCandidates( CandidateList & candidates ) { … … 1493 1493 if ( candidate->cost < found->second.candidate->cost ) { 1494 1494 PRINT( 1495 std::cerr << "cost " << candidate->cost << " beats " 1495 std::cerr << "cost " << candidate->cost << " beats " 1496 1496 << found->second.candidate->cost << std::endl; 1497 1497 ) … … 1499 1499 found->second = PruneStruct{ candidate }; 1500 1500 } else if ( candidate->cost == found->second.candidate->cost ) { 1501 // if one of the candidates contains a deleted identifier, can pick the other, 1502 // since deleted expressions should not be ambiguous if there is another option 1501 // if one of the candidates contains a deleted identifier, can pick the other, 1502 // since deleted expressions should not be ambiguous if there is another option 1503 1503 // that is at least as good 1504 1504 if ( findDeletedExpr( candidate->expr ) ) { … … 1514 1514 } else { 1515 1515 PRINT( 1516 std::cerr << "cost " << candidate->cost << " loses to " 1516 std::cerr << "cost " << candidate->cost << " loses to " 1517 1517 << found->second.candidate->cost << std::endl; 1518 1518 ) … … 1529 1529 1530 1530 CandidateRef cand = target.second.candidate; 1531 1531 1532 1532 ast::ptr< ast::Type > newResult = cand->expr->result; 1533 1533 cand->env.applyFree( newResult ); 1534 1534 cand->expr = ast::mutate_field( 1535 1535 cand->expr.get(), &ast::Expr::result, move( newResult ) ); 1536 1536 1537 1537 out.emplace_back( cand ); 1538 1538 } … … 1582 1582 1583 1583 CandidateList pruned = pruneCandidates( candidates ); 1584 1584 1585 1585 if ( mode.failFast && pruned.empty() ) { 1586 1586 std::ostringstream stream; … … 1601 1601 ) 1602 1602 PRINT( 1603 std::cerr << "there are " << candidates.size() << " alternatives after elimination" 1603 std::cerr << "there are " << candidates.size() << " alternatives after elimination" 1604 1604 << std::endl; 1605 1605 ) 1606 1606 } 1607 1607 1608 // adjust types after pruning so that types substituted by pruneAlternatives are correctly 1608 // adjust types after pruning so that types substituted by pruneAlternatives are correctly 1609 1609 // adjusted 1610 1610 if ( mode.adjust ) { 1611 1611 for ( CandidateRef & r : candidates ) { 1612 r->expr = ast::mutate_field( 1613 r->expr.get(), &ast::Expr::result, 1612 r->expr = ast::mutate_field( 1613 r->expr.get(), &ast::Expr::result, 1614 1614 adjustExprType( r->expr->result, r->env, localSyms ) ); 1615 1615 } … … 1624 1624 } 1625 1625 1626 std::vector< CandidateFinder > CandidateFinder::findSubExprs( 1627 const std::vector< ast::ptr< ast::Expr > > & xs 1626 std::vector< CandidateFinder > CandidateFinder::findSubExprs( 1627 const std::vector< ast::ptr< ast::Expr > > & xs 1628 1628 ) { 1629 1629 std::vector< CandidateFinder > out; … … 1632 1632 out.emplace_back( localSyms, env ); 1633 1633 out.back().find( x, ResolvMode::withAdjustment() ); 1634 1634 1635 1635 PRINT( 1636 1636 std::cerr << "findSubExprs" << std::endl; -
src/ResolvExpr/CurrentObject.cc
r504eb72 r2890212 25 25 #include "AST/Init.hpp" // for Designation 26 26 #include "AST/Node.hpp" // for readonly 27 #include "AST/Print.hpp" // for readonly 27 28 #include "AST/Type.hpp" 28 29 #include "Common/Indenter.h" // for Indenter, operator<< … … 596 597 SimpleIterator( const CodeLocation & loc, const Type * t ) : location( loc ), type( t ) {} 597 598 598 void setPosition( 599 std::deque< ptr< Expr > >::const_iterator begin, 599 void setPosition( 600 std::deque< ptr< Expr > >::const_iterator begin, 600 601 std::deque< ptr< Expr > >::const_iterator end 601 602 ) override { … … 637 638 auto res = eval(expr); 638 639 if ( ! res.second ) { 639 SemanticError( location, 640 SemanticError( location, 640 641 toString("Array designator must be a constant expression: ", expr ) ); 641 642 } … … 644 645 645 646 public: 646 ArrayIterator( const CodeLocation & loc, const ArrayType * at ) 647 ArrayIterator( const CodeLocation & loc, const ArrayType * at ) 647 648 : location( loc ), array( at ), base( at->base ) { 648 649 PRINT( std::cerr << "Creating array iterator: " << at << std::endl; ) … … 655 656 656 657 void setPosition( const Expr * expr ) { 657 // need to permit integer-constant-expressions, including: integer constants, 658 // enumeration constants, character constants, sizeof expressions, alignof expressions, 658 // need to permit integer-constant-expressions, including: integer constants, 659 // enumeration constants, character constants, sizeof expressions, alignof expressions, 659 660 // cast expressions 660 661 if ( auto constExpr = dynamic_cast< const ConstantExpr * >( expr ) ) { … … 662 663 index = constExpr->intValue(); 663 664 } catch ( SemanticErrorException & ) { 664 SemanticError( expr, 665 SemanticError( expr, 665 666 "Constant expression of non-integral type in array designator: " ); 666 667 } 667 668 } else if ( auto castExpr = dynamic_cast< const CastExpr * >( expr ) ) { 668 669 setPosition( castExpr->arg ); 669 } else if ( 670 dynamic_cast< const SizeofExpr * >( expr ) 671 || dynamic_cast< const AlignofExpr * >( expr ) 670 } else if ( 671 dynamic_cast< const SizeofExpr * >( expr ) 672 || dynamic_cast< const AlignofExpr * >( expr ) 672 673 ) { 673 674 index = 0; 674 675 } else { 675 assertf( false, 676 assertf( false, 676 677 "bad designator given to ArrayIterator: %s", toString( expr ).c_str() ); 677 678 } 678 679 } 679 680 680 void setPosition( 681 std::deque< ptr< Expr > >::const_iterator begin, 681 void setPosition( 682 std::deque< ptr< Expr > >::const_iterator begin, 682 683 std::deque< ptr< Expr > >::const_iterator end 683 684 ) override { … … 758 759 } 759 760 760 AggregateIterator( 761 const CodeLocation & loc, const std::string k, const std::string & n, const Type * i, 761 AggregateIterator( 762 const CodeLocation & loc, const std::string k, const std::string & n, const Type * i, 762 763 const MemberList & ms ) 763 : location( loc ), kind( k ), name( n ), inst( i ), members( ms ), curMember( ms.begin() ), 764 : location( loc ), kind( k ), name( n ), inst( i ), members( ms ), curMember( ms.begin() ), 764 765 sub( genericSubstitution( i ) ) { 765 766 PRINT( std::cerr << "Creating " << kind << "(" << name << ")"; ) … … 768 769 769 770 public: 770 void setPosition( 771 std::deque< ptr< Expr > >::const_iterator begin, 771 void setPosition( 772 std::deque< ptr< Expr > >::const_iterator begin, 772 773 std::deque< ptr< Expr > >::const_iterator end 773 774 ) final { … … 786 787 return; 787 788 } 788 assertf( false, 789 assertf( false, 789 790 "could not find member in %s: %s", kind.c_str(), toString( varExpr ).c_str() ); 790 791 } else { 791 assertf( false, 792 assertf( false, 792 793 "bad designator given to %s: %s", kind.c_str(), toString( *begin ).c_str() ); 793 794 } … … 842 843 for ( InitAlternative & alt : ret ) { 843 844 PRINT( std::cerr << "iterating and adding designators" << std::endl; ) 844 alt.designation.get_and_mutate()->designators.emplace_front( 845 alt.designation.get_and_mutate()->designators.emplace_front( 845 846 new VariableExpr{ location, curMember->strict_as< ObjectDecl >() } ); 846 847 } … … 897 898 class TupleIterator final : public AggregateIterator { 898 899 public: 899 TupleIterator( const CodeLocation & loc, const TupleType * inst ) 900 : AggregateIterator( 901 loc, "TupleIterator", toString("Tuple", inst->size()), inst, inst->members 900 TupleIterator( const CodeLocation & loc, const TupleType * inst ) 901 : AggregateIterator( 902 loc, "TupleIterator", toString("Tuple", inst->size()), inst, inst->members 902 903 ) {} 903 904 … … 926 927 return new UnionIterator{ loc, uit }; 927 928 } else { 928 assertf( 929 dynamic_cast< const EnumInstType * >( aggr )930 || dynamic_cast< const TypeInstType * >( aggr ),929 assertf( 930 dynamic_cast< const EnumInstType * >( type ) 931 || dynamic_cast< const TypeInstType * >( type ), 931 932 "Encountered unhandled ReferenceToType in createMemberIterator: %s", 932 933 toString( type ).c_str() ); … … 949 950 using DesignatorChain = std::deque< ptr< Expr > >; 950 951 PRINT( std::cerr << "___findNext" << std::endl; ) 951 952 952 953 // find all the d's 953 954 std::vector< DesignatorChain > desigAlts{ {} }, newDesigAlts; … … 1013 1014 // set new designators 1014 1015 assertf( ! objStack.empty(), "empty object stack when setting designation" ); 1015 Designation * actualDesignation = 1016 Designation * actualDesignation = 1016 1017 new Designation{ designation->location, DesignatorChain{d} }; 1017 1018 objStack.back()->setPosition( d ); // destroys d -
src/ResolvExpr/Resolver.cc
r504eb72 r2890212 1054 1054 const ast::Expr * postmutate( const ast::CastExpr * castExpr ) { 1055 1055 if ( 1056 castExpr->isGenerated 1056 castExpr->isGenerated == ast::GeneratedCast 1057 1057 && typesCompatible( castExpr->arg->result, castExpr->result ) 1058 1058 ) { … … 1321 1321 // in case we decide to allow nested enums 1322 1322 GuardValue( inEnumDecl ); 1323 inEnumDecl = false;1323 inEnumDecl = true; 1324 1324 } 1325 1325 -
src/ResolvExpr/Unify.cc
r504eb72 r2890212 25 25 #include <vector> 26 26 27 #include "AST/Copy.hpp" 27 28 #include "AST/Decl.hpp" 28 29 #include "AST/Node.hpp" 29 30 #include "AST/Pass.hpp" 31 #include "AST/Print.hpp" 30 32 #include "AST/Type.hpp" 31 33 #include "AST/TypeEnvironment.hpp" … … 135 137 findOpenVars( newSecond, open, closed, need, have, FirstOpen ); 136 138 137 return unifyExact( 138 newFirst, newSecond, newEnv, need, have, open, noWiden(), symtab ); 139 return unifyExact(newFirst, newSecond, newEnv, need, have, open, noWiden(), symtab ); 139 140 } 140 141 … … 148 149 newFirst->get_qualifiers() = Type::Qualifiers(); 149 150 newSecond->get_qualifiers() = Type::Qualifiers(); 150 /// std::cerr << "first is "; 151 /// first->print( std::cerr ); 152 /// std::cerr << std::endl << "second is "; 153 /// second->print( std::cerr ); 154 /// std::cerr << std::endl << "newFirst is "; 155 /// newFirst->print( std::cerr ); 156 /// std::cerr << std::endl << "newSecond is "; 157 /// newSecond->print( std::cerr ); 158 /// std::cerr << std::endl; 151 159 152 bool result = unifyExact( newFirst, newSecond, newEnv, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer ); 160 153 delete newFirst; … … 170 163 ast::AssertionSet need, have; 171 164 172 ast:: ptr<ast::Type> newFirst{ first }, newSecond{ second };173 env.apply( newFirst);174 env.apply( newSecond );175 reset_qualifiers( newFirst );176 reset_qualifiers( newSecond );165 ast::Type * newFirst = shallowCopy( first ); 166 ast::Type * newSecond = shallowCopy( second ); 167 newFirst ->qualifiers = {}; 168 newSecond->qualifiers = {}; 169 #warning memory leak 177 170 178 171 return unifyExact( 179 newFirst, newSecond, newEnv, need, have, open, noWiden(), symtab ); 172 env.apply( newFirst ).node, 173 env.apply( newSecond ).node, 174 newEnv, need, have, open, noWiden(), symtab ); 180 175 } 181 176 … … 326 321 327 322 void markAssertionSet( AssertionSet &assertions, DeclarationWithType *assert ) { 328 /// std::cerr << "assertion set is" << std::endl;329 /// printAssertionSet( assertions, std::cerr, 8 );330 /// std::cerr << "looking for ";331 /// assert->print( std::cerr );332 /// std::cerr << std::endl;333 323 AssertionSet::iterator i = assertions.find( assert ); 334 324 if ( i != assertions.end() ) { 335 /// std::cerr << "found it!" << std::endl;336 325 i->second.isUsed = true; 337 326 } // if … … 1202 1191 // force t1 and t2 to be cloned if their qualifiers must be stripped, so that type1 and 1203 1192 // type2 are left unchanged; calling convention forces type{1,2}->strong_ref >= 1 1204 ast::ptr<ast::Type> t1{ type1 }, t2{ type2 }; 1205 reset_qualifiers( t1 ); 1206 reset_qualifiers( t2 ); 1193 ast::Type * t1 = shallowCopy(type1.get()); 1194 ast::Type * t2 = shallowCopy(type2.get()); 1195 t1->qualifiers = {}; 1196 t2->qualifiers = {}; 1197 #warning memory leak 1207 1198 1208 1199 if ( unifyExact( t1, t2, env, need, have, open, widen, symtab ) ) { 1209 t1 = nullptr; t2 = nullptr; // release t1, t2 to avoid spurious clones1210 1211 1200 // if exact unification on unqualified types, try to merge qualifiers 1212 1201 if ( q1 == q2 || ( ( q1 > q2 || widen.first ) && ( q2 > q1 || widen.second ) ) ) { 1213 common = type1;1214 reset_qualifiers( common, q1 | q2 );1202 t1->qualifiers = q1 | q2; 1203 common = t1; 1215 1204 return true; 1216 1205 } else { … … 1219 1208 1220 1209 } else if (( common = commonType( t1, t2, widen, symtab, env, open ) )) { 1221 t1 = nullptr; t2 = nullptr; // release t1, t2 to avoid spurious clones1222 1223 1210 // no exact unification, but common type 1224 reset_qualifiers( common, q1 | q2 ); 1211 auto c = shallowCopy(common.get()); 1212 c->qualifiers = q1 | q2; 1213 common = c; 1225 1214 return true; 1226 1215 } else {
Note: See TracChangeset
for help on using the changeset viewer.