| 1 | //
 | 
|---|
| 2 | // Cforall Version 1.0.0 Copyright (C) 2016 University of Waterloo
 | 
|---|
| 3 | //
 | 
|---|
| 4 | // The contents of this file are covered under the licence agreement in the
 | 
|---|
| 5 | // file "LICENCE" distributed with Cforall.
 | 
|---|
| 6 | //
 | 
|---|
| 7 | // InstantiateGeneric.cpp -- Create concrete instances of generic types.
 | 
|---|
| 8 | //
 | 
|---|
| 9 | // Author           : Andrew Beach
 | 
|---|
| 10 | // Created On       : Tue Aug 16 10:51:00 2022
 | 
|---|
| 11 | // Last Modified By : Andrew Beach
 | 
|---|
| 12 | // Last Modified On : Mon Oct 31 16:48:00 2022
 | 
|---|
| 13 | // Update Count     : 1
 | 
|---|
| 14 | //
 | 
|---|
| 15 | 
 | 
|---|
| 16 | #include "InstantiateGeneric.hpp"
 | 
|---|
| 17 | 
 | 
|---|
| 18 | #include <cassert>                     // for assertf, assert
 | 
|---|
| 19 | #include <set>                         // for set
 | 
|---|
| 20 | #include <utility>                     // for move, pair
 | 
|---|
| 21 | #include <vector>                      // for vector
 | 
|---|
| 22 | 
 | 
|---|
| 23 | #include "AST/Copy.hpp"                // for deepCopy
 | 
|---|
| 24 | #include "AST/Create.hpp"              // for asForward
 | 
|---|
| 25 | #include "AST/Inspect.hpp"             // for getFunction
 | 
|---|
| 26 | #include "AST/Pass.hpp"                // for Pass, WithGuard, WithShortCi...
 | 
|---|
| 27 | #include "AST/TranslationUnit.hpp"     // for TranslationUnit
 | 
|---|
| 28 | #include "AST/Vector.hpp"              // for vector
 | 
|---|
| 29 | #include "CodeGen/OperatorTable.hpp"   // for isAssignment
 | 
|---|
| 30 | #include "Common/ScopedMap.hpp"        // for ScopedMap
 | 
|---|
| 31 | #include "Common/UniqueName.hpp"       // for UniqueName
 | 
|---|
| 32 | #include "GenPoly/GenPoly.hpp"         // for isPolyType, typesPolyCompatible
 | 
|---|
| 33 | #include "GenPoly/ScrubTypeVars.hpp"   // for scrubAllTypeVars
 | 
|---|
| 34 | #include "ResolvExpr/AdjustExprType.hpp"  // for adjustExprType
 | 
|---|
| 35 | #include "ResolvExpr/Unify.hpp"        // for typesCompatible
 | 
|---|
| 36 | 
 | 
