| [1c0657a] | 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 | //
 | 
|---|
| [04db9f6] | 7 | // InstantiateGenericNew.cpp -- Create concrete instances of generic types.
 | 
|---|
| [1c0657a] | 8 | //
 | 
|---|
 | 9 | // Author           : Andrew Beach
 | 
|---|
 | 10 | // Created On       : Tue Aug 16 10:51:00 2022
 | 
|---|
 | 11 | // Last Modified By : Andrew Beach
 | 
|---|
| [1dafdfc] | 12 | // Last Modified On : Mon Oct 31 16:48:00 2022
 | 
|---|
 | 13 | // Update Count     : 1
 | 
|---|
| [1c0657a] | 14 | //
 | 
|---|
 | 15 | 
 | 
|---|
 | 16 | #include "InstantiateGeneric.h"
 | 
|---|
 | 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
 | 
|---|
| [8f1e035] | 24 | #include "AST/Create.hpp"              // for asForward
 | 
|---|
| [e01eb4a] | 25 | #include "AST/Inspect.hpp"             // for getFunction
 | 
|---|
| [1c0657a] | 26 | #include "AST/Pass.hpp"                // for Pass, WithGuard, WithShortCi...
 | 
|---|
 | 27 | #include "AST/TranslationUnit.hpp"     // for TranslationUnit
 | 
|---|
| [bc899d6] | 28 | #include "AST/Vector.hpp"              // for vector
 | 
|---|
| [1c0657a] | 29 | #include "CodeGen/OperatorTable.h"     // for isAssignment
 | 
|---|
 | 30 | #include "Common/ScopedMap.h"          // for ScopedMap
 | 
|---|
 | 31 | #include "Common/UniqueName.h"         // for UniqueName
 | 
|---|
 | 32 | #include "GenPoly/GenPoly.h"           // for isPolyType, typesPolyCompatible
 | 
|---|
 | 33 | #include "GenPoly/ScrubTyVars.h"       // for scrubAll
 | 
|---|
| [5bf3976] | 34 | #include "ResolvExpr/AdjustExprType.hpp"  // for adjustExprType
 | 
|---|
| [e563edf] | 35 | #include "ResolvExpr/Unify.h"          // for typesCompatible
 | 
|---|
| [1c0657a] | 36 | 
 | 
