Changes in / [849720f:4a60488]
- Files:
-
- 6 added
- 1 deleted
- 40 edited
-
Jenkinsfile (deleted)
-
Jenkinsfile_disabled (added)
-
src/AST/Attribute.hpp (modified) (1 diff)
-
src/AST/Convert.cpp (modified) (2 diffs)
-
src/AST/Copy.hpp (added)
-
src/AST/Decl.cpp (modified) (1 diff)
-
src/AST/Decl.hpp (modified) (6 diffs)
-
src/AST/Eval.hpp (added)
-
src/AST/Expr.cpp (modified) (6 diffs)
-
src/AST/Expr.hpp (modified) (3 diffs)
-
src/AST/ForallSubstitutionTable.cpp (added)
-
src/AST/ForallSubstitutionTable.hpp (added)
-
src/AST/ForallSubstitutor.hpp (added)
-
src/AST/Init.hpp (modified) (1 diff)
-
src/AST/Node.cpp (modified) (2 diffs)
-
src/AST/Node.hpp (modified) (9 diffs)
-
src/AST/Pass.hpp (modified) (6 diffs)
-
src/AST/Pass.impl.hpp (modified) (13 diffs)
-
src/AST/Pass.proto.hpp (modified) (3 diffs)
-
src/AST/Stmt.hpp (modified) (2 diffs)
-
src/AST/Type.cpp (modified) (8 diffs)
-
src/AST/Type.hpp (modified) (12 diffs)
-
src/AST/TypeEnvironment.hpp (modified) (6 diffs)
-
src/AST/TypeSubstitution.cpp (modified) (6 diffs)
-
src/AST/TypeSubstitution.hpp (modified) (4 diffs)
-
src/AST/module.mk (modified) (1 diff)
-
src/Common/ScopedMap.h (modified) (1 diff)
-
src/Makefile.in (modified) (4 diffs)
-
src/ResolvExpr/AdjustExprType.cc (modified) (1 diff)
-
src/ResolvExpr/Candidate.hpp (modified) (2 diffs)
-
src/ResolvExpr/CandidateFinder.cpp (modified) (81 diffs)
-
src/ResolvExpr/CandidateFinder.hpp (modified) (1 diff)
-
src/ResolvExpr/CommonType.cc (modified) (1 diff)
-
src/ResolvExpr/ConversionCost.cc (modified) (4 diffs)
-
src/ResolvExpr/CurrentObject.cc (modified) (15 diffs)
-
src/ResolvExpr/PolyCost.cc (modified) (1 diff)
-
src/ResolvExpr/RenameVars.cc (modified) (11 diffs)
-
src/ResolvExpr/ResolveTypeof.cc (modified) (5 diffs)
-
src/ResolvExpr/Resolver.cc (modified) (6 diffs)
-
src/ResolvExpr/SpecCost.cc (modified) (3 diffs)
-
src/ResolvExpr/Unify.cc (modified) (7 diffs)
-
src/SymTab/Autogen.h (modified) (5 diffs)
-
src/SynTree/Statement.h (modified) (1 diff)
-
src/Tuples/Explode.cc (modified) (1 diff)
-
src/Tuples/Explode.h (modified) (2 diffs)
-
src/Tuples/TupleAssignment.cc (modified) (6 diffs)
-
src/main.cc (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
src/AST/Attribute.hpp
r849720f r4a60488 51 51 template<typename node_t> 52 52 friend node_t * mutate(const node_t * node); 53 template<typename node_t> 54 friend node_t * shallowCopy(const node_t * node); 53 55 }; 54 56 -
src/AST/Convert.cpp
r849720f r4a60488 608 608 609 609 tgt->result = get<Type>().accept1(src->result); 610 // Unconditionally use a clone of the result type. 611 // We know this will leak some objects: much of the immediate conversion result. 612 // In some cases, using the conversion result directly gives unintended object sharing. 613 // A parameter (ObjectDecl, a child of a FunctionType) is shared by the weak-ref cache. 614 // But tgt->result must be fully owned privately by tgt. 615 // Applying these conservative copies here means 616 // - weak references point at the declaration's copy, not these expr.result copies (good) 617 // - we copy more objects than really needed (bad, tolerated) 618 if (tgt->result) { 619 tgt->result = tgt->result->clone(); 620 } 610 621 return visitBaseExpr_skipResultType(src, tgt); 611 622 } … … 2113 2124 old->location, 2114 2125 GET_ACCEPT_1(member, DeclWithType), 2115 GET_ACCEPT_1(aggregate, Expr) 2126 GET_ACCEPT_1(aggregate, Expr), 2127 ast::MemberExpr::NoOpConstructionChosen 2116 2128 ) 2117 2129 ); -
src/AST/Decl.cpp
r849720f r4a60488 52 52 53 53 const Type * FunctionDecl::get_type() const { return type.get(); } 54 void FunctionDecl::set_type(Type * t) { type = strict_dynamic_cast< FunctionType* >( t ); } 54 void FunctionDecl::set_type( const Type * t ) { 55 type = strict_dynamic_cast< const FunctionType * >( t ); 56 } 55 57 56 58 // --- TypeDecl -
src/AST/Decl.hpp
r849720f r4a60488 32 32 33 33 // Must be included in *all* AST classes; should be #undef'd at the end of the file 34 #define MUTATE_FRIEND template<typename node_t> friend node_t * mutate(const node_t * node); 34 #define MUTATE_FRIEND \ 35 template<typename node_t> friend node_t * mutate(const node_t * node); \ 36 template<typename node_t> friend node_t * shallowCopy(const node_t * node); 35 37 36 38 namespace ast { … … 87 89 virtual const Type * get_type() const = 0; 88 90 /// Set type of this declaration. May be verified by subclass 89 virtual void set_type( Type *) = 0;91 virtual void set_type( const Type * ) = 0; 90 92 91 93 const DeclWithType * accept( Visitor & v ) const override = 0; … … 110 112 111 113 const Type* get_type() const override { return type; } 112 void set_type( Type * ty ) override { type = ty; }114 void set_type( const Type * ty ) override { type = ty; } 113 115 114 116 const DeclWithType * accept( Visitor& v ) const override { return v.visit( this ); } … … 132 134 133 135 const Type * get_type() const override; 134 void set_type( Type * t) override;136 void set_type( const Type * t ) override; 135 137 136 138 bool has_body() const { return stmts; } … … 149 151 std::vector<ptr<DeclWithType>> assertions; 150 152 151 NamedTypeDecl( const CodeLocation& loc, const std::string& name, Storage::Classes storage, 152 Type* b, Linkage::Spec spec = Linkage::Cforall ) 153 NamedTypeDecl( 154 const CodeLocation & loc, const std::string & name, Storage::Classes storage, 155 const Type * b, Linkage::Spec spec = Linkage::Cforall ) 153 156 : Decl( loc, name, storage, spec ), base( b ), params(), assertions() {} 154 157 … … 185 188 }; 186 189 187 TypeDecl( const CodeLocation& loc, const std::string& name, Storage::Classes storage, Type* b, 188 TypeVar::Kind k, bool s, Type* i = nullptr ) 190 TypeDecl( 191 const CodeLocation & loc, const std::string & name, Storage::Classes storage, 192 const Type * b, TypeVar::Kind k, bool s, const Type * i = nullptr ) 189 193 : NamedTypeDecl( loc, name, storage, b ), kind( k ), sized( k == TypeVar::Ttype || s ), 190 194 init( i ) {} -
src/AST/Expr.cpp
r849720f r4a60488 20 20 #include <vector> 21 21 22 #include "Copy.hpp" // for shallowCopy 23 #include "Eval.hpp" // for call 22 24 #include "GenericSubstitution.hpp" 23 25 #include "Stmt.hpp" … … 51 53 assert( arg ); 52 54 53 UntypedExpr * ret = new UntypedExpr{ 54 loc, new NameExpr{loc, "*?"}, std::vector<ptr<Expr>>{ ptr<Expr>{ arg } } 55 }; 55 UntypedExpr * ret = call( loc, "*?", arg ); 56 56 if ( const Type * ty = arg->result ) { 57 57 const Type * base = InitTweak::getPointerBase( ty ); … … 74 74 assert( lhs && rhs ); 75 75 76 UntypedExpr * ret = new UntypedExpr{ 77 loc, new NameExpr{loc, "?=?"}, std::vector<ptr<Expr>>{ ptr<Expr>{ lhs }, ptr<Expr>{ rhs } } 78 }; 76 UntypedExpr * ret = call( loc, "?=?", lhs, rhs ); 79 77 if ( lhs->result && rhs->result ) { 80 78 // if both expressions are typed, assumes that this assignment is a C bitwise assignment, … … 160 158 assert( aggregate->result ); 161 159 162 // take ownership of member type 163 result = mem->get_type(); 160 // Deep copy on result type avoids mutation on transitively multiply referenced object. 161 // 162 // Example, adapted from parts of builtins and bootloader: 163 // 164 // forall(dtype T) 165 // struct __Destructor { 166 // T * object; 167 // void (*dtor)(T *); 168 // }; 169 // 170 // forall(dtype S) 171 // void foo(__Destructor(S) &d) { 172 // if (d.dtor) { // here 173 // } 174 // } 175 // 176 // Let e be the "d.dtor" guard espression, which is MemberExpr after resolve. Let d be the 177 // declaration of member __Destructor.dtor (an ObjectDecl), as accessed via the top-level 178 // declaration of __Destructor. Consider the types e.result and d.type. In the old AST, one 179 // is a clone of the other. Ordinary new-AST use would set them up as a multiply-referenced 180 // object. 181 // 182 // e.result: PointerType 183 // .base: FunctionType 184 // .params.front(): ObjectDecl, the anonymous parameter of type T* 185 // .type: PointerType 186 // .base: TypeInstType 187 // let x = that 188 // let y = similar, except start from d.type 189 // 190 // Consider two code lines down, genericSubstitution(...).apply(result). 191 // 192 // Applying this chosen-candidate's type substitution means modifying x, substituting 193 // S for T. This mutation should affect x and not y. 194 195 result = deepCopy(mem->get_type()); 196 164 197 // substitute aggregate generic parameters into member type 165 198 genericSubstitution( aggregate->result ).apply( result ); … … 168 201 } 169 202 203 MemberExpr::MemberExpr( const CodeLocation & loc, const DeclWithType * mem, const Expr * agg, 204 MemberExpr::NoOpConstruction overloadSelector ) 205 : Expr( loc ), member( mem ), aggregate( agg ) { 206 assert( member ); 207 assert( aggregate ); 208 assert( aggregate->result ); 209 (void) overloadSelector; 210 } 211 170 212 // --- VariableExpr 171 213 … … 177 219 assert( var ); 178 220 assert( var->get_type() ); 179 result = var->get_type(); 180 add_qualifiers( result, CV::Lvalue ); 221 auto r = shallowCopy( var->get_type() ); 222 r->qualifiers |= CV::Lvalue; 223 result = r; 181 224 } 182 225 -
src/AST/Expr.hpp
r849720f r4a60488 30 30 31 31 // Must be included in *all* AST classes; should be #undef'd at the end of the file 32 #define MUTATE_FRIEND template<typename node_t> friend node_t * mutate(const node_t * node); 32 #define MUTATE_FRIEND \ 33 template<typename node_t> friend node_t * mutate(const node_t * node); \ 34 template<typename node_t> friend node_t * shallowCopy(const node_t * node); 35 33 36 34 37 class ConverterOldToNew; … … 355 358 MemberExpr * clone() const override { return new MemberExpr{ *this }; } 356 359 MUTATE_FRIEND 360 361 // Custructor overload meant only for AST conversion 362 enum NoOpConstruction { NoOpConstructionChosen }; 363 MemberExpr( const CodeLocation & loc, const DeclWithType * mem, const Expr * agg, 364 NoOpConstruction overloadSelector ); 365 friend class ::ConverterOldToNew; 366 friend class ::ConverterNewToOld; 357 367 }; 358 368 … … 531 541 532 542 CommaExpr( const CodeLocation & loc, const Expr * a1, const Expr * a2 ) 533 : Expr( loc ), arg1( a1 ), arg2( a2 ) {} 543 : Expr( loc ), arg1( a1 ), arg2( a2 ) { 544 this->result = a2->result; 545 } 534 546 535 547 const Expr * accept( Visitor & v ) const override { return v.visit( this ); } -
src/AST/Init.hpp
r849720f r4a60488 25 25 26 26 // Must be included in *all* AST classes; should be #undef'd at the end of the file 27 #define MUTATE_FRIEND template<typename node_t> friend node_t * mutate(const node_t * node); 27 #define MUTATE_FRIEND \ 28 template<typename node_t> friend node_t * mutate(const node_t * node); \ 29 template<typename node_t> friend node_t * shallowCopy(const node_t * node); 28 30 29 31 namespace ast { -
src/AST/Node.cpp
r849720f r4a60488 17 17 #include "Fwd.hpp" 18 18 19 #include <csignal> // MEMORY DEBUG -- for raise 19 20 #include <iostream> 20 21 … … 29 30 #include "Print.hpp" 30 31 31 template< typename node_t, enum ast::Node::ref_type ref_t > 32 void ast::ptr_base<node_t, ref_t>::_inc( const node_t * node ) { node->increment(ref_t); } 33 34 template< typename node_t, enum ast::Node::ref_type ref_t > 35 void ast::ptr_base<node_t, ref_t>::_dec( const node_t * node ) { node->decrement(ref_t); } 36 37 template< typename node_t, enum ast::Node::ref_type ref_t > 38 void ast::ptr_base<node_t, ref_t>::_check() const { if(node) assert(node->was_ever_strong == false || node->strong_count > 0); } 32 /// MEMORY DEBUG -- allows breaking on ref-count changes of dynamically chosen object. 33 /// Process to use in GDB: 34 /// break ast::Node::_trap() 35 /// run 36 /// set variable MEM_TRAP_OBJ = <target> 37 /// disable <first breakpoint> 38 /// continue 39 void * MEM_TRAP_OBJ = nullptr; 40 41 void _trap( const void * node ) { 42 if ( node == MEM_TRAP_OBJ ) std::raise(SIGTRAP); 43 } 44 45 template< typename node_t, enum ast::Node::ref_type ref_t > 46 void ast::ptr_base<node_t, ref_t>::_inc( const node_t * node ) { 47 node->increment(ref_t); 48 _trap( node ); 49 } 50 51 template< typename node_t, enum ast::Node::ref_type ref_t > 52 void ast::ptr_base<node_t, ref_t>::_dec( const node_t * node, bool do_delete ) { 53 _trap( node ); 54 node->decrement(ref_t, do_delete ); 55 } 56 57 template< typename node_t, enum ast::Node::ref_type ref_t > 58 void ast::ptr_base<node_t, ref_t>::_check() const { 59 // if(node) assert(node->was_ever_strong == false || node->strong_count > 0); 60 } 39 61 40 62 template< typename node_t, enum ast::Node::ref_type ref_t > -
src/AST/Node.hpp
r849720f r4a60488 38 38 Node& operator= (const Node&) = delete; 39 39 Node& operator= (Node&&) = delete; 40 virtual ~Node() = default;40 virtual ~Node() {} 41 41 42 42 virtual const Node * accept( Visitor & v ) const = 0; … … 57 57 template<typename node_t> 58 58 friend node_t * mutate(const node_t * node); 59 template<typename node_t> 60 friend node_t * shallowCopy(const node_t * node); 59 61 60 62 mutable size_t strong_count = 0; … … 69 71 } 70 72 71 void decrement(ast::Node::ref_type ref ) const {73 void decrement(ast::Node::ref_type ref, bool do_delete = true) const { 72 74 switch (ref) { 73 75 case ref_type::strong: strong_count--; break; … … 75 77 } 76 78 77 if( !strong_count && !weak_count) {79 if( do_delete && !strong_count && !weak_count) { 78 80 delete this; 79 81 } … … 94 96 assertf( 95 97 node->weak_count == 0, 96 "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" 97 99 ); 98 100 return node->clone(); … … 104 106 // skip mutate if equivalent 105 107 if ( node->*field == val ) return node; 106 108 107 109 // mutate and return 108 110 node_t * ret = mutate( node ); … … 123 125 (ret->*field)[i] = std::forward< field_t >( val ); 124 126 return ret; 127 } 128 129 /// Mutate an entire indexed collection by cloning to accepted value 130 template<typename node_t, typename parent_t, typename coll_t> 131 const node_t * mutate_each( const node_t * node, coll_t parent_t::* field, Visitor & v ) { 132 for ( unsigned i = 0; i < (node->*field).size(); ++i ) { 133 node = mutate_field_index( node, field, i, (node->*field)[i]->accept( v ) ); 134 } 135 return node; 125 136 } 126 137 … … 219 230 operator const node_t * () const { _check(); return node; } 220 231 232 const node_t * release() { 233 const node_t * ret = node; 234 if ( node ) { 235 _dec(node, false); 236 node = nullptr; 237 } 238 return ret; 239 } 240 221 241 /// wrapper for convenient access to dynamic_cast 222 242 template<typename o_node_t> … … 244 264 245 265 void _inc( const node_t * other ); 246 void _dec( const node_t * other );266 void _dec( const node_t * other, bool do_delete = true ); 247 267 void _check() const; 248 268 -
src/AST/Pass.hpp
r849720f r4a60488 35 35 #include "AST/SymbolTable.hpp" 36 36 37 #include "AST/ForallSubstitutionTable.hpp" 38 37 39 // Private prelude header, needed for some of the magic tricks this class pulls off 38 40 #include "AST/Pass.proto.hpp" … … 46 48 // 47 49 // Several additional features are available through inheritance 48 // | WithTypeSubstitution - provides polymorphic const TypeSubstitution * env for the 49 // current expression 50 // | WithStmtsToAdd - provides the ability to insert statements before or after the current 51 // statement by adding new statements into stmtsToAddBefore or 52 // stmtsToAddAfter respectively. 53 // | WithDeclsToAdd - provides the ability to insert declarations before or after the current 54 // declarations by adding new DeclStmt into declsToAddBefore or 55 // declsToAddAfter respectively. 56 // | WithShortCircuiting - provides the ability to skip visiting child nodes; set visit_children 57 // to false in pre{visit,visit} to skip visiting children 58 // | WithGuards - provides the ability to save/restore data like a LIFO stack; to save, 59 // call GuardValue with the variable to save, the variable will 60 // automatically be restored to its previous value after the corresponding 61 // postvisit/postmutate teminates. 62 // | WithVisitorRef - provides an pointer to the templated visitor wrapper 63 // | WithSymbolTable - provides symbol table functionality 50 // | WithTypeSubstitution - provides polymorphic const TypeSubstitution * env for the 51 // current expression 52 // | WithStmtsToAdd - provides the ability to insert statements before or after the current 53 // statement by adding new statements into stmtsToAddBefore or 54 // stmtsToAddAfter respectively. 55 // | WithDeclsToAdd - provides the ability to insert declarations before or after the 56 // current declarations by adding new DeclStmt into declsToAddBefore or 57 // declsToAddAfter respectively. 58 // | WithShortCircuiting - provides the ability to skip visiting child nodes; set visit_children 59 // to false in pre{visit,visit} to skip visiting children 60 // | WithGuards - provides the ability to save/restore data like a LIFO stack; to save, 61 // call GuardValue with the variable to save, the variable will 62 // automatically be restored to its previous value after the 63 // corresponding postvisit/postmutate teminates. 64 // | WithVisitorRef - provides an pointer to the templated visitor wrapper 65 // | WithSymbolTable - provides symbol table functionality 66 // | WithForallSubstitutor - maintains links between TypeInstType and TypeDecl under mutation 64 67 //------------------------------------------------------------------------------------------------- 65 68 template< typename pass_t > … … 201 204 container_t< ptr<node_t> > call_accept( const container_t< ptr<node_t> > & container ); 202 205 206 /// Mutate forall-list, accounting for presence of type substitution map 207 template<typename node_t> 208 void mutate_forall( const node_t *& ); 209 203 210 public: 204 211 /// Logic to call the accept and mutate the parent if needed, delegates call to accept … … 209 216 /// Internal RAII guard for symbol table features 210 217 struct guard_symtab { 211 guard_symtab( Pass<pass_t> & pass ): pass( pass ) { __pass::symtab::enter(pass , 0); }212 ~guard_symtab() { __pass::symtab::leave(pass , 0); }218 guard_symtab( Pass<pass_t> & pass ): pass( pass ) { __pass::symtab::enter(pass.pass, 0); } 219 ~guard_symtab() { __pass::symtab::leave(pass.pass, 0); } 213 220 Pass<pass_t> & pass; 214 221 }; … … 216 223 /// Internal RAII guard for scope features 217 224 struct guard_scope { 218 guard_scope( Pass<pass_t> & pass ): pass( pass ) { __pass::scope::enter(pass , 0); }219 ~guard_scope() { __pass::scope::leave(pass , 0); }225 guard_scope( Pass<pass_t> & pass ): pass( pass ) { __pass::scope::enter(pass.pass, 0); } 226 ~guard_scope() { __pass::scope::leave(pass.pass, 0); } 220 227 Pass<pass_t> & pass; 228 }; 229 230 /// Internal RAII guard for forall substitutions 231 struct guard_forall_subs { 232 guard_forall_subs( Pass<pass_t> & pass, const ParameterizedType * type ) 233 : pass( pass ), type( type ) { __pass::forall::enter(pass.pass, 0, type ); } 234 ~guard_forall_subs() { __pass::forall::leave(pass.pass, 0, type ); } 235 Pass<pass_t> & pass; 236 const ParameterizedType * type; 221 237 }; 222 238 … … 313 329 SymbolTable symtab; 314 330 }; 331 332 /// Use when the templated visitor needs to keep TypeInstType instances properly linked to TypeDecl 333 struct WithForallSubstitutor { 334 ForallSubstitutionTable subs; 335 }; 336 315 337 } 316 338 -
src/AST/Pass.impl.hpp
r849720f r4a60488 127 127 , decltype( node->accept(*this) ) 128 128 >::type 129 130 129 { 131 130 __pedantic_pass_assert( __visit_children() ); 132 __pedantic_pass_assert( expr);131 __pedantic_pass_assert( node ); 133 132 134 133 static_assert( !std::is_base_of<ast::Expr, node_t>::value, "ERROR"); … … 323 322 } 324 323 324 325 template< typename pass_t > 326 template< typename node_t > 327 void ast::Pass< pass_t >::mutate_forall( const node_t *& node ) { 328 if ( auto subs = __pass::forall::subs( pass, 0 ) ) { 329 // tracking TypeDecl substitution, full clone 330 if ( node->forall.empty() ) return; 331 332 node_t * mut = mutate( node ); 333 mut->forall = subs->clone( node->forall, *this ); 334 node = mut; 335 } else { 336 // not tracking TypeDecl substitution, just mutate 337 maybe_accept( node, &node_t::forall ); 338 } 339 } 325 340 } 326 341 … … 429 444 guard_symtab guard { *this }; 430 445 // implicit add __func__ identifier as specified in the C manual 6.4.2.2 431 static ast:: ObjectDecl func(432 node->location, "__func__",433 new ast::ArrayType (434 new ast::BasicType ( ast::BasicType::Char, ast::CV::Qualifiers( ast::CV::Const ) ),446 static ast::ptr< ast::ObjectDecl > func{ new ast::ObjectDecl{ 447 CodeLocation{}, "__func__", 448 new ast::ArrayType{ 449 new ast::BasicType{ ast::BasicType::Char, ast::CV::Const }, 435 450 nullptr, VariableLen, DynamicDim 436 )437 );438 __pass::symtab::addId( pass, 0, &func );451 } 452 } }; 453 __pass::symtab::addId( pass, 0, func ); 439 454 VISIT( 440 455 maybe_accept( node, &FunctionDecl::type ); … … 610 625 VISIT({ 611 626 // do not enter a new scope if inFunction is true - needs to check old state before the assignment 612 auto guard1 = makeFuncGuard( [this, inFunction = this->inFunction]() {613 if ( ! inFunction ) __pass::symtab::enter(pass, 0);614 }, [this, inFunction = this->inFunction]() {615 if ( ! inFunction ) __pass::symtab::leave(pass, 0);627 auto guard1 = makeFuncGuard( [this, inFunctionCpy = this->inFunction]() { 628 if ( ! inFunctionCpy ) __pass::symtab::enter(pass, 0); 629 }, [this, inFunctionCpy = this->inFunction]() { 630 if ( ! inFunctionCpy ) __pass::symtab::leave(pass, 0); 616 631 }); 617 632 ValueGuard< bool > guard2( inFunction ); … … 938 953 // For now this isn't visited, it is unclear if this causes problem 939 954 // if all tests are known to pass, remove this code 940 //VISIT(941 //maybe_accept( node, &ImplicitCtorDtorStmt::callStmt );942 //)955 VISIT( 956 maybe_accept( node, &ImplicitCtorDtorStmt::callStmt ); 957 ) 943 958 944 959 VISIT_END( Stmt, node ); … … 1667 1682 VISIT_START( node ); 1668 1683 1669 VISIT( 1670 maybe_accept( node, &FunctionType::forall ); 1684 VISIT({ 1685 guard_forall_subs forall_guard { *this, node }; 1686 mutate_forall( node ); 1671 1687 maybe_accept( node, &FunctionType::returns ); 1672 1688 maybe_accept( node, &FunctionType::params ); 1673 )1689 }) 1674 1690 1675 1691 VISIT_END( Type, node ); … … 1686 1702 VISIT({ 1687 1703 guard_symtab guard { *this }; 1688 maybe_accept( node, &StructInstType::forall ); 1704 guard_forall_subs forall_guard { *this, node }; 1705 mutate_forall( node ); 1689 1706 maybe_accept( node, &StructInstType::params ); 1690 1707 }) … … 1699 1716 VISIT_START( node ); 1700 1717 1701 __pass::symtab::add Struct( pass, 0, node->name );1702 1703 {1718 __pass::symtab::addUnion( pass, 0, node->name ); 1719 1720 VISIT({ 1704 1721 guard_symtab guard { *this }; 1705 maybe_accept( node, &UnionInstType::forall ); 1722 guard_forall_subs forall_guard { *this, node }; 1723 mutate_forall( node ); 1706 1724 maybe_accept( node, &UnionInstType::params ); 1707 } 1725 }) 1708 1726 1709 1727 VISIT_END( Type, node ); … … 1716 1734 VISIT_START( node ); 1717 1735 1718 VISIT( 1719 maybe_accept( node, &EnumInstType::forall ); 1736 VISIT({ 1737 guard_forall_subs forall_guard { *this, node }; 1738 mutate_forall( node ); 1720 1739 maybe_accept( node, &EnumInstType::params ); 1721 )1740 }) 1722 1741 1723 1742 VISIT_END( Type, node ); … … 1730 1749 VISIT_START( node ); 1731 1750 1732 VISIT( 1733 maybe_accept( node, &TraitInstType::forall ); 1751 VISIT({ 1752 guard_forall_subs forall_guard { *this, node }; 1753 mutate_forall( node ); 1734 1754 maybe_accept( node, &TraitInstType::params ); 1735 )1755 }) 1736 1756 1737 1757 VISIT_END( Type, node ); … … 1745 1765 1746 1766 VISIT( 1747 maybe_accept( node, &TypeInstType::forall ); 1748 maybe_accept( node, &TypeInstType::params ); 1767 { 1768 guard_forall_subs forall_guard { *this, node }; 1769 mutate_forall( node ); 1770 maybe_accept( node, &TypeInstType::params ); 1771 } 1772 // ensure that base re-bound if doing substitution 1773 __pass::forall::replace( pass, 0, node ); 1749 1774 ) 1750 1775 … … 1895 1920 guard_symtab guard { *this }; 1896 1921 auto new_node = p.second->accept( *this ); 1897 if (new_node != p.second) mutated = false;1922 if (new_node != p.second) mutated = true; 1898 1923 new_map.insert({ p.first, new_node }); 1899 1924 } … … 1911 1936 guard_symtab guard { *this }; 1912 1937 auto new_node = p.second->accept( *this ); 1913 if (new_node != p.second) mutated = false;1938 if (new_node != p.second) mutated = true; 1914 1939 new_map.insert({ p.first, new_node }); 1915 1940 } -
src/AST/Pass.proto.hpp
r849720f r4a60488 263 263 template<typename pass_t> 264 264 static inline void leave( pass_t &, long ) {} 265 } ;266 267 // Finally certain pass desire an up to date symbol table automatically265 } // namespace scope 266 267 // Certain passes desire an up to date symbol table automatically 268 268 // detect the presence of a member name `symtab` and call all the members appropriately 269 269 namespace symtab { 270 270 // Some simple scoping rules 271 271 template<typename pass_t> 272 static inline auto enter( pass_t & pass, int ) -> decltype( pass.symtab .enterScope(), void() ) {272 static inline auto enter( pass_t & pass, int ) -> decltype( pass.symtab, void() ) { 273 273 pass.symtab.enterScope(); 274 274 } … … 278 278 279 279 template<typename pass_t> 280 static inline auto leave( pass_t & pass, int ) -> decltype( pass.symtab .leaveScope(), void() ) {280 static inline auto leave( pass_t & pass, int ) -> decltype( pass.symtab, void() ) { 281 281 pass.symtab.leaveScope(); 282 282 } … … 356 356 #undef SYMTAB_FUNC1 357 357 #undef SYMTAB_FUNC2 358 }; 359 }; 360 }; 358 } // namespace symtab 359 360 // Some passes need to mutate TypeDecl and properly update their pointing TypeInstType. 361 // Detect the presence of a member name `subs` and call all members appropriately 362 namespace forall { 363 // Some simple scoping rules 364 template<typename pass_t> 365 static inline auto enter( pass_t & pass, int, const ast::ParameterizedType * type ) 366 -> decltype( pass.subs, void() ) { 367 if ( ! type->forall.empty() ) pass.subs.beginScope(); 368 } 369 370 template<typename pass_t> 371 static inline auto enter( pass_t &, long, const ast::ParameterizedType * ) {} 372 373 template<typename pass_t> 374 static inline auto leave( pass_t & pass, int, const ast::ParameterizedType * type ) 375 -> decltype( pass.subs, void() ) { 376 if ( ! type->forall.empty() ) { pass.subs.endScope(); } 377 } 378 379 template<typename pass_t> 380 static inline auto leave( pass_t &, long, const ast::ParameterizedType * ) {} 381 382 // Get the substitution table, if present 383 template<typename pass_t> 384 static inline auto subs( pass_t & pass, int ) -> decltype( &pass.subs ) { 385 return &pass.subs; 386 } 387 388 template<typename pass_t> 389 static inline ast::ForallSubstitutionTable * subs( pass_t &, long ) { return nullptr; } 390 391 // Replaces a TypeInstType's base TypeDecl according to the table 392 template<typename pass_t> 393 static inline auto replace( pass_t & pass, int, const ast::TypeInstType *& inst ) 394 -> decltype( pass.subs, void() ) { 395 inst = ast::mutate_field( 396 inst, &ast::TypeInstType::base, pass.subs.replace( inst->base ) ); 397 } 398 399 template<typename pass_t> 400 static inline auto replace( pass_t &, long, const ast::TypeInstType *& ) {} 401 402 } // namespace forall 403 } // namespace __pass 404 } // namespace ast -
src/AST/Stmt.hpp
r849720f r4a60488 27 27 28 28 // Must be included in *all* AST classes; should be #undef'd at the end of the file 29 #define MUTATE_FRIEND template<typename node_t> friend node_t * mutate(const node_t * node); 29 #define MUTATE_FRIEND \ 30 template<typename node_t> friend node_t * mutate(const node_t * node); \ 31 template<typename node_t> friend node_t * shallowCopy(const node_t * node); 30 32 31 33 namespace ast { … … 397 399 class ImplicitCtorDtorStmt final : public Stmt { 398 400 public: 399 readonly<Stmt> callStmt;401 ptr<Stmt> callStmt; 400 402 401 403 ImplicitCtorDtorStmt( const CodeLocation & loc, const Stmt * callStmt, -
src/AST/Type.cpp
r849720f r4a60488 21 21 22 22 #include "Decl.hpp" 23 #include "ForallSubstitutor.hpp" // for substituteForall 23 24 #include "Init.hpp" 25 #include "Common/utility.h" // for copy, move 24 26 #include "InitTweak/InitTweak.h" // for getPointerBase 25 27 #include "Tuples/Tuples.h" // for isTtype … … 91 93 ); 92 94 95 // --- ParameterizedType 96 97 void ParameterizedType::initWithSub( 98 const ParameterizedType & o, Pass< ForallSubstitutor > & sub 99 ) { 100 forall = sub.pass( o.forall ); 101 } 102 93 103 // --- FunctionType 104 105 FunctionType::FunctionType( const FunctionType & o ) 106 : ParameterizedType( o.qualifiers, copy( o.attributes ) ), returns(), params(), 107 isVarArgs( o.isVarArgs ) { 108 Pass< ForallSubstitutor > sub; 109 initWithSub( o, sub ); // initialize substitution map 110 returns = sub.pass( o.returns ); // apply to return and parameter types 111 params = sub.pass( o.params ); 112 } 94 113 95 114 namespace { … … 107 126 108 127 // --- ReferenceToType 128 129 void ReferenceToType::initWithSub( const ReferenceToType & o, Pass< ForallSubstitutor > & sub ) { 130 ParameterizedType::initWithSub( o, sub ); // initialize substitution 131 params = sub.pass( o.params ); // apply to parameters 132 } 133 134 ReferenceToType::ReferenceToType( const ReferenceToType & o ) 135 : ParameterizedType( o.qualifiers, copy( o.attributes ) ), params(), name( o.name ), 136 hoistType( o.hoistType ) { 137 Pass< ForallSubstitutor > sub; 138 initWithSub( o, sub ); 139 } 140 109 141 std::vector<readonly<Decl>> ReferenceToType::lookup( const std::string& name ) const { 110 142 assertf( aggr(), "Must have aggregate to perform lookup" ); … … 119 151 // --- StructInstType 120 152 121 StructInstType::StructInstType( const StructDecl * b, CV::Qualifiers q,122 std::vector<ptr<Attribute>>&& as )123 : ReferenceToType( b->name, q, std::move(as) ), base( b ) {}153 StructInstType::StructInstType( 154 const StructDecl * b, CV::Qualifiers q, std::vector<ptr<Attribute>>&& as ) 155 : ReferenceToType( b->name, q, move(as) ), base( b ) {} 124 156 125 157 bool StructInstType::isComplete() const { return base ? base->body : false; } … … 127 159 // --- UnionInstType 128 160 129 UnionInstType::UnionInstType( const UnionDecl * b, CV::Qualifiers q,130 std::vector<ptr<Attribute>>&& as )131 : ReferenceToType( b->name, q, std::move(as) ), base( b ) {}161 UnionInstType::UnionInstType( 162 const UnionDecl * b, CV::Qualifiers q, std::vector<ptr<Attribute>>&& as ) 163 : ReferenceToType( b->name, q, move(as) ), base( b ) {} 132 164 133 165 bool UnionInstType::isComplete() const { return base ? base->body : false; } … … 135 167 // --- EnumInstType 136 168 137 EnumInstType::EnumInstType( const EnumDecl * b, CV::Qualifiers q,138 std::vector<ptr<Attribute>>&& as )139 : ReferenceToType( b->name, q, std::move(as) ), base( b ) {}169 EnumInstType::EnumInstType( 170 const EnumDecl * b, CV::Qualifiers q, std::vector<ptr<Attribute>>&& as ) 171 : ReferenceToType( b->name, q, move(as) ), base( b ) {} 140 172 141 173 bool EnumInstType::isComplete() const { return base ? base->body : false; } … … 143 175 // --- TraitInstType 144 176 145 TraitInstType::TraitInstType( const TraitDecl * b, CV::Qualifiers q,146 std::vector<ptr<Attribute>>&& as )147 : ReferenceToType( b->name, q, std::move(as) ), base( b ) {}177 TraitInstType::TraitInstType( 178 const TraitDecl * b, CV::Qualifiers q, std::vector<ptr<Attribute>>&& as ) 179 : ReferenceToType( b->name, q, move(as) ), base( b ) {} 148 180 149 181 // --- TypeInstType 182 183 TypeInstType::TypeInstType( const TypeInstType & o ) 184 : ReferenceToType( o.name, o.qualifiers, copy( o.attributes ) ), base(), kind( o.kind ) { 185 Pass< ForallSubstitutor > sub; 186 initWithSub( o, sub ); // initialize substitution 187 base = sub.pass( o.base ); // apply to base type 188 } 150 189 151 190 void TypeInstType::set_base( const TypeDecl * b ) { … … 159 198 160 199 TupleType::TupleType( std::vector<ptr<Type>> && ts, CV::Qualifiers q ) 161 : Type( q ), types( std::move(ts) ), members() {200 : Type( q ), types( move(ts) ), members() { 162 201 // This constructor is awkward. `TupleType` needs to contain objects so that members can be 163 202 // named, but members without initializer nodes end up getting constructors, which breaks -
src/AST/Type.hpp
r849720f r4a60488 30 30 31 31 // Must be included in *all* AST classes; should be #undef'd at the end of the file 32 #define MUTATE_FRIEND template<typename node_t> friend node_t * mutate(const node_t * node); 32 #define MUTATE_FRIEND \ 33 template<typename node_t> friend node_t * mutate(const node_t * node); \ 34 template<typename node_t> friend node_t * shallowCopy(const node_t * node); 33 35 34 36 namespace ast { 37 38 template< typename T > class Pass; 39 40 struct ForallSubstitutor; 35 41 36 42 class Type : public Node { … … 164 170 static const char *typeNames[]; 165 171 166 BasicType( Kind k, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} ) 172 BasicType( Kind k, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} ) 167 173 : Type(q, std::move(as)), kind(k) {} 168 174 … … 266 272 /// Base type for potentially forall-qualified types 267 273 class ParameterizedType : public Type { 274 protected: 275 /// initializes forall with substitutor 276 void initWithSub( const ParameterizedType & o, Pass< ForallSubstitutor > & sub ); 268 277 public: 269 278 using ForallList = std::vector<ptr<TypeDecl>>; … … 277 286 ParameterizedType( CV::Qualifiers q, std::vector<ptr<Attribute>> && as = {} ) 278 287 : Type(q, std::move(as)), forall() {} 288 289 // enforce use of ForallSubstitutor to copy parameterized type 290 ParameterizedType( const ParameterizedType & ) = delete; 291 292 ParameterizedType( ParameterizedType && ) = default; 293 294 // no need to change destructor, and operator= deleted in Node 279 295 280 296 private: … … 302 318 : ParameterizedType(q), returns(), params(), isVarArgs(va) {} 303 319 320 FunctionType( const FunctionType & o ); 321 304 322 /// true if either the parameters or return values contain a tttype 305 323 bool isTtype() const; … … 315 333 /// base class for types that refer to types declared elsewhere (aggregates and typedefs) 316 334 class ReferenceToType : public ParameterizedType { 335 protected: 336 /// Initializes forall and parameters based on substitutor 337 void initWithSub( const ReferenceToType & o, Pass< ForallSubstitutor > & sub ); 317 338 public: 318 339 std::vector<ptr<Expr>> params; … … 320 341 bool hoistType = false; 321 342 322 ReferenceToType( const std::string& n, CV::Qualifiers q = {},323 std::vector<ptr<Attribute>> && as = {} )343 ReferenceToType( 344 const std::string& n, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} ) 324 345 : ParameterizedType(q, std::move(as)), params(), name(n) {} 346 347 ReferenceToType( const ReferenceToType & o ); 325 348 326 349 /// Gets aggregate declaration this type refers to … … 339 362 readonly<StructDecl> base; 340 363 341 StructInstType( const std::string& n, CV::Qualifiers q = {},342 std::vector<ptr<Attribute>> && as = {} )364 StructInstType( 365 const std::string& n, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} ) 343 366 : ReferenceToType( n, q, std::move(as) ), base() {} 344 StructInstType( const StructDecl * b, CV::Qualifiers q = {}, 345 std::vector<ptr<Attribute>> && as = {} ); 367 368 StructInstType( 369 const StructDecl * b, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} ); 346 370 347 371 bool isComplete() const override; … … 360 384 readonly<UnionDecl> base; 361 385 362 UnionInstType( const std::string& n, CV::Qualifiers q = {},363 std::vector<ptr<Attribute>> && as = {} )386 UnionInstType( 387 const std::string& n, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} ) 364 388 : ReferenceToType( n, q, std::move(as) ), base() {} 365 UnionInstType( const UnionDecl * b, CV::Qualifiers q = {}, 366 std::vector<ptr<Attribute>> && as = {} ); 389 390 UnionInstType( 391 const UnionDecl * b, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} ); 367 392 368 393 bool isComplete() const override; … … 381 406 readonly<EnumDecl> base; 382 407 383 EnumInstType( const std::string& n, CV::Qualifiers q = {},384 std::vector<ptr<Attribute>> && as = {} )408 EnumInstType( 409 const std::string& n, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} ) 385 410 : ReferenceToType( n, q, std::move(as) ), base() {} 386 EnumInstType( const EnumDecl * b, CV::Qualifiers q = {}, 387 std::vector<ptr<Attribute>> && as = {} ); 411 412 EnumInstType( 413 const EnumDecl * b, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} ); 388 414 389 415 bool isComplete() const override; … … 402 428 readonly<TraitDecl> base; 403 429 404 TraitInstType( const std::string& n, CV::Qualifiers q = {},405 std::vector<ptr<Attribute>> && as = {} )430 TraitInstType( 431 const std::string& n, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} ) 406 432 : ReferenceToType( n, q, std::move(as) ), base() {} 407 TraitInstType( const TraitDecl * b, CV::Qualifiers q = {}, 408 std::vector<ptr<Attribute>> && as = {} ); 433 434 TraitInstType( 435 const TraitDecl * b, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} ); 409 436 410 437 // not meaningful for TraitInstType … … 425 452 TypeVar::Kind kind; 426 453 427 TypeInstType( const std::string& n, const TypeDecl * b, CV::Qualifiers q = {}, 454 TypeInstType( 455 const std::string& n, const TypeDecl * b, CV::Qualifiers q = {}, 428 456 std::vector<ptr<Attribute>> && as = {} ) 429 457 : ReferenceToType( n, q, std::move(as) ), base( b ), kind( b->kind ) {} 430 TypeInstType( const std::string& n, TypeVar::Kind k, CV::Qualifiers q = {}, 458 459 TypeInstType( 460 const std::string& n, TypeVar::Kind k, CV::Qualifiers q = {}, 431 461 std::vector<ptr<Attribute>> && as = {} ) 432 462 : ReferenceToType( n, q, std::move(as) ), base(), kind( k ) {} 463 464 TypeInstType( const TypeInstType & o ); 433 465 434 466 /// sets `base`, updating `kind` correctly -
src/AST/TypeEnvironment.hpp
r849720f r4a60488 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
r849720f r4a60488 92 92 namespace { 93 93 struct EnvTrimmer { 94 ptr<TypeSubstitution>env;94 const TypeSubstitution * env; 95 95 TypeSubstitution * newEnv; 96 96 EnvTrimmer( const TypeSubstitution * env, TypeSubstitution * newEnv ) : env( env ), newEnv( newEnv ){} … … 108 108 if ( env ) { 109 109 TypeSubstitution * newEnv = new TypeSubstitution(); 110 #if TIME_TO_CONVERT_PASSES111 110 Pass<EnvTrimmer> trimmer( env, newEnv ); 112 111 expr->accept( trimmer ); 113 #else114 (void)expr;115 (void)env;116 #endif117 112 return newEnv; 118 113 } … … 121 116 122 117 void TypeSubstitution::normalize() { 123 #if TIME_TO_CONVERT_PASSES 124 PassVisitor<Substituter> sub( *this, true ); 118 Pass<Substituter> sub( *this, true ); 125 119 do { 126 120 sub.pass.subCount = 0; 127 121 sub.pass.freeOnly = true; 128 122 for ( TypeEnvType::iterator i = typeEnv.begin(); i != typeEnv.end(); ++i ) { 129 i->second = i->second->accept Mutator( sub );123 i->second = i->second->accept( sub ); 130 124 } 131 125 } while ( sub.pass.subCount ); 132 #endif 133 } 134 135 #if TIME_TO_CONVERT_PASSES 136 137 Type * TypeSubstitution::Substituter::postmutate( TypeInstType *inst ) { 126 } 127 128 const Type * TypeSubstitution::Substituter::postvisit( const TypeInstType *inst ) { 138 129 BoundVarsType::const_iterator bound = boundVars.find( inst->name ); 139 130 if ( bound != boundVars.end() ) return inst; … … 146 137 // Note: this does not prevent cycles in the general case, so it may be necessary to do something more sophisticated here. 147 138 // TODO: investigate preventing type variables from being bound to themselves in the first place. 148 if ( TypeInstType * replacement = i->second.as<TypeInstType>() ) {139 if ( const TypeInstType * replacement = i->second.as<TypeInstType>() ) { 149 140 if ( inst->name == replacement->name ) { 150 141 return inst; … … 153 144 // std::cerr << "found " << inst->name << ", replacing with " << i->second << std::endl; 154 145 subCount++; 155 Type * newtype = i->second->clone(); 156 newtype->get_qualifiers() |= inst->get_qualifiers(); 157 delete inst; 158 // Note: need to recursively apply substitution to the new type because normalize does not substitute bound vars, but bound vars must be substituted when not in freeOnly mode. 159 return newtype->acceptMutator( *visitor ); 160 } // if 161 } 162 163 Expression * TypeSubstitution::Substituter::postmutate( NameExpr * nameExpr ) { 146 ptr<Type> newType = i->second; // force clone if needed 147 add_qualifiers( newType, inst->qualifiers ); 148 // Note: need to recursively apply substitution to the new type because normalize does not 149 // substitute bound vars, but bound vars must be substituted when not in freeOnly mode. 150 newType = newType->accept( *visitor ); 151 return newType.release(); 152 } // if 153 } 154 155 const Expr * TypeSubstitution::Substituter::postvisit( const NameExpr * nameExpr ) { 164 156 VarEnvType::const_iterator i = sub.varEnv.find( nameExpr->name ); 165 157 if ( i == sub.varEnv.end() ) { … … 167 159 } else { 168 160 subCount++; 169 delete nameExpr; 170 return i->second->clone(); 171 } // if 172 } 173 174 void TypeSubstitution::Substituter::premutate( Type * type ) { 161 return i->second; 162 } // if 163 } 164 165 void TypeSubstitution::Substituter::previsit( const ParameterizedType * ptype ) { 175 166 GuardValue( boundVars ); 176 167 // bind type variables from forall-qualifiers 177 168 if ( freeOnly ) { 178 for ( Type::ForallList::const_iterator tyvar = type->forall.begin(); tyvar != type->forall.end(); ++tyvar) {179 boundVars.insert( (*tyvar)->name );169 for ( const TypeDecl * tyvar : ptype->forall ) { 170 boundVars.insert( tyvar->name ); 180 171 } // for 181 172 } // if 182 173 } 183 174 184 template< typename TypeClass > 185 void TypeSubstitution::Substituter::handleAggregateType( TypeClass * type ) { 175 void TypeSubstitution::Substituter::handleAggregateType( const ReferenceToType * type ) { 186 176 GuardValue( boundVars ); 187 177 // bind type variables from forall-qualifiers 188 178 if ( freeOnly ) { 189 for ( Type::ForallList::const_iterator tyvar = type->forall.begin(); tyvar != type->forall.end(); ++tyvar) {190 boundVars.insert( (*tyvar)->name );179 for ( const TypeDecl * tyvar : type->forall ) { 180 boundVars.insert( tyvar->name ); 191 181 } // for 192 182 // bind type variables from generic type instantiations 193 std::list< TypeDecl* > *baseParameters = type->get_baseParameters(); 194 if ( baseParameters && ! type->parameters.empty() ) { 195 for ( std::list< TypeDecl* >::const_iterator tyvar = baseParameters->begin(); tyvar != baseParameters->end(); ++tyvar ) { 196 boundVars.insert( (*tyvar)->name ); 197 } // for 198 } // if 199 } // if 200 } 201 202 void TypeSubstitution::Substituter::premutate( StructInstType * aggregateUseType ) { 183 if ( auto decl = type->aggr() ) { 184 if ( ! type->params.empty() ) { 185 for ( const TypeDecl * tyvar : decl->params ) { 186 boundVars.insert( tyvar->name ); 187 } // for 188 } // if 189 } 190 } // if 191 } 192 193 void TypeSubstitution::Substituter::previsit( const StructInstType * aggregateUseType ) { 203 194 handleAggregateType( aggregateUseType ); 204 195 } 205 196 206 void TypeSubstitution::Substituter::pre mutate(UnionInstType *aggregateUseType ) {197 void TypeSubstitution::Substituter::previsit( const UnionInstType *aggregateUseType ) { 207 198 handleAggregateType( aggregateUseType ); 208 199 } 209 210 #endif211 200 212 201 } // namespace ast -
src/AST/TypeSubstitution.hpp
r849720f r4a60488 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 … … 155 161 Substituter( const TypeSubstitution & sub, bool freeOnly ) : sub( sub ), freeOnly( freeOnly ) {} 156 162 157 #if TIME_TO_CONVERT_PASSES 158 159 Type * postmutate( TypeInstType * aggregateUseType ); 160 Expression * postmutate( NameExpr * nameExpr ); 163 const Type * postvisit( const TypeInstType * aggregateUseType ); 164 const Expr * postvisit( const NameExpr * nameExpr ); 161 165 162 166 /// Records type variable bindings from forall-statements 163 void pre mutate(Type * type );167 void previsit( const ParameterizedType * type ); 164 168 /// Records type variable bindings from forall-statements and instantiations of generic types 165 template< typename TypeClass > void handleAggregateType( TypeClass * type ); 166 167 void premutate( StructInstType * aggregateUseType ); 168 void premutate( UnionInstType * aggregateUseType ); 169 170 #endif 169 void handleAggregateType( const ReferenceToType * type ); 170 171 void previsit( const StructInstType * aggregateUseType ); 172 void previsit( const UnionInstType * aggregateUseType ); 171 173 172 174 const TypeSubstitution & sub; … … 179 181 180 182 template< typename SynTreeClass > 181 int TypeSubstitution::apply( const SynTreeClass *&input ) const {183 TypeSubstitution::ApplyResult<SynTreeClass> TypeSubstitution::apply( const SynTreeClass * input ) const { 182 184 assert( input ); 183 185 Pass<Substituter> sub( *this, false ); 184 186 input = strict_dynamic_cast< const SynTreeClass * >( input->accept( sub ) ); 185 /// std::cerr << "substitution result is: "; 186 /// newType->print( std::cerr ); 187 /// std::cerr << std::endl; 188 return sub.pass.subCount; 187 return { input, sub.pass.subCount }; 189 188 } 190 189 191 190 template< typename SynTreeClass > 192 int TypeSubstitution::applyFree( const SynTreeClass *&input ) const {191 TypeSubstitution::ApplyResult<SynTreeClass> TypeSubstitution::applyFree( const SynTreeClass * input ) const { 193 192 assert( input ); 194 193 Pass<Substituter> sub( *this, true ); 195 194 input = strict_dynamic_cast< const SynTreeClass * >( input->accept( sub ) ); 196 /// std::cerr << "substitution result is: "; 197 /// newType->print( std::cerr ); 198 /// std::cerr << std::endl; 199 return sub.pass.subCount; 195 return { input, sub.pass.subCount }; 200 196 } 201 197 -
src/AST/module.mk
r849720f r4a60488 22 22 AST/DeclReplacer.cpp \ 23 23 AST/Expr.cpp \ 24 AST/ForallSubstitutionTable.cpp \ 24 25 AST/GenericSubstitution.cpp \ 25 26 AST/Init.cpp \ -
src/Common/ScopedMap.h
r849720f r4a60488 249 249 250 250 /// Gets the note at the given scope 251 Note& getNote() { return scopes.back().note; } 252 const Note& getNote() const { return scopes.back().note; } 251 253 Note& getNote( size_type i ) { return scopes[i].note; } 252 254 const Note& getNote( size_type i ) const { return scopes[i].note; } -
src/Makefile.in
r849720f r4a60488 169 169 AST/Convert.$(OBJEXT) AST/Decl.$(OBJEXT) \ 170 170 AST/DeclReplacer.$(OBJEXT) AST/Expr.$(OBJEXT) \ 171 AST/ForallSubstitutionTable.$(OBJEXT) \ 171 172 AST/GenericSubstitution.$(OBJEXT) AST/Init.$(OBJEXT) \ 172 173 AST/LinkageSpec.$(OBJEXT) AST/Node.$(OBJEXT) \ … … 590 591 AST/DeclReplacer.cpp \ 591 592 AST/Expr.cpp \ 593 AST/ForallSubstitutionTable.cpp \ 592 594 AST/GenericSubstitution.cpp \ 593 595 AST/Init.cpp \ … … 766 768 AST/$(DEPDIR)/$(am__dirstamp) 767 769 AST/Expr.$(OBJEXT): AST/$(am__dirstamp) AST/$(DEPDIR)/$(am__dirstamp) 770 AST/ForallSubstitutionTable.$(OBJEXT): AST/$(am__dirstamp) \ 771 AST/$(DEPDIR)/$(am__dirstamp) 768 772 AST/GenericSubstitution.$(OBJEXT): AST/$(am__dirstamp) \ 769 773 AST/$(DEPDIR)/$(am__dirstamp) … … 1221 1225 @AMDEP_TRUE@@am__include@ @am__quote@AST/$(DEPDIR)/DeclReplacer.Po@am__quote@ 1222 1226 @AMDEP_TRUE@@am__include@ @am__quote@AST/$(DEPDIR)/Expr.Po@am__quote@ 1227 @AMDEP_TRUE@@am__include@ @am__quote@AST/$(DEPDIR)/ForallSubstitutionTable.Po@am__quote@ 1223 1228 @AMDEP_TRUE@@am__include@ @am__quote@AST/$(DEPDIR)/GenericSubstitution.Po@am__quote@ 1224 1229 @AMDEP_TRUE@@am__include@ @am__quote@AST/$(DEPDIR)/Init.Po@am__quote@ -
src/ResolvExpr/AdjustExprType.cc
r849720f r4a60488 100 100 101 101 namespace { 102 struct AdjustExprType_new final : public ast::WithShortCircuiting { 102 class AdjustExprType_new final : public ast::WithShortCircuiting { 103 const ast::SymbolTable & symtab; 104 public: 103 105 const ast::TypeEnvironment & tenv; 104 const ast::SymbolTable & symtab;105 106 106 107 AdjustExprType_new( const ast::TypeEnvironment & e, const ast::SymbolTable & syms ) 107 : tenv( e ), symtab( syms) {}108 : symtab( syms ), tenv( e ) {} 108 109 109 void pre mutate( const ast::VoidType * ) { visit_children = false; }110 void pre mutate( const ast::BasicType * ) { visit_children = false; }111 void pre mutate( const ast::PointerType * ) { visit_children = false; }112 void pre mutate( const ast::ArrayType * ) { visit_children = false; }113 void pre mutate( const ast::FunctionType * ) { visit_children = false; }114 void pre mutate( const ast::StructInstType * ) { visit_children = false; }115 void pre mutate( const ast::UnionInstType * ) { visit_children = false; }116 void pre mutate( const ast::EnumInstType * ) { visit_children = false; }117 void pre mutate( const ast::TraitInstType * ) { visit_children = false; }118 void pre mutate( const ast::TypeInstType * ) { visit_children = false; }119 void pre mutate( const ast::TupleType * ) { visit_children = false; }120 void pre mutate( const ast::VarArgsType * ) { visit_children = false; }121 void pre mutate( const ast::ZeroType * ) { visit_children = false; }122 void pre mutate( const ast::OneType * ) { visit_children = false; }110 void previsit( const ast::VoidType * ) { visit_children = false; } 111 void previsit( const ast::BasicType * ) { visit_children = false; } 112 void previsit( const ast::PointerType * ) { visit_children = false; } 113 void previsit( const ast::ArrayType * ) { visit_children = false; } 114 void previsit( const ast::FunctionType * ) { visit_children = false; } 115 void previsit( const ast::StructInstType * ) { visit_children = false; } 116 void previsit( const ast::UnionInstType * ) { visit_children = false; } 117 void previsit( const ast::EnumInstType * ) { visit_children = false; } 118 void previsit( const ast::TraitInstType * ) { visit_children = false; } 119 void previsit( const ast::TypeInstType * ) { visit_children = false; } 120 void previsit( const ast::TupleType * ) { visit_children = false; } 121 void previsit( const ast::VarArgsType * ) { visit_children = false; } 122 void previsit( const ast::ZeroType * ) { visit_children = false; } 123 void previsit( const ast::OneType * ) { visit_children = false; } 123 124 124 const ast::Type * post mutate( const ast::ArrayType * at ) {125 const ast::Type * postvisit( const ast::ArrayType * at ) { 125 126 return new ast::PointerType{ at->base, at->qualifiers }; 126 127 } 127 128 128 const ast::Type * post mutate( const ast::FunctionType * ft ) {129 const ast::Type * postvisit( const ast::FunctionType * ft ) { 129 130 return new ast::PointerType{ ft }; 130 131 } 131 132 132 const ast::Type * post mutate( const ast::TypeInstType * inst ) {133 const ast::Type * postvisit( const ast::TypeInstType * inst ) { 133 134 // replace known function-type-variables with pointer-to-function 134 135 if ( const ast::EqvClass * eqvClass = tenv.lookup( inst->name ) ) { -
src/ResolvExpr/Candidate.hpp
r849720f r4a60488 51 51 52 52 Candidate( const ast::Expr * x, const ast::TypeEnvironment & e ) 53 : expr( x ), cost( Cost::zero ), cvtCost( Cost::zero ), env( e ), open(), need() {} 53 : expr( x ), cost( Cost::zero ), cvtCost( Cost::zero ), env( e ), open(), need() { 54 assert(x->result); 55 } 54 56 55 57 Candidate( const Candidate & o, const ast::Expr * x, const Cost & addedCost = Cost::zero ) 56 58 : expr( x ), cost( o.cost + addedCost ), cvtCost( Cost::zero ), env( o.env ), open( o.open ), 57 need( o.need ) {} 59 need( o.need ) { 60 assert(x->result); 61 } 58 62 59 63 Candidate( 60 const ast::Expr * x, const ast::TypeEnvironment & e, const ast::OpenVarSet & o, 64 const ast::Expr * x, const ast::TypeEnvironment & e, const ast::OpenVarSet & o, 61 65 const ast::AssertionSet & n, const Cost & c, const Cost & cvt = Cost::zero ) 62 : expr( x ), cost( c ), cvtCost( cvt ), env( e ), open( o ), need( n.begin(), n.end() ) {} 66 : expr( x ), cost( c ), cvtCost( cvt ), env( e ), open( o ), need( n.begin(), n.end() ) { 67 assert(x->result); 68 } 63 69 64 70 Candidate( … … 66 72 ast::AssertionSet && n, const Cost & c, const Cost & cvt = Cost::zero ) 67 73 : expr( x ), cost( c ), cvtCost( cvt ), env( std::move( e ) ), open( std::move( o ) ), 68 need( n.begin(), n.end() ) {} 74 need( n.begin(), n.end() ) { 75 assert(x->result); 76 } 69 77 }; 70 78 -
src/ResolvExpr/CandidateFinder.cpp
r849720f r4a60488 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 ); … … 370 370 // push empty tuple expression 371 371 newResult.parent = i; 372 std::vector< ast::ptr< ast::Expr > > emptyList; 373 newResult.expr = 374 new ast::TupleExpr{ CodeLocation{}, move( emptyList ) }; 372 newResult.expr = new ast::TupleExpr{ CodeLocation{}, {} }; 375 373 argType = newResult.expr->result; 376 374 } else { … … 400 398 401 399 // check unification for ttype before adding to final 402 if ( 403 unify( 400 if ( 401 unify( 404 402 ttype, argType, newResult.env, newResult.need, newResult.have, 405 newResult.open, symtab ) 403 newResult.open, symtab ) 406 404 ) { 407 405 finalResults.emplace_back( move( newResult ) ); … … 424 422 if ( expl.exprs.empty() ) { 425 423 results.emplace_back( 426 results[i], move( env ), copy( results[i].need ), 424 results[i], move( env ), copy( results[i].need ), 427 425 copy( results[i].have ), move( open ), nextArg + 1, expl.cost ); 428 426 429 427 continue; 430 428 } … … 432 430 // add new result 433 431 results.emplace_back( 434 i, expl.exprs.front(), move( env ), copy( results[i].need ), 435 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, 436 434 expl.cost, expl.exprs.size() == 1 ? 0 : 1, j ); 437 435 } … … 479 477 480 478 results.emplace_back( 481 i, expr, move( env ), move( need ), move( have ), move( open ), nextArg, 479 i, expr, move( env ), move( need ), move( have ), move( open ), nextArg, 482 480 nTuples, Cost::zero, nextExpl, results[i].explAlt ); 483 481 } … … 495 493 if ( unify( paramType, cnst->result, env, need, have, open, symtab ) ) { 496 494 results.emplace_back( 497 i, new ast::DefaultArgExpr{ cnst->location, cnst }, move( env ), 495 i, new ast::DefaultArgExpr{ cnst->location, cnst }, move( env ), 498 496 move( need ), move( have ), move( open ), nextArg, nTuples ); 499 497 } … … 517 515 if ( expl.exprs.empty() ) { 518 516 results.emplace_back( 519 results[i], move( env ), move( need ), move( have ), move( open ), 517 results[i], move( env ), move( need ), move( have ), move( open ), 520 518 nextArg + 1, expl.cost ); 521 519 522 520 continue; 523 521 } … … 539 537 // add new result 540 538 results.emplace_back( 541 i, expr, move( env ), move( need ), move( have ), move( open ), 539 i, expr, move( env ), move( need ), move( have ), move( open ), 542 540 nextArg + 1, nTuples, expl.cost, expl.exprs.size() == 1 ? 0 : 1, j ); 543 541 } … … 548 546 genStart = genEnd; 549 547 550 return genEnd != results.size(); 548 return genEnd != results.size(); // were any new results added? 551 549 } 552 550 553 551 /// Generate a cast expression from `arg` to `toType` 554 const ast::Expr * restructureCast( 552 const ast::Expr * restructureCast( 555 553 ast::ptr< ast::Expr > & arg, const ast::Type * toType, ast::GeneratedFlag isGenerated = ast::GeneratedCast 556 554 ) { 557 if ( 558 arg->result->size() > 1 559 && ! toType->isVoid() 560 && ! dynamic_cast< const ast::ReferenceType * >( toType ) 555 if ( 556 arg->result->size() > 1 557 && ! toType->isVoid() 558 && ! dynamic_cast< const ast::ReferenceType * >( toType ) 561 559 ) { 562 // Argument is a tuple and the target type is neither void nor a reference. Cast each 563 // member of the tuple to its corresponding target type, producing the tuple of those 564 // cast expressions. If there are more components of the tuple than components in the 565 // 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 566 564 // UniqueExpr ensures that the side effects will still be produced) 567 565 if ( Tuples::maybeImpureIgnoreUnique( arg ) ) { 568 // 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 569 567 // the expression 570 568 arg = new ast::UniqueExpr{ arg->location, arg }; … … 574 572 // cast each component 575 573 ast::ptr< ast::Expr > idx = new ast::TupleIndexExpr{ arg->location, arg, i }; 576 components.emplace_back( 574 components.emplace_back( 577 575 restructureCast( idx, toType->getComponent( i ), isGenerated ) ); 578 576 } … … 594 592 595 593 /// Actually visits expressions to find their candidate interpretations 596 struct Finder final : public ast::WithShortCircuiting { 594 class Finder final : public ast::WithShortCircuiting { 595 const ast::SymbolTable & symtab; 596 public: 597 597 CandidateFinder & selfFinder; 598 const ast::SymbolTable & symtab;599 598 CandidateList & candidates; 600 599 const ast::TypeEnvironment & tenv; … … 602 601 603 602 Finder( CandidateFinder & f ) 604 : s elfFinder( f ), symtab( f.symtab ), candidates( f.candidates ), tenv( f.env ),603 : symtab( f.localSyms ), selfFinder( f ), candidates( f.candidates ), tenv( f.env ), 605 604 targetType( f.targetType ) {} 606 605 607 606 void previsit( const ast::Node * ) { visit_children = false; } 608 607 … … 639 638 640 639 /// Completes a function candidate with arguments located 641 void validateFunctionCandidate( 642 const CandidateRef & func, ArgPack & result, const std::vector< ArgPack > & results, 643 CandidateList & out 640 void validateFunctionCandidate( 641 const CandidateRef & func, ArgPack & result, const std::vector< ArgPack > & results, 642 CandidateList & out 644 643 ) { 645 ast::ApplicationExpr * appExpr = 644 ast::ApplicationExpr * appExpr = 646 645 new ast::ApplicationExpr{ func->expr->location, func->expr }; 647 646 // sum cost and accumulate arguments … … 657 656 appExpr->args = move( vargs ); 658 657 // build and validate new candidate 659 auto newCand = 658 auto newCand = 660 659 std::make_shared<Candidate>( appExpr, result.env, result.open, result.need, cost ); 661 660 PRINT( … … 669 668 /// Builds a list of candidates for a function, storing them in out 670 669 void makeFunctionCandidates( 671 const CandidateRef & func, const ast::FunctionType * funcType, 670 const CandidateRef & func, const ast::FunctionType * funcType, 672 671 const ExplodedArgs_new & args, CandidateList & out 673 672 ) { … … 676 675 ast::TypeEnvironment funcEnv{ func->env }; 677 676 makeUnifiableVars( funcType, funcOpen, funcNeed ); 678 // add all type variables as open variables now so that those not used in the parameter679 // list are still considered open677 // add all type variables as open variables now so that those not used in the 678 // parameter list are still considered open 680 679 funcEnv.add( funcType->forall ); 681 680 … … 683 682 // attempt to narrow based on expected target type 684 683 const ast::Type * returnType = funcType->returns.front()->get_type(); 685 if ( ! unify( 686 returnType, targetType, funcEnv, funcNeed, funcHave, funcOpen, symtab ) 684 if ( ! unify( 685 returnType, targetType, funcEnv, funcNeed, funcHave, funcOpen, symtab ) 687 686 ) { 688 687 // unification failed, do not pursue this candidate … … 698 697 for ( const ast::DeclWithType * param : funcType->params ) { 699 698 auto obj = strict_dynamic_cast< const ast::ObjectDecl * >( param ); 700 // 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 701 700 // matches 702 if ( ! instantiateArgument( 701 if ( ! instantiateArgument( 703 702 obj->type, obj->init, args, results, genStart, symtab ) ) return; 704 703 } … … 750 749 if ( expl.exprs.empty() ) { 751 750 results.emplace_back( 752 results[i], move( env ), copy( results[i].need ), 753 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, 754 753 expl.cost ); 755 754 … … 760 759 results.emplace_back( 761 760 i, expl.exprs.front(), move( env ), copy( results[i].need ), 762 copy( results[i].have ), move( open ), nextArg + 1, 0, expl.cost, 761 copy( results[i].have ), move( open ), nextArg + 1, 0, expl.cost, 763 762 expl.exprs.size() == 1 ? 0 : 1, j ); 764 763 } … … 780 779 /// Adds implicit struct-conversions to the alternative list 781 780 void addAnonConversions( const CandidateRef & cand ) { 782 // adds anonymous member interpretations whenever an aggregate value type is seen. 783 // 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 784 783 // base type to treat the aggregate as the referenced value 785 784 ast::ptr< ast::Expr > aggrExpr( cand->expr ); 786 785 ast::ptr< ast::Type > & aggrType = aggrExpr.get_and_mutate()->result; 787 786 cand->env.apply( aggrType ); 788 787 789 788 if ( aggrType.as< ast::ReferenceType >() ) { 790 789 aggrExpr = new ast::CastExpr{ aggrExpr, aggrType->stripReferences() }; … … 799 798 800 799 /// Adds aggregate member interpretations 801 void addAggMembers( 802 const ast::ReferenceToType * aggrInst, const ast::Expr * expr, 803 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 804 803 ) { 805 804 for ( const ast::Decl * decl : aggrInst->lookup( name ) ) { 806 805 auto dwt = strict_dynamic_cast< const ast::DeclWithType * >( decl ); 807 CandidateRef newCand = std::make_shared<Candidate>( 806 CandidateRef newCand = std::make_shared<Candidate>( 808 807 cand, new ast::MemberExpr{ expr->location, dwt, expr }, addedCost ); 809 // add anonymous member interpretations whenever an aggregate value type is seen 808 // add anonymous member interpretations whenever an aggregate value type is seen 810 809 // as a member expression 811 810 addAnonConversions( newCand ); … … 815 814 816 815 /// Adds tuple member interpretations 817 void addTupleMembers( 818 const ast::TupleType * tupleType, const ast::Expr * expr, const Candidate & cand, 819 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 820 819 ) { 821 820 if ( auto constantExpr = dynamic_cast< const ast::ConstantExpr * >( member ) ) { 822 // 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 823 822 // length of the tuple to have meaning 824 823 long long val = constantExpr->intValue(); 825 824 if ( val >= 0 && (unsigned long long)val < tupleType->size() ) { 826 825 addCandidate( 827 cand, new ast::TupleIndexExpr{ expr->location, expr, (unsigned)val }, 826 cand, new ast::TupleIndexExpr{ expr->location, expr, (unsigned)val }, 828 827 addedCost ); 829 828 } … … 837 836 if ( funcFinder.candidates.empty() ) return; 838 837 839 std::vector< CandidateFinder > argCandidates = 838 std::vector< CandidateFinder > argCandidates = 840 839 selfFinder.findSubExprs( untypedExpr->args ); 841 840 842 841 // take care of possible tuple assignments 843 842 // if not tuple assignment, handled as normal function call … … 877 876 if ( auto function = pointer->base.as< ast::FunctionType >() ) { 878 877 CandidateRef newFunc{ new Candidate{ *func } }; 879 newFunc->expr = 878 newFunc->expr = 880 879 referenceToRvalueConversion( newFunc->expr, newFunc->cost ); 881 880 makeFunctionCandidates( newFunc, function, argExpansions, found ); 882 881 } 883 } else if ( 884 auto inst = dynamic_cast< const ast::TypeInstType * >( funcResult ) 882 } else if ( 883 auto inst = dynamic_cast< const ast::TypeInstType * >( funcResult ) 885 884 ) { 886 885 if ( const ast::EqvClass * clz = func->env.lookup( inst->name ) ) { 887 886 if ( auto function = clz->bound.as< ast::FunctionType >() ) { 888 887 CandidateRef newFunc{ new Candidate{ *func } }; 889 newFunc->expr = 888 newFunc->expr = 890 889 referenceToRvalueConversion( newFunc->expr, newFunc->cost ); 891 890 makeFunctionCandidates( newFunc, function, argExpansions, found ); … … 901 900 std::vector< ExplodedArg > funcE; 902 901 funcE.reserve( funcFinder.candidates.size() ); 903 for ( const CandidateRef & func : funcFinder ) { 902 for ( const CandidateRef & func : funcFinder ) { 904 903 funcE.emplace_back( *func, symtab ); 905 904 } … … 913 912 if ( auto function = pointer->base.as< ast::FunctionType >() ) { 914 913 CandidateRef newOp{ new Candidate{ *op} }; 915 newOp->expr = 914 newOp->expr = 916 915 referenceToRvalueConversion( newOp->expr, newOp->cost ); 917 916 makeFunctionCandidates( newOp, function, argExpansions, found ); … … 922 921 } 923 922 924 // 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 925 924 // candidates 926 925 if ( found.empty() && ! errors.isEmpty() ) { throw errors; } … … 934 933 auto pointer = appExpr->func->result.strict_as< ast::PointerType >(); 935 934 auto function = pointer->base.strict_as< ast::FunctionType >(); 936 935 937 936 std::cerr << "Case +++++++++++++ " << appExpr->func << std::endl; 938 937 std::cerr << "parameters are:" << std::endl; … … 957 956 promoteCvtCost( winners ); 958 957 959 // function may return a struct/union value, in which case we need to add candidates 960 // 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 961 960 // `findMinCost`, since anon conversions are never the cheapest 962 961 for ( const CandidateRef & c : winners ) { … … 966 965 967 966 if ( candidates.empty() && targetType && ! targetType->isVoid() ) { 968 // 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 969 968 // will sometimes succeed when it wouldn't with a target type binding. 970 969 // For example: … … 1016 1015 cand->env.extractOpenVars( open ); 1017 1016 1018 // It is possible that a cast can throw away some values in a multiply-valued 1019 // expression, e.g. cast-to-void, one value to zero. Figure out the prefix of the 1020 // 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 1021 1020 // has fewer results than there are types to cast to. 1022 1021 int discardedValues = cand->expr->result->size() - toType->size(); … … 1037 1036 // count one safe conversion for each value that is thrown away 1038 1037 thisCost.incSafe( discardedValues ); 1039 CandidateRef newCand = std::make_shared<Candidate>( 1040 restructureCast( cand->expr, toType, castExpr->isGenerated ), 1041 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, 1042 1041 cand->cost + thisCost ); 1043 1042 inferParameters( newCand, matches ); … … 1057 1056 finder.find( castExpr->arg, ResolvMode::withoutPrune() ); 1058 1057 for ( CandidateRef & r : finder.candidates ) { 1059 addCandidate( 1060 *r, 1058 addCandidate( 1059 *r, 1061 1060 new ast::VirtualCastExpr{ castExpr->location, r->expr, castExpr->result } ); 1062 1061 } … … 1067 1066 aggFinder.find( memberExpr->aggregate, ResolvMode::withAdjustment() ); 1068 1067 for ( CandidateRef & agg : aggFinder.candidates ) { 1069 // 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 1070 1069 // base type to treat the aggregate as the referenced value 1071 1070 Cost addedCost = Cost::zero; … … 1074 1073 // find member of the given type 1075 1074 if ( auto structInst = agg->expr->result.as< ast::StructInstType >() ) { 1076 addAggMembers( 1075 addAggMembers( 1077 1076 structInst, agg->expr, *agg, addedCost, getMemberName( memberExpr ) ); 1078 1077 } else if ( auto unionInst = agg->expr->result.as< ast::UnionInstType >() ) { 1079 addAggMembers( 1078 addAggMembers( 1080 1079 unionInst, agg->expr, *agg, addedCost, getMemberName( memberExpr ) ); 1081 1080 } else if ( auto tupleType = agg->expr->result.as< ast::TupleType >() ) { … … 1097 1096 1098 1097 CandidateRef newCand = std::make_shared<Candidate>( 1099 newExpr, copy( tenv ), ast::OpenVarSet{}, ast::AssertionSet{}, Cost::zero, 1098 newExpr, copy( tenv ), ast::OpenVarSet{}, ast::AssertionSet{}, Cost::zero, 1100 1099 cost ); 1101 1100 PRINT( … … 1107 1106 std::cerr << std::endl; 1108 1107 ) 1109 newCand->expr = ast::mutate_field( 1110 newCand->expr.get(), &ast::Expr::result, 1108 newCand->expr = ast::mutate_field( 1109 newCand->expr.get(), &ast::Expr::result, 1111 1110 renameTyVars( newCand->expr->result ) ); 1112 // add anonymous member interpretations whenever an aggregate value type is seen 1111 // add anonymous member interpretations whenever an aggregate value type is seen 1113 1112 // as a name expression 1114 1113 addAnonConversions( newCand ); … … 1120 1119 // not sufficient to just pass `variableExpr` here, type might have changed since 1121 1120 // creation 1122 addCandidate( 1121 addCandidate( 1123 1122 new ast::VariableExpr{ variableExpr->location, variableExpr->var }, tenv ); 1124 1123 } … … 1130 1129 void postvisit( const ast::SizeofExpr * sizeofExpr ) { 1131 1130 if ( sizeofExpr->type ) { 1132 addCandidate( 1133 new ast::SizeofExpr{ 1134 sizeofExpr->location, resolveTypeof( sizeofExpr->type, symtab ) }, 1131 addCandidate( 1132 new ast::SizeofExpr{ 1133 sizeofExpr->location, resolveTypeof( sizeofExpr->type, symtab ) }, 1135 1134 tenv ); 1136 1135 } else { … … 1141 1140 CandidateList winners = findMinCost( finder.candidates ); 1142 1141 if ( winners.size() != 1 ) { 1143 SemanticError( 1142 SemanticError( 1144 1143 sizeofExpr->expr.get(), "Ambiguous expression in sizeof operand: " ); 1145 1144 } … … 1154 1153 void postvisit( const ast::AlignofExpr * alignofExpr ) { 1155 1154 if ( alignofExpr->type ) { 1156 addCandidate( 1157 new ast::AlignofExpr{ 1158 alignofExpr->location, resolveTypeof( alignofExpr->type, symtab ) }, 1155 addCandidate( 1156 new ast::AlignofExpr{ 1157 alignofExpr->location, resolveTypeof( alignofExpr->type, symtab ) }, 1159 1158 tenv ); 1160 1159 } else { … … 1165 1164 CandidateList winners = findMinCost( finder.candidates ); 1166 1165 if ( winners.size() != 1 ) { 1167 SemanticError( 1166 SemanticError( 1168 1167 alignofExpr->expr.get(), "Ambiguous expression in alignof operand: " ); 1169 1168 } … … 1172 1171 choice->expr = referenceToRvalueConversion( choice->expr, choice->cost ); 1173 1172 choice->cost = Cost::zero; 1174 addCandidate( 1173 addCandidate( 1175 1174 *choice, new ast::AlignofExpr{ alignofExpr->location, choice->expr } ); 1176 1175 } … … 1185 1184 for ( const ast::Decl * member : aggInst->lookup( offsetofExpr->member ) ) { 1186 1185 auto dwt = strict_dynamic_cast< const ast::DeclWithType * >( member ); 1187 addCandidate( 1186 addCandidate( 1188 1187 new ast::OffsetofExpr{ offsetofExpr->location, aggInst, dwt }, tenv ); 1189 1188 } … … 1218 1217 1219 1218 addCandidate( 1220 new ast::LogicalExpr{ 1219 new ast::LogicalExpr{ 1221 1220 logicalExpr->location, r1->expr, r2->expr, logicalExpr->isAnd }, 1222 1221 move( env ), move( open ), move( need ), r1->cost + r2->cost ); … … 1256 1255 ast::AssertionSet have; 1257 1256 1258 // unify true and false results, then infer parameters to produce new 1257 // unify true and false results, then infer parameters to produce new 1259 1258 // candidates 1260 1259 ast::ptr< ast::Type > common; 1261 if ( 1262 unify( 1263 r2->expr->result, r3->expr->result, env, need, have, open, symtab, 1264 common ) 1260 if ( 1261 unify( 1262 r2->expr->result, r3->expr->result, env, need, have, open, symtab, 1263 common ) 1265 1264 ) { 1266 1265 // generate typed expression 1267 ast::ConditionalExpr * newExpr = new ast::ConditionalExpr{ 1266 ast::ConditionalExpr * newExpr = new ast::ConditionalExpr{ 1268 1267 conditionalExpr->location, r1->expr, r2->expr, r3->expr }; 1269 1268 newExpr->result = common ? common : r2->expr->result; 1270 1269 // convert both options to result type 1271 1270 Cost cost = r1->cost + r2->cost + r3->cost; 1272 newExpr->arg2 = computeExpressionConversionCost( 1271 newExpr->arg2 = computeExpressionConversionCost( 1273 1272 newExpr->arg2, newExpr->result, symtab, env, cost ); 1274 1273 newExpr->arg3 = computeExpressionConversionCost( … … 1287 1286 ast::TypeEnvironment env{ tenv }; 1288 1287 ast::ptr< ast::Expr > arg1 = resolveInVoidContext( commaExpr->arg1, symtab, env ); 1289 1288 1290 1289 CandidateFinder finder2{ symtab, env }; 1291 1290 finder2.find( commaExpr->arg2, ResolvMode::withAdjustment() ); … … 1330 1329 1331 1330 ast::ptr< ast::Type > common; 1332 if ( 1333 unify( 1334 r1->expr->result, r2->expr->result, env, need, have, open, symtab, 1335 common ) 1331 if ( 1332 unify( 1333 r1->expr->result, r2->expr->result, env, need, have, open, symtab, 1334 common ) 1336 1335 ) { 1337 1336 // generate new expression 1338 ast::RangeExpr * newExpr = 1337 ast::RangeExpr * newExpr = 1339 1338 new ast::RangeExpr{ rangeExpr->location, r1->expr, r2->expr }; 1340 1339 newExpr->result = common ? common : r1->expr->result; 1341 1340 // add candidate 1342 1341 CandidateRef newCand = std::make_shared<Candidate>( 1343 newExpr, move( env ), move( open ), move( need ), 1342 newExpr, move( env ), move( open ), move( need ), 1344 1343 r1->cost + r2->cost ); 1345 1344 inferParameters( newCand, candidates ); … … 1350 1349 1351 1350 void postvisit( const ast::UntypedTupleExpr * tupleExpr ) { 1352 std::vector< CandidateFinder > subCandidates = 1351 std::vector< CandidateFinder > subCandidates = 1353 1352 selfFinder.findSubExprs( tupleExpr->exprs ); 1354 1353 std::vector< CandidateList > possibilities; … … 1370 1369 1371 1370 addCandidate( 1372 new ast::TupleExpr{ tupleExpr->location, move( exprs ) }, 1371 new ast::TupleExpr{ tupleExpr->location, move( exprs ) }, 1373 1372 move( env ), move( open ), move( need ), sumCost( subs ) ); 1374 1373 } … … 1412 1411 toType = SymTab::validateType( initExpr->location, toType, symtab ); 1413 1412 toType = adjustExprType( toType, tenv, symtab ); 1414 // The call to find must occur inside this loop, otherwise polymorphic return 1415 // types are not bound to the initialization type, since return type variables are 1416 // 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. 1417 1416 CandidateFinder finder{ symtab, tenv, toType }; 1418 1417 finder.find( initExpr->expr, ResolvMode::withAdjustment() ); … … 1426 1425 ) 1427 1426 1428 // It is possible that a cast can throw away some values in a multiply-valued 1429 // expression, e.g. cast-to-void, one value to zero. Figure out the prefix of 1430 // 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 1431 1430 // if it has fewer results than there are types to cast to. 1432 1431 int discardedValues = cand->expr->result->size() - toType->size(); … … 1436 1435 unify( toType, cand->expr->result, env, need, have, open, symtab ); 1437 1436 Cost thisCost = castCost( cand->expr->result, toType, symtab, env ); 1438 1437 1439 1438 if ( thisCost != Cost::infinity ) { 1440 1439 // count one safe conversion for each value that is thrown away 1441 1440 thisCost.incSafe( discardedValues ); 1442 CandidateRef newCand = std::make_shared<Candidate>( 1443 new ast::InitExpr{ 1444 initExpr->location, restructureCast( cand->expr, toType ), 1445 initAlt.designation }, 1441 CandidateRef newCand = std::make_shared<Candidate>( 1442 new ast::InitExpr{ 1443 initExpr->location, restructureCast( cand->expr, toType ), 1444 initAlt.designation }, 1446 1445 copy( cand->env ), move( open ), move( need ), cand->cost, thisCost ); 1447 1446 inferParameters( newCand, matches ); … … 1469 1468 }; 1470 1469 1471 /// 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 1472 1471 /// return type. Skips ambiguous candidates. 1473 1472 CandidateList pruneCandidates( CandidateList & candidates ) { … … 1486 1485 { 1487 1486 ast::ptr< ast::Type > newType = candidate->expr->result; 1487 assertf(candidate->expr->result, "Result of expression %p for candidate is null", candidate->expr.get()); 1488 1488 candidate->env.apply( newType ); 1489 1489 mangleName = Mangle::mangle( newType ); … … 1494 1494 if ( candidate->cost < found->second.candidate->cost ) { 1495 1495 PRINT( 1496 std::cerr << "cost " << candidate->cost << " beats " 1496 std::cerr << "cost " << candidate->cost << " beats " 1497 1497 << found->second.candidate->cost << std::endl; 1498 1498 ) … … 1500 1500 found->second = PruneStruct{ candidate }; 1501 1501 } else if ( candidate->cost == found->second.candidate->cost ) { 1502 // if one of the candidates contains a deleted identifier, can pick the other, 1503 // since deleted expressions should not be ambiguous if there is another option 1502 // if one of the candidates contains a deleted identifier, can pick the other, 1503 // since deleted expressions should not be ambiguous if there is another option 1504 1504 // that is at least as good 1505 1505 if ( findDeletedExpr( candidate->expr ) ) { … … 1515 1515 } else { 1516 1516 PRINT( 1517 std::cerr << "cost " << candidate->cost << " loses to " 1517 std::cerr << "cost " << candidate->cost << " loses to " 1518 1518 << found->second.candidate->cost << std::endl; 1519 1519 ) … … 1530 1530 1531 1531 CandidateRef cand = target.second.candidate; 1532 1532 1533 1533 ast::ptr< ast::Type > newResult = cand->expr->result; 1534 1534 cand->env.applyFree( newResult ); 1535 1535 cand->expr = ast::mutate_field( 1536 1536 cand->expr.get(), &ast::Expr::result, move( newResult ) ); 1537 1537 1538 1538 out.emplace_back( cand ); 1539 1539 } … … 1558 1558 std::vector< std::string > errors; 1559 1559 for ( CandidateRef & candidate : candidates ) { 1560 satisfyAssertions( candidate, symtab, satisfied, errors );1560 satisfyAssertions( candidate, localSyms, satisfied, errors ); 1561 1561 } 1562 1562 … … 1583 1583 1584 1584 CandidateList pruned = pruneCandidates( candidates ); 1585 1585 1586 1586 if ( mode.failFast && pruned.empty() ) { 1587 1587 std::ostringstream stream; … … 1602 1602 ) 1603 1603 PRINT( 1604 std::cerr << "there are " << candidates.size() << " alternatives after elimination" 1604 std::cerr << "there are " << candidates.size() << " alternatives after elimination" 1605 1605 << std::endl; 1606 1606 ) 1607 1607 } 1608 1608 1609 // adjust types after pruning so that types substituted by pruneAlternatives are correctly 1609 // adjust types after pruning so that types substituted by pruneAlternatives are correctly 1610 1610 // adjusted 1611 1611 if ( mode.adjust ) { 1612 1612 for ( CandidateRef & r : candidates ) { 1613 r->expr = ast::mutate_field( 1614 r->expr.get(), &ast::Expr::result, 1615 adjustExprType( r->expr->result, r->env, symtab) );1613 r->expr = ast::mutate_field( 1614 r->expr.get(), &ast::Expr::result, 1615 adjustExprType( r->expr->result, r->env, localSyms ) ); 1616 1616 } 1617 1617 } … … 1625 1625 } 1626 1626 1627 std::vector< CandidateFinder > CandidateFinder::findSubExprs( 1628 const std::vector< ast::ptr< ast::Expr > > & xs 1627 std::vector< CandidateFinder > CandidateFinder::findSubExprs( 1628 const std::vector< ast::ptr< ast::Expr > > & xs 1629 1629 ) { 1630 1630 std::vector< CandidateFinder > out; 1631 1631 1632 1632 for ( const auto & x : xs ) { 1633 out.emplace_back( symtab, env );1633 out.emplace_back( localSyms, env ); 1634 1634 out.back().find( x, ResolvMode::withAdjustment() ); 1635 1635 1636 1636 PRINT( 1637 1637 std::cerr << "findSubExprs" << std::endl; -
src/ResolvExpr/CandidateFinder.hpp
r849720f r4a60488 28 28 struct CandidateFinder { 29 29 CandidateList candidates; ///< List of candidate resolutions 30 const ast::SymbolTable & symtab; ///< Symbol table to lookup candidates30 const ast::SymbolTable & localSyms; ///< Symbol table to lookup candidates 31 31 const ast::TypeEnvironment & env; ///< Substitutions performed in this resolution 32 32 ast::ptr< ast::Type > targetType; ///< Target type for resolution 33 33 34 34 CandidateFinder( 35 const ast::SymbolTable & sym tab, const ast::TypeEnvironment & env,35 const ast::SymbolTable & syms, const ast::TypeEnvironment & env, 36 36 const ast::Type * tt = nullptr ) 37 : candidates(), symtab( symtab), env( env ), targetType( tt ) {}37 : candidates(), localSyms( syms ), env( env ), targetType( tt ) {} 38 38 39 39 /// Fill candidates with feasible resolutions for `expr` -
src/ResolvExpr/CommonType.cc
r849720f r4a60488 939 939 ast::ptr< ast::Type > result; 940 940 const ast::ReferenceType * ref1 = type1.as< ast::ReferenceType >(); 941 const ast::ReferenceType * ref2 = type 1.as< ast::ReferenceType >();941 const ast::ReferenceType * ref2 = type2.as< ast::ReferenceType >(); 942 942 943 943 if ( depth1 > depth2 ) { -
src/ResolvExpr/ConversionCost.cc
r849720f r4a60488 10 10 // Created On : Sun May 17 07:06:19 2015 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Mon Aug 12 10:21:00 201912 // Last Modified On : Thr Jul 4 10:56:00 2019 13 13 // Update Count : 27 14 14 // … … 701 701 void ConversionCost_new::postvisit( const ast::EnumInstType * enumInstType ) { 702 702 (void)enumInstType; 703 static const ast::BasicType integer( ast::BasicType::SignedInt );704 cost = costCalc( &integer, dst, symtab, env );703 static ast::ptr<ast::BasicType> integer = { new ast::BasicType( ast::BasicType::SignedInt ) }; 704 cost = costCalc( integer, dst, symtab, env ); 705 705 if ( cost < Cost::unsafe ) { 706 706 cost.incSafe(); … … 772 772 cost.incSign( signMatrix[ ast::BasicType::SignedInt ][ dstAsBasic->kind ] ); 773 773 } 774 } else if ( dynamic_cast< const ast::PointerType * >( dst ) ) { 775 cost = Cost::zero; 776 // +1 for zero_t ->, +1 for disambiguation 777 cost.incSafe( maxIntCost + 2 ); 774 778 } 775 779 } … … 789 793 cost.incSign( signMatrix[ ast::BasicType::SignedInt ][ dstAsBasic->kind ] ); 790 794 } 791 } else if ( dynamic_cast< const ast::PointerType * >( dst ) ) {792 cost = Cost::zero;793 cost.incSafe( maxIntCost + 2 );794 795 } 795 796 } -
src/ResolvExpr/CurrentObject.cc
r849720f r4a60488 21 21 #include <string> // for string, operator<<, allocator 22 22 23 #include "AST/Copy.hpp" // for shallowCopy 23 24 #include "AST/Expr.hpp" // for InitAlternative 24 25 #include "AST/GenericSubstitution.hpp" // for genericSubstitution 25 26 #include "AST/Init.hpp" // for Designation 26 27 #include "AST/Node.hpp" // for readonly 28 #include "AST/Print.hpp" // for readonly 27 29 #include "AST/Type.hpp" 28 30 #include "Common/Indenter.h" // for Indenter, operator<< … … 596 598 SimpleIterator( const CodeLocation & loc, const Type * t ) : location( loc ), type( t ) {} 597 599 598 void setPosition( 599 std::deque< ptr< Expr > >::const_iterator begin, 600 void setPosition( 601 std::deque< ptr< Expr > >::const_iterator begin, 600 602 std::deque< ptr< Expr > >::const_iterator end 601 603 ) override { … … 637 639 auto res = eval(expr); 638 640 if ( ! res.second ) { 639 SemanticError( location, 641 SemanticError( location, 640 642 toString("Array designator must be a constant expression: ", expr ) ); 641 643 } … … 644 646 645 647 public: 646 ArrayIterator( const CodeLocation & loc, const ArrayType * at ) 648 ArrayIterator( const CodeLocation & loc, const ArrayType * at ) 647 649 : location( loc ), array( at ), base( at->base ) { 648 650 PRINT( std::cerr << "Creating array iterator: " << at << std::endl; ) … … 655 657 656 658 void setPosition( const Expr * expr ) { 657 // need to permit integer-constant-expressions, including: integer constants, 658 // enumeration constants, character constants, sizeof expressions, alignof expressions, 659 // need to permit integer-constant-expressions, including: integer constants, 660 // enumeration constants, character constants, sizeof expressions, alignof expressions, 659 661 // cast expressions 660 662 if ( auto constExpr = dynamic_cast< const ConstantExpr * >( expr ) ) { … … 662 664 index = constExpr->intValue(); 663 665 } catch ( SemanticErrorException & ) { 664 SemanticError( expr, 666 SemanticError( expr, 665 667 "Constant expression of non-integral type in array designator: " ); 666 668 } 667 669 } else if ( auto castExpr = dynamic_cast< const CastExpr * >( expr ) ) { 668 670 setPosition( castExpr->arg ); 669 } else if ( 670 dynamic_cast< const SizeofExpr * >( expr ) 671 || dynamic_cast< const AlignofExpr * >( expr ) 671 } else if ( 672 dynamic_cast< const SizeofExpr * >( expr ) 673 || dynamic_cast< const AlignofExpr * >( expr ) 672 674 ) { 673 675 index = 0; 674 676 } else { 675 assertf( false, 677 assertf( false, 676 678 "bad designator given to ArrayIterator: %s", toString( expr ).c_str() ); 677 679 } 678 680 } 679 681 680 void setPosition( 681 std::deque< ptr< Expr > >::const_iterator begin, 682 void setPosition( 683 std::deque< ptr< Expr > >::const_iterator begin, 682 684 std::deque< ptr< Expr > >::const_iterator end 683 685 ) override { … … 758 760 } 759 761 760 AggregateIterator( 761 const CodeLocation & loc, const std::string k, const std::string & n, const Type * i, 762 AggregateIterator( 763 const CodeLocation & loc, const std::string k, const std::string & n, const Type * i, 762 764 const MemberList & ms ) 763 : location( loc ), kind( k ), name( n ), inst( i ), members( ms ), curMember( ms.begin() ), 765 : location( loc ), kind( k ), name( n ), inst( i ), members( ms ), curMember( ms.begin() ), 764 766 sub( genericSubstitution( i ) ) { 765 767 PRINT( std::cerr << "Creating " << kind << "(" << name << ")"; ) … … 768 770 769 771 public: 770 void setPosition( 771 std::deque< ptr< Expr > >::const_iterator begin, 772 void setPosition( 773 std::deque< ptr< Expr > >::const_iterator begin, 772 774 std::deque< ptr< Expr > >::const_iterator end 773 775 ) final { … … 786 788 return; 787 789 } 788 assertf( false, 790 assertf( false, 789 791 "could not find member in %s: %s", kind.c_str(), toString( varExpr ).c_str() ); 790 792 } else { 791 assertf( false, 793 assertf( false, 792 794 "bad designator given to %s: %s", kind.c_str(), toString( *begin ).c_str() ); 793 795 } … … 803 805 new VariableExpr{ location, curMember->strict_as< ObjectDecl >() } ); 804 806 // need to substitute for generic types so that casts are to concrete types 807 alt.type = shallowCopy(alt.type.get()); 805 808 PRINT( std::cerr << " type is: " << alt.type; ) 806 809 sub.apply( alt.type ); // also apply to designation?? … … 842 845 for ( InitAlternative & alt : ret ) { 843 846 PRINT( std::cerr << "iterating and adding designators" << std::endl; ) 844 alt.designation.get_and_mutate()->designators.emplace_front( 847 alt.designation.get_and_mutate()->designators.emplace_front( 845 848 new VariableExpr{ location, curMember->strict_as< ObjectDecl >() } ); 846 849 } … … 897 900 class TupleIterator final : public AggregateIterator { 898 901 public: 899 TupleIterator( const CodeLocation & loc, const TupleType * inst ) 900 : AggregateIterator( 901 loc, "TupleIterator", toString("Tuple", inst->size()), inst, inst->members 902 TupleIterator( const CodeLocation & loc, const TupleType * inst ) 903 : AggregateIterator( 904 loc, "TupleIterator", toString("Tuple", inst->size()), inst, inst->members 902 905 ) {} 903 906 … … 926 929 return new UnionIterator{ loc, uit }; 927 930 } else { 928 assertf( 929 dynamic_cast< const EnumInstType * >( aggr )930 || dynamic_cast< const TypeInstType * >( aggr ),931 assertf( 932 dynamic_cast< const EnumInstType * >( type ) 933 || dynamic_cast< const TypeInstType * >( type ), 931 934 "Encountered unhandled ReferenceToType in createMemberIterator: %s", 932 935 toString( type ).c_str() ); … … 949 952 using DesignatorChain = std::deque< ptr< Expr > >; 950 953 PRINT( std::cerr << "___findNext" << std::endl; ) 951 954 952 955 // find all the d's 953 956 std::vector< DesignatorChain > desigAlts{ {} }, newDesigAlts; … … 1013 1016 // set new designators 1014 1017 assertf( ! objStack.empty(), "empty object stack when setting designation" ); 1015 Designation * actualDesignation = 1018 Designation * actualDesignation = 1016 1019 new Designation{ designation->location, DesignatorChain{d} }; 1017 1020 objStack.back()->setPosition( d ); // destroys d -
src/ResolvExpr/PolyCost.cc
r849720f r4a60488 58 58 59 59 // TODO: When the old PolyCost is torn out get rid of the _new suffix. 60 struct PolyCost_new { 60 class PolyCost_new { 61 const ast::SymbolTable &symtab; 62 public: 61 63 int result; 62 const ast::SymbolTable &symtab;63 64 const ast::TypeEnvironment &env_; 64 65 65 PolyCost_new( const ast::SymbolTable & symtab, const ast::TypeEnvironment & env ) :66 result( 0 ), symtab( symtab), env_( env ) {}66 PolyCost_new( const ast::SymbolTable & symtab, const ast::TypeEnvironment & env ) 67 : symtab( symtab ), result( 0 ), env_( env ) {} 67 68 68 69 void previsit( const ast::TypeInstType * type ) { -
src/ResolvExpr/RenameVars.cc
r849720f r4a60488 19 19 #include <utility> // for pair 20 20 21 #include "AST/ForallSubstitutionTable.hpp" 21 22 #include "AST/Pass.hpp" 22 23 #include "AST/Type.hpp" … … 30 31 #include "SynTree/Visitor.h" // for acceptAll, maybeAccept 31 32 33 #include "AST/Copy.hpp" 34 32 35 namespace ResolvExpr { 33 36 … … 37 40 int resetCount = 0; 38 41 ScopedMap< std::string, std::string > nameMap; 42 public: 43 ast::ForallSubstitutionTable subs; 39 44 40 public:41 45 void reset() { 42 46 level = 0; … … 44 48 } 45 49 46 using mapConstIterator = ScopedMap< std::string, std::string >::const_iterator;47 48 50 void rename( TypeInstType * type ) { 49 mapConstIteratorit = nameMap.find( type->name );51 auto it = nameMap.find( type->name ); 50 52 if ( it != nameMap.end() ) { 51 53 type->name = it->second; … … 65 67 // ditto for assertion names, the next level in 66 68 level++; 67 // acceptAll( td->assertions, *this ); 68 } // for 69 } // if 69 } 70 } 70 71 } 71 72 … … 77 78 78 79 const ast::TypeInstType * rename( const ast::TypeInstType * type ) { 79 mapConstIterator it = nameMap.find( type->name ); 80 // re-linking of base type handled by WithForallSubstitutor 81 82 // rename 83 auto it = nameMap.find( type->name ); 80 84 if ( it != nameMap.end() ) { 81 ast::TypeInstType * mutType = ast::mutate( type ); 82 mutType->name = it->second; 83 type = mutType; 85 // unconditionally mutate because map will *always* have different name, 86 // if this mutates, will *always* have been mutated by ForallSubstitutor above 87 ast::TypeInstType * mut = ast::mutate( type ); 88 mut->name = it->second; 89 type = mut; 84 90 } 91 85 92 return type; 86 93 } … … 88 95 template<typename NodeT> 89 96 const NodeT * openLevel( const NodeT * type ) { 90 if ( !type->forall.empty() ) { 91 nameMap.beginScope(); 92 // Load new names from this forall clause and perform renaming. 93 NodeT * mutType = ast::mutate( type ); 94 for ( ast::ptr< ast::TypeDecl > & td : mutType->forall ) { 95 std::ostringstream output; 96 output << "_" << resetCount << "_" << level << "_" << td->name; 97 std::string newname( output.str() ); 98 nameMap[ td->name ] = newname; 99 ++level; 97 if ( type->forall.empty() ) return type; 100 98 101 ast::TypeDecl * decl = ast::mutate( td.get() ); 102 decl->name = newname; 103 td = decl; 104 } 99 nameMap.beginScope(); 100 101 // Load new names from this forall clause and perform renaming. 102 NodeT * mutType = ast::mutate( type ); 103 assert( type == mutType && "mutated type must be unique from ForallSubstitutor" ); 104 for ( ast::ptr< ast::TypeDecl > & td : mutType->forall ) { 105 std::ostringstream output; 106 output << "_" << resetCount << "_" << level << "_" << td->name; 107 std::string newname = output.str(); 108 nameMap[ td->name ] = newname; 109 ++level; 110 111 ast::TypeDecl * mutDecl = ast::mutate( td.get() ); 112 assert( td == mutDecl && "mutated decl must be unique from ForallSubstitutor" ); 113 mutDecl->name = newname; 114 // assertion above means `td = mutDecl;` is unnecessary 105 115 } 116 // assertion above means `type = mutType;` is unnecessary 117 106 118 return type; 107 119 } 108 120 109 template<typename NodeT> 110 const NodeT * closeLevel( const NodeT * type ) { 111 if ( !type->forall.empty() ) { 112 nameMap.endScope(); 113 } 114 return type; 121 void closeLevel( const ast::ParameterizedType * type ) { 122 if ( type->forall.empty() ) return; 123 124 nameMap.endScope(); 115 125 } 116 126 }; … … 119 129 RenamingData renaming; 120 130 121 struct RenameVars {131 struct RenameVars_old { 122 132 void previsit( TypeInstType * instType ) { 123 133 renaming.openLevel( (Type*)instType ); … … 130 140 renaming.closeLevel( type ); 131 141 } 142 }; 143 144 struct RenameVars_new /*: public ast::WithForallSubstitutor*/ { 145 #warning when old RenameVars goes away, replace hack below with global pass inheriting from WithForallSubstitutor 146 ast::ForallSubstitutionTable & subs = renaming.subs; 132 147 133 148 const ast::FunctionType * previsit( const ast::FunctionType * type ) { … … 146 161 return renaming.rename( renaming.openLevel( type ) ); 147 162 } 148 const ast::ParameterizedType *postvisit( const ast::ParameterizedType * type ) {149 re turn renaming.closeLevel( type );163 void postvisit( const ast::ParameterizedType * type ) { 164 renaming.closeLevel( type ); 150 165 } 151 166 }; … … 154 169 155 170 void renameTyVars( Type * t ) { 156 PassVisitor<RenameVars > renamer;171 PassVisitor<RenameVars_old> renamer; 157 172 t->accept( renamer ); 158 173 } 159 174 160 175 const ast::Type * renameTyVars( const ast::Type * t ) { 161 ast::Pass<RenameVars> renamer; 162 return t->accept( renamer ); 176 ast::Type *tc = ast::deepCopy(t); 177 ast::Pass<RenameVars_new> renamer; 178 // return t->accept( renamer ); 179 return tc->accept( renamer ); 163 180 } 164 181 -
src/ResolvExpr/ResolveTypeof.cc
r849720f r4a60488 99 99 // replace basetypeof(<enum>) by int 100 100 if ( dynamic_cast<EnumInstType*>(newType) ) { 101 Type* newerType = 102 new BasicType{ newType->get_qualifiers(), BasicType::SignedInt, 101 Type* newerType = 102 new BasicType{ newType->get_qualifiers(), BasicType::SignedInt, 103 103 newType->attributes }; 104 104 delete newType; 105 105 newType = newerType; 106 106 } 107 newType->get_qualifiers().val 107 newType->get_qualifiers().val 108 108 = ( newType->get_qualifiers().val & ~Type::Qualifiers::Mask ) | oldQuals; 109 109 } else { 110 110 newType->get_qualifiers().val |= oldQuals; 111 111 } 112 112 113 113 return newType; 114 114 } … … 120 120 ResolveTypeof_new( const ast::SymbolTable & syms ) : localSymtab( syms ) {} 121 121 122 void pre mutate( const ast::TypeofType * ) { visit_children = false; }122 void previsit( const ast::TypeofType * ) { visit_children = false; } 123 123 124 const ast::Type * post mutate( const ast::TypeofType * typeofType ) {124 const ast::Type * postvisit( const ast::TypeofType * typeofType ) { 125 125 // pass on null expression 126 126 if ( ! typeofType->expr ) return typeofType; … … 133 133 // typeof wrapping expression 134 134 ast::TypeEnvironment dummy; 135 ast::ptr< ast::Expr > newExpr = 135 ast::ptr< ast::Expr > newExpr = 136 136 resolveInVoidContext( typeofType->expr, localSymtab, dummy ); 137 137 assert( newExpr->result && ! newExpr->result->isVoid() ); … … 143 143 // replace basetypeof(<enum>) by int 144 144 if ( newType.as< ast::EnumInstType >() ) { 145 newType = new ast::BasicType{ 145 newType = new ast::BasicType{ 146 146 ast::BasicType::SignedInt, newType->qualifiers, copy(newType->attributes) }; 147 147 } 148 reset_qualifiers( 149 newType, 148 reset_qualifiers( 149 newType, 150 150 ( newType->qualifiers & ~ast::CV::EquivQualifiers ) | typeofType->qualifiers ); 151 151 } else { … … 153 153 } 154 154 155 return newType ;155 return newType.release(); 156 156 } 157 157 }; -
src/ResolvExpr/Resolver.cc
r849720f r4a60488 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 ) { … … 1108 1108 1109 1109 // set up and resolve expression cast to void 1110 ast:: CastExpr *untyped = new ast::CastExpr{ expr };1110 ast::ptr< ast::CastExpr > untyped = new ast::CastExpr{ expr }; 1111 1111 CandidateRef choice = findUnfinishedKindExpression( 1112 1112 untyped, symtab, "", anyCandidate, ResolvMode::withAdjustment() ); … … 1247 1247 }; 1248 1248 1249 void resolve( std::list< ast::ptr< ast::Decl> >& translationUnit ) {1249 void resolve( std::list< ast::ptr< ast::Decl > >& translationUnit ) { 1250 1250 ast::Pass< Resolver_new > resolver; 1251 1251 accept_all( translationUnit, resolver ); … … 1281 1281 ast::ptr< ast::FunctionDecl > ret = functionDecl; 1282 1282 for ( unsigned i = 0; i < functionDecl->type->params.size(); ++i ) { 1283 const ast::ptr< ast::DeclWithType> & d = functionDecl->type->params[i];1283 const ast::ptr< ast::DeclWithType > & d = functionDecl->type->params[i]; 1284 1284 1285 1285 if ( const ast::ObjectDecl * obj = d.as< ast::ObjectDecl >() ) { … … 1298 1298 } 1299 1299 } 1300 return ret. get();1300 return ret.release(); 1301 1301 } 1302 1302 … … 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/SpecCost.cc
r849720f r4a60488 10 10 // Created On : Tue Oct 02 15:50:00 2018 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Wed Jun 19 10:43:00 2019 13 // Update Count : 2 14 // 15 12 // Last Modified On : Wed Jul 3 11:07:00 2019 13 // Update Count : 3 14 // 15 16 #include <cassert> 16 17 #include <limits> 17 18 #include <list> … … 129 130 typename std::add_pointer<ast::Type const *(typename T::value_type const &)>::type; 130 131 132 #warning Should use a standard maybe_accept 133 void maybe_accept( ast::Type const * type ) { 134 if ( type ) { 135 auto node = type->accept( *visitor ); 136 assert( node == nullptr || node == type ); 137 } 138 } 139 131 140 // Update the minimum to the new lowest non-none value. 132 141 template<typename T> … … 134 143 for ( const auto & node : list ) { 135 144 count = -1; 136 ma pper( node )->accept( *visitor);145 maybe_accept( mapper( node ) ); 137 146 if ( count != -1 && count < minimum ) minimum = count; 138 147 } -
src/ResolvExpr/Unify.cc
r849720f r4a60488 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 ast::ptr< ast::Type > t1_(newFirst ); 170 ast::ptr< ast::Type > t2_(newSecond); 177 171 178 172 return unifyExact( 179 newFirst, newSecond, newEnv, need, have, open, noWiden(), symtab ); 173 env.apply( newFirst ).node, 174 env.apply( newSecond ).node, 175 newEnv, need, have, open, noWiden(), symtab ); 180 176 } 181 177 … … 326 322 327 323 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 324 AssertionSet::iterator i = assertions.find( assert ); 334 325 if ( i != assertions.end() ) { 335 /// std::cerr << "found it!" << std::endl;336 326 i->second.isUsed = true; 337 327 } // if … … 1202 1192 // force t1 and t2 to be cloned if their qualifiers must be stripped, so that type1 and 1203 1193 // 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 ); 1194 ast::Type * t1 = shallowCopy(type1.get()); 1195 ast::Type * t2 = shallowCopy(type2.get()); 1196 t1->qualifiers = {}; 1197 t2->qualifiers = {}; 1198 ast::ptr< ast::Type > t1_(t1); 1199 ast::ptr< ast::Type > t2_(t2); 1207 1200 1208 1201 if ( unifyExact( t1, t2, env, need, have, open, widen, symtab ) ) { 1209 t1 = nullptr; t2 = nullptr; // release t1, t2 to avoid spurious clones1210 1211 1202 // if exact unification on unqualified types, try to merge qualifiers 1212 1203 if ( q1 == q2 || ( ( q1 > q2 || widen.first ) && ( q2 > q1 || widen.second ) ) ) { 1213 common = type1;1214 reset_qualifiers( common, q1 | q2 );1204 t1->qualifiers = q1 | q2; 1205 common = t1; 1215 1206 return true; 1216 1207 } else { … … 1219 1210 1220 1211 } else if (( common = commonType( t1, t2, widen, symtab, env, open ) )) { 1221 t1 = nullptr; t2 = nullptr; // release t1, t2 to avoid spurious clones1222 1223 1212 // no exact unification, but common type 1224 reset_qualifiers( common, q1 | q2 ); 1213 auto c = shallowCopy(common.get()); 1214 c->qualifiers = q1 | q2; 1215 common = c; 1225 1216 return true; 1226 1217 } else { -
src/SymTab/Autogen.h
r849720f r4a60488 21 21 22 22 #include "AST/Decl.hpp" 23 #include "AST/Eval.hpp" 23 24 #include "AST/Expr.hpp" 24 25 #include "AST/Init.hpp" … … 264 265 } 265 266 266 ast::ptr< ast::Expr > begin, end, cmp, update; 267 ast::ptr< ast::Expr > begin, end; 268 std::string cmp, update; 267 269 268 270 if ( forward ) { … … 270 272 begin = ast::ConstantExpr::from_int( loc, 0 ); 271 273 end = array->dimension; 272 cmp = new ast::NameExpr{ loc, "?<?" };273 update = new ast::NameExpr{ loc, "++?" };274 cmp = "?<?"; 275 update = "++?"; 274 276 } else { 275 277 // generate: for ( int i = N-1; i >= 0; --i ) 276 begin = new ast::UntypedExpr{ 277 loc, new ast::NameExpr{ loc, "?-?" }, 278 { array->dimension, ast::ConstantExpr::from_int( loc, 1 ) } }; 278 begin = ast::call( 279 loc, "?-?", array->dimension, ast::ConstantExpr::from_int( loc, 1 ) ); 279 280 end = ast::ConstantExpr::from_int( loc, 0 ); 280 cmp = new ast::NameExpr{ loc, "?>=?" };281 update = new ast::NameExpr{ loc, "--?" };281 cmp = "?>=?"; 282 update = "--?"; 282 283 } 283 284 … … 285 286 loc, indexName.newName(), new ast::BasicType{ ast::BasicType::SignedInt }, 286 287 new ast::SingleInit{ loc, begin } }; 287 288 ast::ptr< ast::Expr > cond = new ast::UntypedExpr{ 289 loc, cmp, { new ast::VariableExpr{ loc, index }, end } }; 290 291 ast::ptr< ast::Expr > inc = new ast::UntypedExpr{ 292 loc, update, { new ast::VariableExpr{ loc, index } } }; 293 294 ast::ptr< ast::Expr > dstIndex = new ast::UntypedExpr{ 295 loc, new ast::NameExpr{ loc, "?[?]" }, 296 { dstParam, new ast::VariableExpr{ loc, index } } }; 288 ast::ptr< ast::Expr > indexVar = new ast::VariableExpr{ loc, index }; 289 290 ast::ptr< ast::Expr > cond = ast::call( loc, cmp, indexVar, end ); 291 292 ast::ptr< ast::Expr > inc = ast::call( loc, update, indexVar ); 293 294 ast::ptr< ast::Expr > dstIndex = ast::call( loc, "?[?]", dstParam, indexVar ); 297 295 298 296 // srcParam must keep track of the array indices to build the source parameter and/or 299 297 // array list initializer 300 srcParam.addArrayIndex( new ast::VariableExpr{ loc, index }, array->dimension );298 srcParam.addArrayIndex( indexVar, array->dimension ); 301 299 302 300 // for stmt's body, eventually containing call … … 384 382 if ( isUnnamedBitfield( obj ) ) return {}; 385 383 386 ast::ptr< ast::Type > addCast = nullptr;384 ast::ptr< ast::Type > addCast; 387 385 if ( (fname == "?{}" || fname == "^?{}") && ( ! obj || ( obj && ! obj->bitfieldWidth ) ) ) { 388 386 assert( dstParam->result ); -
src/SynTree/Statement.h
r849720f r4a60488 502 502 class ImplicitCtorDtorStmt : public Statement { 503 503 public: 504 // Non-owned pointer to the constructor/destructor statement504 // the constructor/destructor call statement; owned here for a while, eventually transferred elsewhere 505 505 Statement * callStmt; 506 506 -
src/Tuples/Explode.cc
r849720f r4a60488 129 129 for ( const ast::Expr * expr : tupleExpr->exprs ) { 130 130 exprs.emplace_back( applyCast( expr, false ) ); 131 //exprs.emplace_back( ast::ptr< ast::Expr >( applyCast( expr, false ) ) );132 131 } 133 132 if ( first ) { -
src/Tuples/Explode.h
r849720f r4a60488 210 210 } 211 211 // Cast a reference away to a value-type to allow further explosion. 212 if ( dynamic_cast< const ast::ReferenceType *>( local->result.get()) ) {212 if ( local->result.as< ast::ReferenceType >() ) { 213 213 local = new ast::CastExpr{ local, tupleType }; 214 214 } … … 220 220 // delete idx; 221 221 } 222 // delete local;223 222 } 224 223 } else { -
src/Tuples/TupleAssignment.cc
r849720f r4a60488 465 465 // resolve ctor/dtor for the new object 466 466 ast::ptr< ast::Init > ctorInit = ResolvExpr::resolveCtorInit( 467 InitTweak::genCtorInit( location, ret ), spotter.crntFinder. symtab);467 InitTweak::genCtorInit( location, ret ), spotter.crntFinder.localSyms ); 468 468 // remove environments from subexpressions of stmtExpr 469 469 ast::Pass< EnvRemover > rm{ env }; … … 560 560 // resolve the cast expression so that rhsCand return type is bound by the cast 561 561 // type as needed, and transfer the resulting environment 562 ResolvExpr::CandidateFinder finder{ spotter.crntFinder. symtab, env };562 ResolvExpr::CandidateFinder finder{ spotter.crntFinder.localSyms, env }; 563 563 finder.find( rhsCand->expr, ResolvExpr::ResolvMode::withAdjustment() ); 564 564 assert( finder.candidates.size() == 1 ); … … 609 609 // explode the LHS so that each field of a tuple-valued expr is assigned 610 610 ResolvExpr::CandidateList lhs; 611 explode( *lhsCand, crntFinder. symtab, back_inserter(lhs), true );611 explode( *lhsCand, crntFinder.localSyms, back_inserter(lhs), true ); 612 612 for ( ResolvExpr::CandidateRef & cand : lhs ) { 613 613 // each LHS value must be a reference - some come in with a cast, if not … … 629 629 if ( isTuple( rhsCand->expr ) ) { 630 630 // multiple assignment 631 explode( *rhsCand, crntFinder. symtab, back_inserter(rhs), true );631 explode( *rhsCand, crntFinder.localSyms, back_inserter(rhs), true ); 632 632 matcher.reset( 633 633 new MultipleAssignMatcher{ *this, expr->location, lhs, rhs } ); … … 648 648 // multiple assignment 649 649 ResolvExpr::CandidateList rhs; 650 explode( rhsCand, crntFinder. symtab, back_inserter(rhs), true );650 explode( rhsCand, crntFinder.localSyms, back_inserter(rhs), true ); 651 651 matcher.reset( 652 652 new MultipleAssignMatcher{ *this, expr->location, lhs, rhs } ); … … 678 678 ) 679 679 680 ResolvExpr::CandidateFinder finder{ crntFinder. symtab, matcher->env };680 ResolvExpr::CandidateFinder finder{ crntFinder.localSyms, matcher->env }; 681 681 682 682 try { -
src/main.cc
r849720f r4a60488 29 29 #include <string> // for char_traits, operator<< 30 30 31 #include "AST/Convert.hpp" 31 32 #include "CompilationState.h" 32 33 #include "../config.h" // for CFA_LIBDIR … … 313 314 } // if 314 315 315 assertTopLvalue( translationUnit ); 316 317 PASS( "Resolve", ResolvExpr::resolve( translationUnit ) ); 316 // PASS( "Resolve", ResolvExpr::resolve( translationUnit ) ); 317 { 318 auto transUnit = convert( move( translationUnit ) ); 319 PASS( "Resolve", ResolvExpr::resolve( transUnit ) ); 320 translationUnit = convert( move( transUnit ) ); 321 } 322 318 323 if ( exprp ) { 319 324 dump( translationUnit );
Note:
See TracChangeset
for help on using the changeset viewer.