|---|
| 37 | namespace GenPoly {
 | 
|---|
| 38 | 
 | 
|---|
| 39 | namespace {
 | 
|---|
| 40 | 
 | 
|---|
| 41 | // Utilities:
 | 
|---|
| 42 | 
 | 
|---|
| 43 | using type_vector = ast::vector< ast::TypeExpr >;
 | 
|---|
| 44 | 
 | 
|---|
| 45 | /// Abstracts type equality for a list of parameter types.
 | 
|---|
| 46 | struct TypeList {
 | 
|---|
| 47 |         TypeList() : params() {}
 | 
|---|
| 48 |         TypeList( ast::vector< ast::Type > const & params ) :
 | 
|---|
| 49 |                 params( params ) {}
 | 
|---|
| 50 |         TypeList( ast::vector< ast::Type > && params ) :
 | 
|---|
| 51 |                 params( std::move( params ) ) {}
 | 
|---|
| 52 |         TypeList( TypeList const & that ) : params( that.params ) {}
 | 
|---|
| 53 |         TypeList( TypeList && that ) : params( std::move( that.params ) ) {}
 | 
|---|
| 54 | 
 | 
|---|
| 55 |         TypeList( ast::vector< ast::TypeExpr > const & exprs ) :
 | 
|---|
| 56 |                         params() {
 | 
|---|
| 57 |                 for ( auto expr : exprs ) {
 | 
|---|
| 58 |                         params.emplace_back( ast::deepCopy( expr->type ) );
 | 
|---|
| 59 |                 }
 | 
|---|
| 60 |         }
 | 
|---|
| 61 | 
 | 
|---|
| 62 |         TypeList & operator=( TypeList const & that ) {
 | 
|---|
| 63 |                 params = that.params;
 | 
|---|
| 64 |                 return *this;
 | 
|---|
| 65 |         }
 | 
|---|
| 66 | 
 | 
|---|
| 67 |         TypeList & operator=( TypeList && that ) {
 | 
|---|
| 68 |                 params = std::move( that.params );
 | 
|---|
| 69 |                 return *this;
 | 
|---|
| 70 |         }
 | 
|---|
| 71 | 
 | 
|---|
| 72 |         bool operator==( TypeList const & that ) const {
 | 
|---|
| 73 |                 if ( params.size() != that.params.size() ) {
 | 
|---|
| 74 |                         return false;
 | 
|---|
| 75 |                 }
 | 
|---|
| 76 | 
 | 
|---|
| 77 |                 for ( auto it = params.begin(), jt = that.params.begin() ;
 | 
|---|
| 78 |                                 it != params.end() ; ++it, ++jt ) {
 | 
|---|
| 79 |                         if ( !typesPolyCompatible( it->get(), jt->get() ) ) {
 | 
|---|
| 80 |                                 return false;
 | 
|---|
| 81 |                         }
 | 
|---|
| 82 |                 }
 | 
|---|
| 83 |                 return true;
 | 
|---|
| 84 |         }
 | 
|---|
| 85 | 
 | 
|---|
| 86 |         ast::vector<ast::Type> params;
 | 
|---|
| 87 | };
 | 
|---|
| 88 | 
 | 
|---|
| 89 | /// Maps a key and a TypeList to a valuue. Also supports scoping.
 | 
|---|
| 90 | class InstantiationMap final {
 | 
|---|
| 91 |         /// Wraps value for a specific (AggregateDecl, TypeList) combination.
 | 
|---|
| 92 |         using Instantiation = std::pair<TypeList, ast::ptr<ast::AggregateDecl>>;
 | 
|---|
| 93 |         /// List of TypeLists paired with the appropriate values.
 | 
|---|
| 94 |         using ValueList = std::vector<Instantiation>;
 | 
|---|
| 95 |         /// Underlying map type; maps keys to a linear list of corresponding
 | 
|---|
| 96 |         /// TypeLists and values.
 | 
|---|
| 97 |         using InnerMap = ScopedMap<ast::ptr<ast::AggregateDecl>, ValueList>;
 | 
|---|
| 98 | 
 | 
|---|
| 99 |         InnerMap data;
 | 
|---|
| 100 | public:
 | 
|---|
| 101 |         void beginScope() { data.beginScope(); }
 | 
|---|
| 102 |         void endScope() { data.endScope(); }
 | 
|---|
| 103 | 
 | 
|---|
| 104 |         /// Gets the value for the (declaration, type list) pair,
 | 
|---|
| 105 |         /// returns null if no such value exists.
 | 
|---|
| 106 |         ast::AggregateDecl const * lookup(
 | 
|---|
| 107 |                         ast::AggregateDecl const * key,
 | 
|---|
| 108 |                         type_vector const & params ) const {
 | 
|---|
| 109 |                 // This type repackaging is used for the helpers.
 | 
|---|
| 110 |                 ast::ptr<ast::AggregateDecl> ptr = key;
 | 
|---|
| 111 |                 TypeList typeList( params );
 | 
|---|
| 112 | 
 | 
|---|
| 113 |                 // Scan scopes for matches to the key.
 | 
|---|
| 114 |                 for ( auto insts = data.find( key ) ;
 | 
|---|
| 115 |                                 insts != data.end() ; insts = data.findNext( insts, ptr )) {
 | 
|---|
| 116 |                         for ( auto inst = insts->second.rbegin() ;
 | 
|---|
| 117 |                                         inst != insts->second.rend() ; ++inst ) {
 | 
|---|
| 118 |                                 if ( inst->first == typeList ) {
 | 
|---|
| 119 |                                         return inst->second;
 | 
|---|
| 120 |                                 }
 | 
|---|
| 121 |                         }
 | 
|---|
| 122 |                 }
 | 
|---|
| 123 |                 return nullptr;
 | 
|---|
| 124 |         }
 | 
|---|
| 125 | 
 | 
|---|
| 126 |         /// Adds a value for a (key, type list) pair to the current scope.
 | 
|---|
| 127 |         void insert( ast::AggregateDecl const * key, type_vector const & params,
 | 
|---|
| 128 |                         ast::AggregateDecl const * value ) {
 | 
|---|
| 129 |                 auto it = data.findAt( data.currentScope(), key );
 | 
|---|
| 130 |                 if ( it == data.end() ) {
 | 
|---|
| 131 |                         data.insert( key, ValueList( 1,
 | 
|---|
| 132 |                                 Instantiation( TypeList( params ), value ) ) );
 | 
|---|
| 133 |                 } else {
 | 
|---|
| 134 |                         it->second.emplace_back(
 | 
|---|
| 135 |                                 Instantiation( TypeList( params ), value ) );
 | 
|---|
| 136 |                 }
 | 
|---|
| 137 |         }
 | 
|---|
| 138 | };
 | 
|---|
| 139 | 
 | 
|---|
| 140 | /// Possible options for a given specialization of a generic type.
 | 
|---|
| 141 | enum class GenericType {
 | 
|---|
| 142 |         /// Concrete instatiation based solely on {d,f}type-to-void conversions.
 | 
|---|
| 143 |         dtypeStatic,
 | 
|---|
| 144 |         /// Concrete instatiation requiring at least one parameters type.
 | 
|---|
| 145 |         concrete,
 | 
|---|
| 146 |         /// No concrete instantiation.
 | 
|---|
| 147 |         dynamic
 | 
|---|
| 148 | };
 | 
|---|
| 149 | 
 | 
|---|
| 150 | GenericType & operator|=( GenericType & gt, const GenericType & ht ) {
 | 
|---|
| 151 |         if ( gt < ht ) gt = ht;
 | 
|---|
| 152 |         return gt;
 | 
|---|
| 153 | }
 | 
|---|
| 154 | 
 | 
|---|
| 155 | bool isDtypeStatic( ast::vector<ast::TypeDecl> const & baseParams ) {
 | 
|---|
| 156 |         return std::all_of( baseParams.begin(), baseParams.end(),
 | 
|---|
| 157 |                 []( ast::TypeDecl const * td ){ return !td->isComplete(); }
 | 
|---|
| 158 |         );
 | 
|---|
| 159 | }
 | 
|---|
| 160 | 
 | 
|---|
| 161 | /// Makes substitutions of params into baseParams; returns dtypeStatic if
 | 
|---|
| 162 | /// there is a concrete instantiation based only on {d,f}type-to-void
 | 
|---|
| 163 | /// conversions, concrete if there is a concrete instantiation requiring at
 | 
|---|
| 164 | /// least one parameter type, and dynamic if there is no concrete instantiation.
 | 
|---|
| 165 | GenericType makeSubstitutions(
 | 
|---|
| 166 |                 ast::vector<ast::TypeExpr> & out,
 | 
|---|
| 167 |                 ast::vector<ast::TypeDecl> const & baseParams,
 | 
|---|
| 168 |                 ast::vector<ast::Expr> const & params ) {
 | 
|---|
| 169 |         GenericType gt = GenericType::dtypeStatic;
 | 
|---|
| 170 | 
 | 
|---|
| 171 |         // Substitute concrete types for given parameters,
 | 
|---|
| 172 |         // using incomplete types for placeholders.
 | 
|---|
| 173 |         auto baseParam = baseParams.begin();
 | 
|---|
| 174 |         auto param = params.begin();
 | 
|---|
| 175 |         for ( ; baseParam != baseParams.end() && param != params.end() ;
 | 
|---|
| 176 |                         ++baseParam, ++param ) {
 | 
|---|
| 177 |                 ast::TypeExpr const * paramExpr = param->as<ast::TypeExpr>();
 | 
|---|
| 178 |                 assertf( paramExpr, "Aggregate parameters should be type expressions." );
 | 
|---|
| 179 | 
 | 
|---|
| 180 |                 if ( (*baseParam)->isComplete() ) {
 | 
|---|
| 181 |                         // Substitute parameter for complete (otype or sized dtype) type.
 | 
|---|
| 182 |                         if ( isPolyType( paramExpr->type ) ) {
 | 
|---|
| 183 |                                 // Substitute polymorphic parameter type in to generic type.
 | 
|---|
| 184 |                                 out.push_back( ast::deepCopy( paramExpr ) );
 | 
|---|
| 185 |                                 gt = GenericType::dynamic;
 | 
|---|
| 186 |                         } else {
 | 
|---|
| 187 |                                 // Normalize possibly dtype-static parameter type.
 | 
|---|
| 188 |                                 out.emplace_back( new ast::TypeExpr( paramExpr->location,
 | 
|---|
| 189 |                                         scrubAllTypeVars( ast::deepCopy( paramExpr->type ) ) ) );
 | 
|---|
| 190 |                                 gt |= GenericType::concrete;
 | 
|---|
| 191 |                         }
 | 
|---|
| 192 |                 } else switch ( (*baseParam)->kind ) {
 | 
|---|
| 193 |                 case ast::TypeDecl::Dtype:
 | 
|---|
| 194 |                         // Here, pretend that any incomplete dtype is `void`.
 | 
|---|
| 195 |                         out.emplace_back( new ast::TypeExpr( paramExpr->location,
 | 
|---|
| 196 |                                 new ast::VoidType() ) );
 | 
|---|
| 197 |                         break;
 | 
|---|
| 198 |                 case ast::TypeDecl::Ftype:
 | 
|---|
| 199 |                         // Here, pretend that any ftype is `void (*)(void)`.
 | 
|---|
| 200 |                         out.emplace_back( new ast::TypeExpr( paramExpr->location,
 | 
|---|
| 201 |                                 new ast::FunctionType() ) );
 | 
|---|
| 202 |                         break;
 | 
|---|
| 203 |                 case ast::TypeDecl::Ttype:
 | 
|---|
| 204 |                         assertf( false, "Ttype parameters are not currently allowed as parameters to generic types." );
 | 
|---|
| 205 |                         break;
 | 
|---|
| 206 |                 default:
 | 
|---|
| 207 |                         assertf( false, "Unhandled type parameter kind" );
 | 
|---|
| 208 |                         break;
 | 
|---|
| 209 |                 }
 | 
|---|
| 210 |         }
 | 
|---|
| 211 | 
 | 
|---|
| 212 |         assertf( baseParam == baseParams.end(), "Base Parameters not exausted." );
 | 
|---|
| 213 |         assertf( param == params.end(), "Type parameters not exausted." );
 | 
|---|
| 214 |         return gt;
 | 
|---|
| 215 | }
 | 
|---|
| 216 | 
 | 
|---|
| 217 | /// Substitutes types of members according to baseParams => typeSubs,
 | 
|---|
| 218 | /// returning the result in a new vector.
 | 
|---|
| 219 | ast::vector<ast::Decl> substituteMembers(
 | 
|---|
| 220 |                 ast::vector<ast::Decl> const & members,
 | 
|---|
| 221 |                 ast::vector<ast::TypeDecl> const & baseParams,
 | 
|---|
| 222 |                 ast::vector<ast::TypeExpr> const & typeSubs ) {
 | 
|---|
| 223 |         ast::vector<ast::Decl> out;
 | 
|---|
| 224 |         ast::TypeSubstitution subs( baseParams, typeSubs );
 | 
|---|
| 225 |         for ( ast::ptr<ast::Decl> const & member : members ) {
 | 
|---|
| 226 |                 // Create a manual copy to avoid in-place mutation.
 | 
|---|
| 227 |                 // If being a PureVisitor is decided to be part of apply's interface,
 | 
|---|
| 228 |                 // then we can actually skip this step as it will never mutate in-
 | 
|---|
| 229 |                 // place. (Then we don't need the extra guard to free temp value.)
 | 
|---|
| 230 |                 ast::ptr<ast::Decl> copy = ast::deepCopy( member.get() );
 | 
|---|
| 231 |                 auto result = subs.apply( copy.get() );
 | 
|---|
| 232 |                 out.emplace_back( result.node );
 | 
|---|
| 233 |         }
 | 
|---|
| 234 |         return out;
 | 
|---|
| 235 | }
 | 
|---|
| 236 | 
 | 
|---|
| 237 | /// Substitutes types of members according to baseParams => typeSubs,
 | 
|---|
| 238 | /// modifying them in-place.
 | 
|---|
| 239 | void substituteMembersHere(
 | 
|---|
| 240 |                 ast::vector<ast::Decl> & members,
 | 
|---|
| 241 |                 ast::vector<ast::TypeDecl> const & baseParams,
 | 
|---|
| 242 |                 ast::vector<ast::TypeExpr> const & typeSubs ) {
 | 
|---|
| 243 |         ast::TypeSubstitution subs( baseParams, typeSubs );
 | 
|---|
| 244 |         for ( ast::ptr<ast::Decl> & member : members ) {
 | 
|---|
| 245 |                 // The member must be mutated in place to avoid breaking
 | 
|---|
| 246 |                 assert( member->unique() );
 | 
|---|
| 247 | 
 | 
|---|
| 248 |                 auto field = member.strict_as<ast::ObjectDecl>();
 | 
|---|
| 249 |                 auto result = subs.apply( field->type.get() );
 | 
|---|
| 250 |                 auto copy = ast::mutate_field(
 | 
|---|
| 251 |                         field, &ast::ObjectDecl::type, result.node );
 | 
|---|
| 252 | 
 | 
|---|
| 253 |                 // I'm not kidding, it is very important.
 | 
|---|
| 254 |                 assert( copy == member.get() );
 | 
|---|
| 255 |         }
 | 
|---|
| 256 | }
 | 
|---|
| 257 | 
 | 
|---|
| 258 | /// Strips the instances' type parameters.
 | 
|---|
| 259 | void stripInstParams( ast::BaseInstType * inst ) {
 | 
|---|
| 260 |         inst->params.clear();
 | 
|---|
| 261 | }
 | 
|---|
| 262 | 
 | 
|---|
| 263 | bool isGenericType( ast::Type const * type ) {
 | 
|---|
| 264 |         if ( auto inst = dynamic_cast<ast::StructInstType const *>( type ) ) {
 | 
|---|
| 265 |                 return !inst->params.empty();
 | 
|---|
| 266 |         } else if ( auto inst = dynamic_cast<ast::UnionInstType const *>( type ) ) {
 | 
|---|
| 267 |                 return !inst->params.empty();
 | 
|---|
| 268 |         } else {
 | 
|---|
| 269 |                 return false;
 | 
|---|
| 270 |         }
 | 
|---|
| 271 | }
 | 
|---|
| 272 | 
 | 
|---|
| 273 | // The Passes:
 | 
|---|
| 274 | 
 | 
|---|
| 275 | struct FixDtypeStatic final :
 | 
|---|
| 276 |                 public ast::WithGuards,
 | 
|---|
| 277 |                 public ast::WithVisitorRef<FixDtypeStatic>,
 | 
|---|
| 278 |                 public ast::WithShortCircuiting,
 | 
|---|
| 279 |                 public ast::WithStmtsToAdd<> {
 | 
|---|
| 280 |         ast::ApplicationExpr const * previsit( ast::ApplicationExpr const * expr );
 | 
|---|
| 281 |         void previsit( ast::AddressExpr const * expr );
 | 
|---|
| 282 | 
 | 
|---|
| 283 |         ast::Expr const * postvisit( ast::MemberExpr const * expr );
 | 
|---|
| 284 | private:
 | 
|---|
| 285 |         template<typename Aggr>
 | 
|---|
| 286 |         ast::Expr const * fixMemberExpr(
 | 
|---|
| 287 |                 Aggr const * inst, ast::MemberExpr const * memberExpr );
 | 
|---|
| 288 | 
 | 
|---|
| 289 |         ast::Expr const * fixMemberExpr(
 | 
|---|
| 290 |                 ast::vector<ast::TypeDecl> const & baseParams,
 | 
|---|
| 291 |                 ast::MemberExpr const * memberExpr );
 | 
|---|
| 292 | 
 | 
|---|
| 293 |         bool isLValueArg = false;
 | 
|---|
| 294 | };
 | 
|---|
| 295 | 
 | 
|---|
| 296 | ast::ApplicationExpr const * FixDtypeStatic::previsit(
 | 
|---|
| 297 |                 ast::ApplicationExpr const * expr ) {
 | 
|---|
| 298 |         GuardValue( isLValueArg ) = false;
 | 
|---|
| 299 |         ast::Decl const * function = ast::getFunction( expr );
 | 
|---|
| 300 |         if ( ast::Linkage::Intrinsic != function->linkage
 | 
|---|
| 301 |                         || !CodeGen::isAssignment( function->name ) ) {
 | 
|---|
| 302 |                 return expr;
 | 
|---|
| 303 |         }
 | 
|---|
| 304 | 
 | 
|---|
| 305 |         // Explicity visit children because only the first element must be a
 | 
|---|
| 306 |         // C lvalue (normally, it can only send info to both or neither).
 | 
|---|
| 307 |         visit_children = false;
 | 
|---|
| 308 |         expr = mutate_field( expr, &ast::ApplicationExpr::env,
 | 
|---|
| 309 |                 maybe_accept( expr->env.get(), *visitor ) );
 | 
|---|
| 310 |         expr = mutate_field( expr, &ast::ApplicationExpr::result,
 | 
|---|
| 311 |                 maybe_accept( expr->result.get(), *visitor ) );
 | 
|---|
| 312 |         expr = mutate_field( expr, &ast::ApplicationExpr::func,
 | 
|---|
| 313 |                 maybe_accept( expr->func.get(), *visitor ) );
 | 
|---|
| 314 |         isLValueArg = true;
 | 
|---|
| 315 |         for ( unsigned i = 0; i < expr->args.size(); ++i ) {
 | 
|---|
| 316 |                 ast::Expr const * newExpr = expr->args[i]->accept( *visitor );
 | 
|---|
| 317 |                 // This is declared here for lifetime reasons.
 | 
|---|
| 318 |                 ast::ptr<ast::CastExpr> cast;
 | 
|---|
| 319 |                 if ( newExpr != expr->args[i].get() &&
 | 
|---|
| 320 |                                 (cast = dynamic_cast<ast::CastExpr const *>( newExpr )) ) {
 | 
|---|
| 321 |                         newExpr = cast->arg.get();
 | 
|---|
| 322 |                 }
 | 
|---|
| 323 |                 expr = mutate_field_index( expr, &ast::ApplicationExpr::args,
 | 
|---|
| 324 |                         i, newExpr );
 | 
|---|
| 325 |                 isLValueArg = false;
 | 
|---|
| 326 |         }
 | 
|---|
| 327 |         return expr;
 | 
|---|
| 328 | }
 | 
|---|
| 329 | 
 | 
|---|
| 330 | void FixDtypeStatic::previsit( ast::AddressExpr const * ) {
 | 
|---|
| 331 |         // The argument of an address expression (`&`) must be a C lvalue.
 | 
|---|
| 332 |         GuardValue( isLValueArg ) = true;
 | 
|---|
| 333 | }
 | 
|---|
| 334 | 
 | 
|---|
| 335 | ast::Expr const * FixDtypeStatic::postvisit( ast::MemberExpr const * expr ) {
 | 
|---|
| 336 |         ast::ptr<ast::Type> const & type = expr->aggregate->result;
 | 
|---|
| 337 |         if ( auto inst = type.as<ast::StructInstType>() ) {
 | 
|---|
| 338 |                 if ( !inst->params.empty() ) return fixMemberExpr( inst, expr );
 | 
|---|
| 339 |         } else if ( auto inst = type.as<ast::UnionInstType>() ) {
 | 
|---|
| 340 |                 if ( !inst->params.empty() ) return fixMemberExpr( inst, expr );
 | 
|---|
| 341 |         }
 | 
|---|
| 342 |         return expr;
 | 
|---|
| 343 | }
 | 
|---|
| 344 | 
 | 
|---|
| 345 | template<typename Aggr>
 | 
|---|
| 346 | ast::Expr const * FixDtypeStatic::fixMemberExpr(
 | 
|---|
| 347 |                 Aggr const * inst, ast::MemberExpr const * memberExpr ) {
 | 
|---|
| 348 |         return fixMemberExpr( inst->base->params, memberExpr );
 | 
|---|
| 349 | }
 | 
|---|
| 350 | 
 | 
|---|
| 351 | ast::Expr const * FixDtypeStatic::fixMemberExpr(
 | 
|---|
| 352 |                 ast::vector<ast::TypeDecl> const & baseParams,
 | 
|---|
| 353 |                 ast::MemberExpr const * memberExpr ) {
 | 
|---|
| 354 |         // Need to cast dtype-static member expressions to their actual type
 | 
|---|
| 355 |         // before the actual type type is erased.
 | 
|---|
| 356 |         // NOTE: The casts here have the third argument (isGenerated) set to
 | 
|---|
| 357 |         // ExplicitCast so that they casts persist until Box, where they are needed.
 | 
|---|
| 358 | 
 | 
|---|
| 359 |         if ( !isDtypeStatic( baseParams ) ||
 | 
|---|
| 360 |                         ResolvExpr::typesCompatible(
 | 
|---|
| 361 |                                 memberExpr->result,
 | 
|---|
| 362 |                                 memberExpr->member->get_type() ) ) {
 | 
|---|
| 363 |                 return memberExpr;
 | 
|---|
| 364 |         }
 | 
|---|
| 365 | 
 | 
|---|
| 366 |         // Type of member and type of expression differ.
 | 
|---|
| 367 |         ast::Type const * concType = ast::deepCopy( memberExpr->result );
 | 
|---|
| 368 |         CodeLocation const & location = memberExpr->location;
 | 
|---|
| 369 |         if ( isLValueArg ) {
 | 
|---|
| 370 |                 // The result must be a C lvalue expression. So make a new reference
 | 
|---|
| 371 |                 // variable with the correct actual type to replace the
 | 
|---|
| 372 |                 // member expression.
 | 
|---|
| 373 |                 //   forall(T &)
 | 
|---|
| 374 |                 //   struct Ptr {
 | 
|---|
| 375 |                 //     T * x;
 | 
|---|
| 376 |                 //   };
 | 
|---|
| 377 |                 //   Ptr(int) p;
 | 
|---|
| 378 |                 //   int i;
 | 
|---|
| 379 |                 // The original expression:
 | 
|---|
| 380 |                 //   p.x = &i;
 | 
|---|
| 381 |                 // Becomes the expression/declaration:
 | 
|---|
| 382 |                 //   int *& _dtype_static_member_0;
 | 
|---|
| 383 |                 //   (_dtype_static_member_0 = (int**)&p.x,
 | 
|---|
| 384 |                 //    _dtype_static_member_0) = &i;
 | 
|---|
| 385 | 
 | 
|---|
| 386 |                 // The declaration is simple:
 | 
|---|
| 387 |                 static UniqueName tmpNamer( "_dtype_static_member_" );
 | 
|---|
| 388 |                 ast::ObjectDecl * tmp = new ast::ObjectDecl( location,
 | 
|---|
| 389 |                         tmpNamer.newName(),
 | 
|---|
| 390 |                         new ast::ReferenceType( concType ),
 | 
|---|
| 391 |                         nullptr,
 | 
|---|
| 392 |                         ast::Storage::Classes(),
 | 
|---|
| 393 |                         ast::Linkage::C
 | 
|---|
| 394 |                 );
 | 
|---|
| 395 |                 stmtsToAddBefore.push_back( new ast::DeclStmt( location, tmp ) );
 | 
|---|
| 396 | 
 | 
|---|
| 397 |                 // The expression is more complex, uses references and reference /
 | 
|---|
| 398 |                 // pointer parity. But breaking it up risks reordering.
 | 
|---|
| 399 |                 return new ast::CommaExpr( location,
 | 
|---|
| 400 |                         ast::UntypedExpr::createAssign( location,
 | 
|---|
| 401 |                                 new ast::VariableExpr( location, tmp ),
 | 
|---|
| 402 |                                 new ast::CastExpr( location,
 | 
|---|
| 403 |                                         new ast::AddressExpr( location, memberExpr ),
 | 
|---|
| 404 |                                         new ast::PointerType( ast::deepCopy( concType ) ),
 | 
|---|
| 405 |                                         ast::ExplicitCast
 | 
|---|
| 406 |                                 )
 | 
|---|
| 407 |                         ),
 | 
|---|
| 408 |                         new ast::VariableExpr( location, tmp )
 | 
|---|
| 409 |                 );
 | 
|---|
| 410 |         } else {
 | 
|---|
| 411 |                 // Here, it can simply add a cast to actual types.
 | 
|---|
| 412 |                 return new ast::CastExpr( location,
 | 
|---|
| 413 |                         memberExpr,
 | 
|---|
| 414 |                         concType,
 | 
|---|
| 415 |                         ast::ExplicitCast
 | 
|---|
| 416 |                 );
 | 
|---|
| 417 |         }
 | 
|---|
| 418 | }
 | 
|---|
| 419 | 
 | 
|---|
| 420 | struct GenericInstantiator final :
 | 
|---|
| 421 |                 public ast::WithCodeLocation,
 | 
|---|
| 422 |                 public ast::WithConstTypeSubstitution,
 | 
|---|
| 423 |                 public ast::WithDeclsToAdd<>,
 | 
|---|
| 424 |                 public ast::WithGuards,
 | 
|---|
| 425 |                 public ast::WithVisitorRef<GenericInstantiator>
 | 
|---|
| 426 | {
 | 
|---|
| 427 |         /// Map of (generic type, parameter list) pairs
 | 
|---|
| 428 |         /// to concrete type instantiations.
 | 
|---|
| 429 |         InstantiationMap instantiations;
 | 
|---|
| 430 |         /// Set of types which are dtype-only generic
 | 
|---|
| 431 |         /// (and therefore have static layout).
 | 
|---|
| 432 |         std::set<ast::AggregateDecl const *> dtypeStatics;
 | 
|---|
| 433 |         /// Namer for concrete types.
 | 
|---|
| 434 |         UniqueName typeNamer;
 | 
|---|
| 435 |         /// Should not make use of type environment to replace types of function
 | 
|---|
| 436 |         /// parameter and return values.
 | 
|---|
| 437 |         bool inFunctionType = false;
 | 
|---|
| 438 |         /// Index of current member, used to recreate MemberExprs with the
 | 
|---|
| 439 |         /// member from an instantiation.
 | 
|---|
| 440 |         int memberIndex = -1;
 | 
|---|
| 441 | 
 | 
|---|
| 442 |         GenericInstantiator() :
 | 
|---|
| 443 |                 instantiations(), dtypeStatics(), typeNamer("_conc_") {}
 | 
|---|
| 444 | 
 | 
|---|
| 445 |         ast::Type const * postvisit( ast::StructInstType const * inst );
 | 
|---|
| 446 |         ast::Type const * postvisit( ast::UnionInstType const * inst );
 | 
|---|
| 447 | 
 | 
|---|
| 448 |         void previsit( ast::MemberExpr const * expr );
 | 
|---|
| 449 |         ast::Expr const * postvisit( ast::MemberExpr const * expr );
 | 
|---|
| 450 |         ast::Expr const * postvisit( ast::Expr const * expr );
 | 
|---|
| 451 |         ast::Designation const * postvisit( ast::Designation const * );
 | 
|---|
| 452 | 
 | 
|---|
| 453 |         void previsit( ast::ParseNode const * node ) {
 | 
|---|
| 454 |                 GuardValue( location ) = &node->location;
 | 
|---|
| 455 |         }
 | 
|---|
| 456 |         void previsit( ast::FunctionType const * ) {
 | 
|---|
| 457 |                 GuardValue( inFunctionType ) = true;
 | 
|---|
| 458 |         }
 | 
|---|
| 459 |         void beginScope() {
 | 
|---|
| 460 |                 instantiations.beginScope();
 | 
|---|
| 461 |         }
 | 
|---|
| 462 |         void endScope() {
 | 
|---|
| 463 |                 instantiations.endScope();
 | 
|---|
| 464 |         }
 | 
|---|
| 465 | private:
 | 
|---|
| 466 |         /// Wrap instantiation lookup for structures.
 | 
|---|
| 467 |         ast::StructDecl const * lookup(
 | 
|---|
| 468 |                 ast::StructInstType const * inst, type_vector const & typeSubs ) const;
 | 
|---|
| 469 |         /// Wrap instantiation lookup for unions.
 | 
|---|
| 470 |         ast::UnionDecl const * lookup(
 | 
|---|
| 471 |                 ast::UnionInstType const * inst, type_vector const & typeSubs ) const;
 | 
|---|
| 472 |         /// Wrap instantiation insertion for structures.
 | 
|---|
| 473 |         void insert( ast::StructInstType const * inst,
 | 
|---|
| 474 |                 type_vector const & typeSubs, ast::StructDecl const * decl );
 | 
|---|
| 475 |         /// Wrap instantiation insertion for unions.
 | 
|---|
| 476 |         void insert( ast::UnionInstType const * inst,
 | 
|---|
| 477 |                 type_vector const & typeSubs, ast::UnionDecl const * decl );
 | 
|---|
| 478 | 
 | 
|---|
| 479 |         void replaceParametersWithConcrete( ast::vector<ast::Expr> & params );
 | 
|---|
| 480 |         ast::Type const * replaceWithConcrete( ast::Type const * type, bool doClone );
 | 
|---|
| 481 | 
 | 
|---|
| 482 |         template<typename AggrDecl>
 | 
|---|
| 483 |         ast::Type const * fixInstType( ast::SueInstType<AggrDecl> const * inst );
 | 
|---|
| 484 | 
 | 
|---|
| 485 |         /// Strips a dtype-static aggregate decl of its type parameters,
 | 
|---|
| 486 |         /// marks it as stripped.
 | 
|---|
| 487 |         void stripDtypeParams( ast::AggregateDecl * base,
 | 
|---|
| 488 |                 ast::vector<ast::TypeDecl> & baseParams,
 | 
|---|
| 489 |                 ast::vector<ast::TypeExpr> const & typeSubs );
 | 
|---|
| 490 | };
 | 
|---|
| 491 | 
 | 
|---|
| 492 | ast::Type const * GenericInstantiator::postvisit(
 | 
|---|
| 493 |                 ast::StructInstType const * inst ) {
 | 
|---|
| 494 |         return fixInstType( inst );
 | 
|---|
| 495 | }
 | 
|---|
| 496 | 
 | 
|---|
| 497 | ast::Type const * GenericInstantiator::postvisit(
 | 
|---|
| 498 |                 ast::UnionInstType const * inst ) {
 | 
|---|
| 499 |         return fixInstType( inst );
 | 
|---|
| 500 | }
 | 
|---|
| 501 | 
 | 
|---|
| 502 | template<typename AggrDecl>
 | 
|---|
| 503 | ast::Type const * GenericInstantiator::fixInstType(
 | 
|---|
| 504 |                 ast::SueInstType<AggrDecl> const * inst ) {
 | 
|---|
| 505 |         assert( location );
 | 
|---|
| 506 | 
 | 
|---|
| 507 |         // There is nothing to mutate if the params are empty.
 | 
|---|
| 508 |         if ( inst->params.empty() ) return inst;
 | 
|---|
| 509 | 
 | 
|---|
| 510 |         // Need to replace type variables to ensure that generic types are
 | 
|---|
| 511 |         // instantiated for the return values of polymorphic functions (in
 | 
|---|
| 512 |         // particular, for thunks, because they are not [currently] copy
 | 
|---|
| 513 |         // constructed).
 | 
|---|
| 514 |         // (This used to be run only on structures, but I believe both need it.)
 | 
|---|
| 515 |         inst = strict_dynamic_cast<ast::SueInstType<AggrDecl> const *>(
 | 
|---|
| 516 |                 replaceWithConcrete( inst, false ) );
 | 
|---|
| 517 | 
 | 
|---|
| 518 |         // Check for an already-instantiatiated dtype-static type.
 | 
|---|
| 519 |         if ( dtypeStatics.find( inst->base ) != dtypeStatics.end() ) {
 | 
|---|
| 520 |                 auto mutInst = ast::mutate( inst );
 | 
|---|
| 521 |                 stripInstParams( mutInst );
 | 
|---|
| 522 |                 return mutInst;
 | 
|---|
| 523 |         }
 | 
|---|
| 524 | 
 | 
|---|
| 525 |         // Check if the type can be concretely instantiated;
 | 
|---|
| 526 |         // and put substitutions in typeSubs.
 | 
|---|
| 527 |         assertf( inst->base, "Base data-type has parameters." );
 | 
|---|
| 528 |         ast::vector<ast::TypeExpr> typeSubs;
 | 
|---|
| 529 |         GenericType gt = makeSubstitutions( typeSubs, inst->base->params, inst->params );
 | 
|---|
| 530 |         switch ( gt ) {
 | 
|---|
| 531 |         case GenericType::dtypeStatic:
 | 
|---|
| 532 |         {
 | 
|---|
| 533 |                 auto mutInst = ast::mutate( inst );
 | 
|---|
| 534 |                 assert( mutInst->base->unique() );
 | 
|---|
| 535 |                 auto mutBase = mutInst->base.get_and_mutate();
 | 
|---|
| 536 |                 stripDtypeParams( mutBase, mutBase->params, typeSubs );
 | 
|---|
| 537 |                 stripInstParams( mutInst );
 | 
|---|
| 538 |                 return mutInst;
 | 
|---|
| 539 |         }
 | 
|---|
| 540 |         case GenericType::concrete:
 | 
|---|
| 541 |         {
 | 
|---|
| 542 |                 // Make concrete instantiation of generic type.
 | 
|---|
| 543 |                 AggrDecl const * concDecl = lookup( inst, typeSubs );
 | 
|---|
| 544 |                 if ( !concDecl ) {
 | 
|---|
| 545 |                         // Set concDecl to new type, insert type declaration
 | 
|---|
| 546 |                         // into statements to add.
 | 
|---|
| 547 |                         AggrDecl * newDecl = new AggrDecl( *location,
 | 
|---|
| 548 |                                 typeNamer.newName( inst->name )
 | 
|---|
| 549 |                         );
 | 
|---|
| 550 |                         newDecl->body = inst->base->body;
 | 
|---|
| 551 |                         newDecl->members = substituteMembers(
 | 
|---|
| 552 |                                 inst->base->members,
 | 
|---|
| 553 |                                 inst->base->params,
 | 
|---|
| 554 |                                 typeSubs
 | 
|---|
| 555 |                         );
 | 
|---|
| 556 | 
 | 
|---|
| 557 |                         // Forward declare before recursion. (TODO: Only when needed, #199.)
 | 
|---|
| 558 |                         insert( inst, typeSubs, newDecl );
 | 
|---|
| 559 |                         if ( AggrDecl const * forwardDecl = ast::asForward( newDecl ) ) {
 | 
|---|
| 560 |                                 declsToAddBefore.push_back( forwardDecl );
 | 
|---|
| 561 |                         }
 | 
|---|
| 562 |                         // Recursively instantiate members:
 | 
|---|
| 563 |                         concDecl = strict_dynamic_cast<AggrDecl const *>(
 | 
|---|
| 564 |                                 newDecl->accept( *visitor ) );
 | 
|---|
| 565 |                         // Must occur before declaration is added so
 | 
|---|
| 566 |                         // that member instantiation appear first.
 | 
|---|
| 567 |                         declsToAddBefore.push_back( concDecl );
 | 
|---|
| 568 |                 }
 | 
|---|
| 569 |                 return new ast::SueInstType<AggrDecl>( concDecl, inst->qualifiers );
 | 
|---|
| 570 |         }
 | 
|---|
| 571 |         case GenericType::dynamic:
 | 
|---|
| 572 |                 // Do nothing.
 | 
|---|
| 573 |         default:
 | 
|---|
| 574 |                 // Should never happen.
 | 
|---|
| 575 |                 return inst;
 | 
|---|
| 576 |         }
 | 
|---|
| 577 | }
 | 
|---|
| 578 | 
 | 
|---|
| 579 | void GenericInstantiator::previsit( ast::MemberExpr const * expr ) {
 | 
|---|
| 580 |         GuardValue( location ) = &expr->location;
 | 
|---|
| 581 |         GuardValue( memberIndex ) = -1;
 | 
|---|
| 582 |         // Only run on expressions where the field being accessed is generic.
 | 
|---|
| 583 |         if ( isGenericType( expr->aggregate->result ) ) {
 | 
|---|
| 584 |                 // Find the location of the member:
 | 
|---|
| 585 |                 ast::AggregateDecl const * aggr =
 | 
|---|
| 586 |                         expr->aggregate->result.strict_as<ast::BaseInstType>()->aggr();
 | 
|---|
| 587 |                 ast::vector<ast::Decl> const & members = aggr->members;
 | 
|---|
| 588 |                 auto it = std::find( members.begin(), members.end(), expr->member );
 | 
|---|
| 589 |                 memberIndex = std::distance( members.begin(), it );
 | 
|---|
| 590 |                 assertf( memberIndex < (int)members.size(), "Could not find member %s in generic type %s.", toString( expr->member ).c_str(), toString( expr->aggregate ).c_str() );
 | 
|---|
| 591 |         }
 | 
|---|
| 592 | }
 | 
|---|
| 593 | 
 | 
|---|
| 594 | ast::Expr const * GenericInstantiator::postvisit(
 | 
|---|
| 595 |                 ast::MemberExpr const * expr ) {
 | 
|---|
| 596 |         if ( memberIndex == -1 ) {
 | 
|---|
| 597 |                 return expr;
 | 
|---|
| 598 |         }
 | 
|---|
| 599 | 
 | 
|---|
| 600 |         // Using the location from the generic type, find the member
 | 
|---|
| 601 |         // in the instantiation and rebuild the member expression.
 | 
|---|
| 602 |         ast::AggregateDecl const * aggr =
 | 
|---|
| 603 |                 expr->aggregate->result.strict_as<ast::BaseInstType>()->aggr();
 | 
|---|
| 604 |         assertf( memberIndex < (int)aggr->members.size(), "Instantiation somehow has fewer members than the generic type." );
 | 
|---|
| 605 |         ast::Decl const * member = *std::next( aggr->members.begin(), memberIndex );
 | 
|---|
| 606 |         assertf( member->name == expr->member->name, "Instantiation has different member order than the generic type. %s / %s", toString( member ).c_str(), toString( expr->member ).c_str() );
 | 
|---|
| 607 |         auto field = strict_dynamic_cast< ast::DeclWithType const * >( member );
 | 
|---|
| 608 |         ast::MemberExpr * ret = new ast::MemberExpr( expr->location,
 | 
|---|
| 609 |                 field,
 | 
|---|
| 610 |                 ast::deepCopy( expr->aggregate )
 | 
|---|
| 611 |         );
 | 
|---|
| 612 |         // For pointer decay:
 | 
|---|
| 613 |         ret->result = ResolvExpr::adjustExprType(
 | 
|---|
| 614 |                 ret->result,
 | 
|---|
| 615 |                 ast::TypeEnvironment(),
 | 
|---|
| 616 |                 ast::SymbolTable()
 | 
|---|
| 617 |         );
 | 
|---|
| 618 |         ret->env = expr->env;
 | 
|---|
| 619 |         return ret;
 | 
|---|
| 620 | }
 | 
|---|
| 621 | 
 | 
|---|
| 622 | ast::Expr const * GenericInstantiator::postvisit( ast::Expr const * expr ) {
 | 
|---|
| 623 |         // We are not modifying env on MemberExpr, but that seems to work.
 | 
|---|
| 624 |         if ( expr->env ) {
 | 
|---|
| 625 |                 auto newEnv = expr->env->accept( *visitor );
 | 
|---|
| 626 |                 expr = ast::mutate_field( expr, &ast::Expr::env, newEnv );
 | 
|---|
| 627 |         }
 | 
|---|
| 628 |         return expr;
 | 
|---|
| 629 | }
 | 
|---|
| 630 | 
 | 
|---|
| 631 | // This attempts to figure out what the final name of the field will be.
 | 
|---|
| 632 | // Pretty printing can cause this to become incorrect.
 | 
|---|
| 633 | std::string getPrintName( ast::DeclWithType const * decl ) {
 | 
|---|
| 634 |         return ( decl->linkage.is_mangled )
 | 
|---|
| 635 |                 ? decl->scopedMangleName() : decl->name;
 | 
|---|
| 636 | }
 | 
|---|
| 637 | 
 | 
|---|
| 638 | ast::Designation const * GenericInstantiator::postvisit(
 | 
|---|
| 639 |                 ast::Designation const * designation ) {
 | 
|---|
| 640 |         // Disconnect designator names from their fields.
 | 
|---|
| 641 |         // It is now incorrect to point at the generic definition where the used
 | 
|---|
| 642 |         // type now is replaced with a concrete instance. Ideally, new variable
 | 
|---|
| 643 |         // expressions would point at fields in the concrete instances, but that
 | 
|---|
| 644 |         // is work and that information should not be needed this late in
 | 
|---|
| 645 |         // compilation.
 | 
|---|
| 646 | 
 | 
|---|
| 647 |         // Modify all designations, even if not needed.
 | 
|---|
| 648 |         auto mutNode = mutate( designation );
 | 
|---|
| 649 |         for ( ast::ptr<ast::Expr> & designator : mutNode->designators ) {
 | 
|---|
| 650 |                 if ( auto var = designator.as<ast::VariableExpr>() ) {
 | 
|---|
| 651 |                         designator = new ast::NameExpr(
 | 
|---|
| 652 |                                 var->location, getPrintName( var->var ) );
 | 
|---|
| 653 |                 }
 | 
|---|
| 654 |         }
 | 
|---|
| 655 |         return mutNode;
 | 
|---|
| 656 | }
 | 
|---|
| 657 | 
 | 
|---|
| 658 | ast::StructDecl const * GenericInstantiator::lookup(
 | 
|---|
| 659 |                 ast::StructInstType const * inst,
 | 
|---|
| 660 |                 type_vector const & typeSubs ) const {
 | 
|---|
| 661 |         auto ret = instantiations.lookup( inst->base, typeSubs );
 | 
|---|
| 662 |         return strict_dynamic_cast<ast::StructDecl const *, nullptr>( ret );
 | 
|---|
| 663 | }
 | 
|---|
| 664 | 
 | 
|---|
| 665 | ast::UnionDecl const * GenericInstantiator::lookup(
 | 
|---|
| 666 |                 ast::UnionInstType const * inst,
 | 
|---|
| 667 |                 type_vector const & typeSubs ) const {
 | 
|---|
| 668 |         auto ret = instantiations.lookup( inst->base, typeSubs );
 | 
|---|
| 669 |         return strict_dynamic_cast<ast::UnionDecl const *, nullptr>( ret );
 | 
|---|
| 670 | }
 | 
|---|
| 671 | 
 | 
|---|
| 672 | void GenericInstantiator::insert( ast::StructInstType const * inst,
 | 
|---|
| 673 |                 type_vector const & typeSubs, ast::StructDecl const * decl ) {
 | 
|---|
| 674 |         instantiations.insert( inst->base, typeSubs, decl );
 | 
|---|
| 675 | }
 | 
|---|
| 676 | 
 | 
|---|
| 677 | void GenericInstantiator::insert( ast::UnionInstType const * inst,
 | 
|---|
| 678 |                 type_vector const & typeSubs, ast::UnionDecl const * decl ) {
 | 
|---|
| 679 |         instantiations.insert( inst->base, typeSubs, decl );
 | 
|---|
| 680 | }
 | 
|---|
| 681 | 
 | 
|---|
| 682 | void GenericInstantiator::replaceParametersWithConcrete(
 | 
|---|
| 683 |                 ast::vector<ast::Expr> & params ) {
 | 
|---|
| 684 |         for ( ast::ptr<ast::Expr> & param : params ) {
 | 
|---|
| 685 |                 auto paramType = param.as<ast::TypeExpr>();
 | 
|---|
| 686 |                 assertf( paramType, "Aggregate parameters should be type expressions." );
 | 
|---|
| 687 |                 auto type = replaceWithConcrete( paramType->type, false );
 | 
|---|
| 688 |                 param = ast::mutate_field( paramType, &ast::TypeExpr::type, type );
 | 
|---|
| 689 |         }
 | 
|---|
| 690 | }
 | 
|---|
| 691 | 
 | 
|---|
| 692 | ast::Type const * GenericInstantiator::replaceWithConcrete(
 | 
|---|
| 693 |                 ast::Type const * type, bool doClone ) {
 | 
|---|
| 694 |         if ( auto inst = dynamic_cast<ast::TypeInstType const *>( type ) ) {
 | 
|---|
| 695 |                 if ( typeSubs && !inFunctionType ) {
 | 
|---|
| 696 |                         ast::Type const * concType = typeSubs->lookup( inst );
 | 
|---|
| 697 |                         return ast::deepCopy( ( concType ) ? concType : inst );
 | 
|---|
| 698 |                 }
 | 
|---|
| 699 |         } else if ( auto inst = dynamic_cast<ast::StructInstType const *>( type ) ) {
 | 
|---|
| 700 |                 auto mut = ( doClone ) ? ast::deepCopy( inst ) : ast::mutate( inst );
 | 
|---|
| 701 |                 replaceParametersWithConcrete( mut->params );
 | 
|---|
| 702 |                 return mut;
 | 
|---|
| 703 |         } else if ( auto inst = dynamic_cast<ast::UnionInstType const *>( type ) ) {
 | 
|---|
| 704 |                 auto mut = ( doClone ) ? ast::deepCopy( inst ) : ast::mutate( inst );
 | 
|---|
| 705 |                 replaceParametersWithConcrete( mut->params );
 | 
|---|
| 706 |                 return mut;
 | 
|---|
| 707 |         }
 | 
|---|
| 708 |         return type;
 | 
|---|
| 709 | }
 | 
|---|
| 710 | 
 | 
|---|
| 711 | void GenericInstantiator::stripDtypeParams(
 | 
|---|
| 712 |                 ast::AggregateDecl * base,
 | 
|---|
| 713 |                 ast::vector<ast::TypeDecl> & baseParams,
 | 
|---|
| 714 |                 ast::vector<ast::TypeExpr> const & typeSubs ) {
 | 
|---|
| 715 |         substituteMembersHere( base->members, baseParams, typeSubs );
 | 
|---|
| 716 | 
 | 
|---|
| 717 |         baseParams.clear();
 | 
|---|
| 718 | 
 | 
|---|
| 719 |         dtypeStatics.insert( base );
 | 
|---|
| 720 | }
 | 
|---|
| 721 | 
 | 
|---|
| 722 | } // namespace
 | 
|---|
| 723 | 
 | 
|---|
| 724 | void instantiateGeneric( ast::TranslationUnit & translationUnit ) {
 | 
|---|
| 725 |         ast::Pass<FixDtypeStatic>::run( translationUnit );
 | 
|---|
| 726 |         ast::Pass<GenericInstantiator>::run( translationUnit );
 | 
|---|
| 727 | }
 | 
|---|
| 728 | 
 | 
|---|
| 729 | } // namespace GenPoly
 | 
|---|
| 730 | 
 | 
|---|
| 731 | // Local Variables: //
 | 
|---|
| 732 | // tab-width: 4 //
 | 
|---|
| 733 | // mode: c++ //
 | 
|---|
| 734 | // compile-command: "make install" //
 | 
|---|
| 735 | // End: //
 | 
|---|