|---|
 | 37 | namespace GenPoly {
 | 
|---|
 | 38 | 
 | 
|---|
 | 39 | namespace {
 | 
|---|
 | 40 | 
 | 
|---|
 | 41 | // Utilities:
 | 
|---|
 | 42 | 
 | 
|---|
| [bc899d6] | 43 | using type_vector = ast::vector< ast::TypeExpr >;
 | 
|---|
| [1c0657a] | 44 | 
 | 
|---|
 | 45 | /// Abstracts type equality for a list of parameter types.
 | 
|---|
 | 46 | struct TypeList {
 | 
|---|
 | 47 |         TypeList() : params() {}
 | 
|---|
| [bc899d6] | 48 |         TypeList( ast::vector< ast::Type > const & params ) :
 | 
|---|
| [1c0657a] | 49 |                 params( params ) {}
 | 
|---|
| [bc899d6] | 50 |         TypeList( ast::vector< ast::Type > && params ) :
 | 
|---|
| [1c0657a] | 51 |                 params( std::move( params ) ) {}
 | 
|---|
 | 52 |         TypeList( TypeList const & that ) : params( that.params ) {}
 | 
|---|
 | 53 |         TypeList( TypeList && that ) : params( std::move( that.params ) ) {}
 | 
|---|
 | 54 | 
 | 
|---|
| [bc899d6] | 55 |         TypeList( ast::vector< ast::TypeExpr > const & exprs ) :
 | 
|---|
| [1c0657a] | 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 | 
 | 
|---|
| [bc899d6] | 86 |         ast::vector<ast::Type> params;
 | 
|---|
| [1c0657a] | 87 | };
 | 
|---|
 | 88 | 
 | 
|---|
 | 89 | /// Maps a key and a TypeList to a valuue. Also supports scoping.
 | 
|---|
| [c36814a] | 90 | class InstantiationMap final {
 | 
|---|
| [1c0657a] | 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(
 | 
|---|
| [bc899d6] | 107 |                         ast::AggregateDecl const * key,
 | 
|---|
 | 108 |                         type_vector const & params ) const {
 | 
|---|
| [1c0657a] | 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 | 
 | 
|---|
| [bc899d6] | 155 | bool isDtypeStatic( ast::vector<ast::TypeDecl> const & baseParams ) {
 | 
|---|
| [1c0657a] | 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(
 | 
|---|
| [bc899d6] | 166 |                 ast::vector<ast::TypeExpr> & out,
 | 
|---|
 | 167 |                 ast::vector<ast::TypeDecl> const & baseParams,
 | 
|---|
 | 168 |                 ast::vector<ast::Expr> const & params ) {
 | 
|---|
| [1c0657a] | 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.
 | 
|---|
| [bc899d6] | 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;
 | 
|---|
| [1c0657a] | 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(
 | 
|---|
| [bc899d6] | 240 |                 ast::vector<ast::Decl> & members,
 | 
|---|
 | 241 |                 ast::vector<ast::TypeDecl> const & baseParams,
 | 
|---|
 | 242 |                 ast::vector<ast::TypeExpr> const & typeSubs ) {
 | 
|---|
| [1c0657a] | 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(
 | 
|---|
| [bc899d6] | 290 |                 ast::vector<ast::TypeDecl> const & baseParams,
 | 
|---|
| [1c0657a] | 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;
 | 
|---|
| [e01eb4a] | 299 |         ast::Decl const * function = ast::getFunction( expr );
 | 
|---|
| [1c0657a] | 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;
 | 
|---|
| [1ee0a4da] | 337 |         if ( auto inst = type.as<ast::StructInstType>() ) {
 | 
|---|
 | 338 |                 if ( !inst->params.empty() ) return fixMemberExpr( inst, expr );
 | 
|---|
| [1c0657a] | 339 |         } else if ( auto inst = type.as<ast::UnionInstType>() ) {
 | 
|---|
| [1ee0a4da] | 340 |                 if ( !inst->params.empty() ) return fixMemberExpr( inst, expr );
 | 
|---|
| [1c0657a] | 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(
 | 
|---|
| [bc899d6] | 352 |                 ast::vector<ast::TypeDecl> const & baseParams,
 | 
|---|
| [1c0657a] | 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,
 | 
|---|
| [251ce80] | 362 |                                 memberExpr->member->get_type() ) ) {
 | 
|---|
| [1c0657a] | 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;
 | 
|---|
| [1dafdfc] | 379 |                 // The original expression:
 | 
|---|
| [1c0657a] | 380 |                 //   p.x = &i;
 | 
|---|
| [1dafdfc] | 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:
 | 
|---|
| [1c0657a] | 387 |                 static UniqueName tmpNamer( "_dtype_static_member_" );
 | 
|---|
 | 388 |                 ast::ObjectDecl * tmp = new ast::ObjectDecl( location,
 | 
|---|
 | 389 |                         tmpNamer.newName(),
 | 
|---|
 | 390 |                         new ast::ReferenceType( concType ),
 | 
|---|
| [1dafdfc] | 391 |                         nullptr,
 | 
|---|
| [1c0657a] | 392 |                         ast::Storage::Classes(),
 | 
|---|
 | 393 |                         ast::Linkage::C
 | 
|---|
 | 394 |                 );
 | 
|---|
 | 395 |                 stmtsToAddBefore.push_back( new ast::DeclStmt( location, tmp ) );
 | 
|---|
| [1dafdfc] | 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 |                 );
 | 
|---|
| [1c0657a] | 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 :
 | 
|---|
| [01865fb] | 421 |                 public ast::WithCodeLocation,
 | 
|---|
| [1c0657a] | 422 |                 public ast::WithConstTypeSubstitution,
 | 
|---|
| [01865fb] | 423 |                 public ast::WithDeclsToAdd<>,
 | 
|---|
 | 424 |                 public ast::WithGuards,
 | 
|---|
 | 425 |                 public ast::WithVisitorRef<GenericInstantiator>
 | 
|---|
 | 426 | {
 | 
|---|
| [1c0657a] | 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 );
 | 
|---|
| [1ee0a4da] | 451 |         ast::Designation const * postvisit( ast::Designation const * );
 | 
|---|
| [1c0657a] | 452 | 
 | 
|---|
| [1ee0a4da] | 453 |         void previsit( ast::ParseNode const * node ) {
 | 
|---|
 | 454 |                 GuardValue( location ) = &node->location;
 | 
|---|
 | 455 |         }
 | 
|---|
| [1c0657a] | 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 | 
 | 
|---|
| [bc899d6] | 479 |         void replaceParametersWithConcrete( ast::vector<ast::Expr> & params );
 | 
|---|
| [1c0657a] | 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,
 | 
|---|
| [bc899d6] | 488 |                 ast::vector<ast::TypeDecl> & baseParams,
 | 
|---|
 | 489 |                 ast::vector<ast::TypeExpr> const & typeSubs );
 | 
|---|
| [1c0657a] | 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." );
 | 
|---|
| [bc899d6] | 528 |         ast::vector<ast::TypeExpr> typeSubs;
 | 
|---|
| [1c0657a] | 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 );
 | 
|---|
| [8f1e035] | 559 |                         if ( AggrDecl const * forwardDecl = ast::asForward( newDecl ) ) {
 | 
|---|
| [1c0657a] | 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();
 | 
|---|
| [bc899d6] | 587 |                 ast::vector<ast::Decl> const & members = aggr->members;
 | 
|---|
| [1c0657a] | 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 | 
 | 
|---|
| [1ee0a4da] | 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;
 | 
|---|
| [1c0657a] | 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(
 | 
|---|
| [bc899d6] | 683 |                 ast::vector<ast::Expr> & params ) {
 | 
|---|
| [1c0657a] | 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,
 | 
|---|
| [bc899d6] | 713 |                 ast::vector<ast::TypeDecl> & baseParams,
 | 
|---|
 | 714 |                 ast::vector<ast::TypeExpr> const & typeSubs ) {
 | 
|---|
| [1c0657a] | 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: //
 | 
|---|