source: src/GenPoly/InstantiateGeneric.cpp@ b1c220a

Last change on this file since b1c220a was a21aaff, checked in by Andrew Beach <ajbeach@…>, 6 months ago

Syncronized getPrintName with mangleName. Ideally there would be some common function to call but I'm not sure where it would go.

  • Property mode set to 100644
File size: 26.4 KB
Line 
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 : Wed Mar 12 15:18:00 2025
13// Update Count : 2
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
37namespace GenPoly {
38
39namespace {
40
41// Utilities:
42
43using type_vector = ast::vector< ast::TypeExpr >;
44
45/// Abstracts type equality for a list of parameter types.
46struct 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.
90class 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;
100public:
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.
141enum 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
150GenericType & operator|=( GenericType & gt, const GenericType & ht ) {
151 if ( gt < ht ) gt = ht;
152 return gt;
153}
154
155bool 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/// Get the scrubbed type of a declaration (see scrubTypeVars functions).
162ast::TypeExpr const * scrubTypeDecl(
163 CodeLocation const & location, ast::TypeDecl const * typeDecl ) {
164 switch ( typeDecl->kind ) {
165 // Erase any incomplete dtype to `void` (`T *` -> `void *`).
166 case ast::TypeDecl::Dtype:
167 return new ast::TypeExpr( location, new ast::VoidType() );
168 // Erase any ftype to `void (*)(void)`.
169 case ast::TypeDecl::Ftype:
170 return new ast::TypeExpr( location, new ast::FunctionType() );
171 // Remaining cases are not supported.
172 case ast::TypeDecl::Ttype:
173 assertf( false, "Ttype parameters are not currently allowed as parameters to generic types." );
174 break;
175 default:
176 assertf( false, "Unhandled type parameter kind" );
177 break;
178 }
179}
180
181/// Makes substitutions of params into baseParams; returns dtypeStatic if
182/// there is a concrete instantiation based only on {d,f}type-to-void
183/// conversions, concrete if there is a concrete instantiation requiring at
184/// least one parameter type, and dynamic if there is no concrete instantiation.
185GenericType makeSubstitutions(
186 ast::vector<ast::TypeExpr> & out,
187 ast::vector<ast::TypeDecl> const & baseParams,
188 ast::vector<ast::Expr> const & params ) {
189 GenericType gt = GenericType::dtypeStatic;
190
191 // Substitute concrete types for given parameters,
192 // using incomplete types for placeholders.
193 auto baseParam = baseParams.begin();
194 auto param = params.begin();
195 for ( ; baseParam != baseParams.end() && param != params.end() ;
196 ++baseParam, ++param ) {
197 ast::TypeExpr const * paramExpr = param->as<ast::TypeExpr>();
198 assertf( paramExpr, "Aggregate parameters should be type expressions." );
199
200 if ( (*baseParam)->isComplete() ) {
201 // Substitute parameter for complete (otype or sized dtype) type.
202 if ( isPolyType( paramExpr->type ) ) {
203 // Substitute polymorphic parameter type in to generic type.
204 out.push_back( ast::deepCopy( paramExpr ) );
205 gt = GenericType::dynamic;
206 } else {
207 // Normalize possibly dtype-static parameter type.
208 out.emplace_back( new ast::TypeExpr( paramExpr->location,
209 scrubAllTypeVars( ast::deepCopy( paramExpr->type ) ) ) );
210 gt |= GenericType::concrete;
211 }
212 } else {
213 out.emplace_back( scrubTypeDecl( paramExpr->location, *baseParam ) );
214 }
215 }
216
217 assertf( baseParam == baseParams.end(), "Base Parameters not exausted." );
218 assertf( param == params.end(), "Type parameters not exausted." );
219 return gt;
220}
221
222/// Substitutes types of members according to baseParams => typeSubs,
223/// returning the result in a new vector.
224ast::vector<ast::Decl> substituteMembers(
225 ast::vector<ast::Decl> const & members,
226 ast::vector<ast::TypeDecl> const & baseParams,
227 ast::vector<ast::TypeExpr> const & typeSubs ) {
228 ast::vector<ast::Decl> out;
229 ast::TypeSubstitution subs( baseParams, typeSubs );
230 for ( ast::ptr<ast::Decl> const & member : members ) {
231 // Create a manual copy to avoid in-place mutation.
232 // If being a PureVisitor is decided to be part of apply's interface,
233 // then we can actually skip this step as it will never mutate in-
234 // place. (Then we don't need the extra guard to free temp value.)
235 ast::ptr<ast::Decl> copy = ast::deepCopy( member.get() );
236 auto result = subs.apply( copy.get() );
237 out.emplace_back( result.node );
238 }
239 return out;
240}
241
242/// Substitutes types of members according to baseParams => typeSubs,
243/// modifying them in-place.
244void substituteMembersHere(
245 ast::vector<ast::Decl> & members,
246 ast::vector<ast::TypeDecl> const & baseParams,
247 ast::vector<ast::TypeExpr> const & typeSubs ) {
248 ast::TypeSubstitution subs( baseParams, typeSubs );
249 for ( ast::ptr<ast::Decl> & member : members ) {
250 // The member must be mutated in place to avoid breaking
251 assert( member->unique() );
252
253 auto field = member.strict_as<ast::ObjectDecl>();
254 auto result = subs.apply( field->type.get() );
255 auto copy = ast::mutate_field(
256 field, &ast::ObjectDecl::type, result.node );
257
258 // I'm not kidding, it is very important.
259 assert( copy == member.get() );
260 }
261}
262
263/// Strips the instances' type parameters.
264void stripInstParams( ast::BaseInstType * inst ) {
265 inst->params.clear();
266}
267
268bool isGenericType( ast::Type const * type ) {
269 if ( auto inst = dynamic_cast<ast::StructInstType const *>( type ) ) {
270 return !inst->params.empty();
271 } else if ( auto inst = dynamic_cast<ast::UnionInstType const *>( type ) ) {
272 return !inst->params.empty();
273 } else {
274 return false;
275 }
276}
277
278// The Passes:
279
280struct FixDtypeStatic final :
281 public ast::WithGuards,
282 public ast::WithVisitorRef<FixDtypeStatic>,
283 public ast::WithShortCircuiting,
284 public ast::WithStmtsToAdd {
285 ast::ApplicationExpr const * previsit( ast::ApplicationExpr const * expr );
286 void previsit( ast::AddressExpr const * expr );
287
288 ast::Expr const * postvisit( ast::MemberExpr const * expr );
289private:
290 template<typename Aggr>
291 ast::Expr const * fixMemberExpr(
292 Aggr const * inst, ast::MemberExpr const * memberExpr );
293
294 ast::Expr const * fixMemberExpr(
295 ast::vector<ast::TypeDecl> const & baseParams,
296 ast::MemberExpr const * memberExpr );
297
298 bool isLValueArg = false;
299};
300
301ast::ApplicationExpr const * FixDtypeStatic::previsit(
302 ast::ApplicationExpr const * expr ) {
303 GuardValue( isLValueArg ) = false;
304 ast::Decl const * function = ast::getFunction( expr );
305 if ( ast::Linkage::Intrinsic != function->linkage
306 || !CodeGen::isAssignment( function->name ) ) {
307 return expr;
308 }
309
310 // Explicity visit children because only the first element must be a
311 // C lvalue (normally, it can only send info to both or neither).
312 visit_children = false;
313 expr = mutate_field( expr, &ast::ApplicationExpr::env,
314 maybe_accept( expr->env.get(), *visitor ) );
315 expr = mutate_field( expr, &ast::ApplicationExpr::result,
316 maybe_accept( expr->result.get(), *visitor ) );
317 expr = mutate_field( expr, &ast::ApplicationExpr::func,
318 maybe_accept( expr->func.get(), *visitor ) );
319 isLValueArg = true;
320 for ( unsigned i = 0; i < expr->args.size(); ++i ) {
321 ast::Expr const * newExpr = expr->args[i]->accept( *visitor );
322 // This is declared here for lifetime reasons.
323 ast::ptr<ast::CastExpr> cast;
324 if ( newExpr != expr->args[i].get() &&
325 (cast = dynamic_cast<ast::CastExpr const *>( newExpr )) ) {
326 newExpr = cast->arg.get();
327 }
328 expr = mutate_field_index( expr, &ast::ApplicationExpr::args,
329 i, newExpr );
330 isLValueArg = false;
331 }
332 return expr;
333}
334
335void FixDtypeStatic::previsit( ast::AddressExpr const * ) {
336 // The argument of an address expression (`&`) must be a C lvalue.
337 GuardValue( isLValueArg ) = true;
338}
339
340ast::Expr const * FixDtypeStatic::postvisit( ast::MemberExpr const * expr ) {
341 ast::ptr<ast::Type> const & type = expr->aggregate->result;
342 if ( auto inst = type.as<ast::StructInstType>() ) {
343 if ( !inst->params.empty() ) return fixMemberExpr( inst, expr );
344 } else if ( auto inst = type.as<ast::UnionInstType>() ) {
345 if ( !inst->params.empty() ) return fixMemberExpr( inst, expr );
346 }
347 return expr;
348}
349
350template<typename Aggr>
351ast::Expr const * FixDtypeStatic::fixMemberExpr(
352 Aggr const * inst, ast::MemberExpr const * memberExpr ) {
353 return fixMemberExpr( inst->base->params, memberExpr );
354}
355
356ast::Expr const * FixDtypeStatic::fixMemberExpr(
357 ast::vector<ast::TypeDecl> const & baseParams,
358 ast::MemberExpr const * memberExpr ) {
359 // Need to cast dtype-static member expressions to their actual type
360 // before the actual type type is erased.
361 // NOTE: The casts here have the third argument (isGenerated) set to
362 // ExplicitCast so that they casts persist until Box, where they are needed.
363
364 if ( !isDtypeStatic( baseParams ) ||
365 ResolvExpr::typesCompatible(
366 memberExpr->result,
367 memberExpr->member->get_type() ) ) {
368 return memberExpr;
369 }
370
371 // Type of member and type of expression differ.
372 ast::Type const * concType = ast::deepCopy( memberExpr->result );
373 CodeLocation const & location = memberExpr->location;
374 if ( isLValueArg ) {
375 // The result must be a C lvalue expression. So make a new reference
376 // variable with the correct actual type to replace the
377 // member expression.
378 // forall(T &)
379 // struct Ptr {
380 // T * x;
381 // };
382 // Ptr(int) p;
383 // int i;
384 // The original expression:
385 // p.x = &i;
386 // Becomes the expression/declaration:
387 // int *& _dtype_static_member_0;
388 // (_dtype_static_member_0 = (int**)&p.x,
389 // _dtype_static_member_0) = &i;
390
391 // The declaration is simple:
392 static UniqueName tmpNamer( "_dtype_static_member_" );
393 ast::ObjectDecl * tmp = new ast::ObjectDecl( location,
394 tmpNamer.newName(),
395 new ast::ReferenceType( concType ),
396 nullptr,
397 ast::Storage::Classes(),
398 ast::Linkage::C
399 );
400 stmtsToAddBefore.push_back( new ast::DeclStmt( location, tmp ) );
401
402 // The expression is more complex, uses references and reference /
403 // pointer parity. But breaking it up risks reordering.
404 return new ast::CommaExpr( location,
405 ast::UntypedExpr::createAssign( location,
406 new ast::VariableExpr( location, tmp ),
407 new ast::CastExpr( location,
408 new ast::AddressExpr( location, memberExpr ),
409 new ast::PointerType( ast::deepCopy( concType ) ),
410 ast::ExplicitCast
411 )
412 ),
413 new ast::VariableExpr( location, tmp )
414 );
415 } else {
416 // Here, it can simply add a cast to actual types.
417 return new ast::CastExpr( location,
418 memberExpr,
419 concType,
420 ast::ExplicitCast
421 );
422 }
423}
424
425struct GenericInstantiator final :
426 public ast::WithCodeLocation,
427 public ast::WithConstTypeSubstitution,
428 public ast::WithDeclsToAdd,
429 public ast::WithGuards,
430 public ast::WithVisitorRef<GenericInstantiator>
431{
432 /// Map of (generic type, parameter list) pairs
433 /// to concrete type instantiations.
434 InstantiationMap instantiations;
435 /// Set of types which are dtype-only generic
436 /// (and therefore have static layout).
437 std::set<ast::AggregateDecl const *> dtypeStatics;
438 /// Namer for concrete types.
439 UniqueName typeNamer;
440 /// Should not make use of type environment to replace types of function
441 /// parameter and return values.
442 bool inFunctionType = false;
443 /// Index of current member, used to recreate MemberExprs with the
444 /// member from an instantiation.
445 int memberIndex = -1;
446
447 GenericInstantiator() :
448 instantiations(), dtypeStatics(), typeNamer("_conc_") {}
449
450 ast::StructDecl const * previsit( ast::StructDecl const * );
451 ast::UnionDecl const * previsit( ast::UnionDecl const * );
452
453 ast::Type const * postvisit( ast::StructInstType const * inst );
454 ast::Type const * postvisit( ast::UnionInstType const * inst );
455
456 void previsit( ast::MemberExpr const * expr );
457 ast::Expr const * postvisit( ast::MemberExpr const * expr );
458 ast::Expr const * postvisit( ast::Expr const * expr );
459 ast::Designation const * postvisit( ast::Designation const * );
460
461 void previsit( ast::ParseNode const * node ) {
462 GuardValue( location ) = &node->location;
463 }
464 void previsit( ast::FunctionType const * ) {
465 GuardValue( inFunctionType ) = true;
466 }
467 void beginScope() {
468 instantiations.beginScope();
469 }
470 void endScope() {
471 instantiations.endScope();
472 }
473private:
474 /// Wrap instantiation lookup for structures.
475 ast::StructDecl const * lookup(
476 ast::StructInstType const * inst, type_vector const & typeSubs ) const;
477 /// Wrap instantiation lookup for unions.
478 ast::UnionDecl const * lookup(
479 ast::UnionInstType const * inst, type_vector const & typeSubs ) const;
480 /// Wrap instantiation insertion for structures.
481 void insert( ast::StructInstType const * inst,
482 type_vector const & typeSubs, ast::StructDecl const * decl );
483 /// Wrap instantiation insertion for unions.
484 void insert( ast::UnionInstType const * inst,
485 type_vector const & typeSubs, ast::UnionDecl const * decl );
486
487 void replaceParametersWithConcrete( ast::vector<ast::Expr> & params );
488 ast::Type const * replaceWithConcrete( ast::Type const * type, bool doClone );
489
490 template<typename AggrDecl>
491 AggrDecl const * fixAggrDecl( AggrDecl const * decl );
492
493 template<typename AggrDecl>
494 ast::Type const * fixInstType( ast::SueInstType<AggrDecl> const * inst );
495
496 /// Strips a dtype-static aggregate decl of its type parameters,
497 /// marks it as stripped.
498 void stripDtypeParams( ast::AggregateDecl * base,
499 ast::vector<ast::TypeDecl> & baseParams,
500 ast::vector<ast::TypeExpr> const & typeSubs );
501};
502
503ast::StructDecl const * GenericInstantiator::previsit( ast::StructDecl const * decl ) {
504 return fixAggrDecl( decl );
505}
506
507ast::UnionDecl const * GenericInstantiator::previsit( ast::UnionDecl const * decl ) {
508 return fixAggrDecl( decl );
509}
510
511template<typename AggrDecl>
512AggrDecl const * GenericInstantiator::fixAggrDecl( AggrDecl const * decl ) {
513 // This function and stripDtypeParams handle declarations before their
514 // first use (required to be in the previsit for types with a self use).
515 if ( decl->params.empty() || !isDtypeStatic( decl->params ) ) {
516 return decl;
517 }
518
519 ast::vector<ast::TypeExpr> typeSubs;
520 for ( auto const & param : decl->params ) {
521 assert( !param->isComplete() );
522 typeSubs.emplace_back( scrubTypeDecl( param->location, param ) );
523 }
524
525 assert( decl->unique() );
526 auto mutDecl = ast::mutate( decl );
527 stripDtypeParams( mutDecl, mutDecl->params, typeSubs );
528
529 return mutDecl;
530}
531
532ast::Type const * GenericInstantiator::postvisit(
533 ast::StructInstType const * inst ) {
534 return fixInstType( inst );
535}
536
537ast::Type const * GenericInstantiator::postvisit(
538 ast::UnionInstType const * inst ) {
539 return fixInstType( inst );
540}
541
542template<typename AggrDecl>
543ast::Type const * GenericInstantiator::fixInstType(
544 ast::SueInstType<AggrDecl> const * inst ) {
545 assert( location );
546
547 // There is nothing to mutate if the params are empty.
548 if ( inst->params.empty() ) return inst;
549
550 // Need to replace type variables to ensure that generic types are
551 // instantiated for the return values of polymorphic functions (in
552 // particular, for thunks, because they are not [currently] copy
553 // constructed).
554 // (This used to be run only on structures, but I believe both need it.)
555 inst = strict_dynamic_cast<ast::SueInstType<AggrDecl> const *>(
556 replaceWithConcrete( inst, false ) );
557
558 // Check for an already-instantiatiated dtype-static type.
559 if ( dtypeStatics.find( inst->base ) != dtypeStatics.end() ) {
560 auto mutInst = ast::mutate( inst );
561 stripInstParams( mutInst );
562 return mutInst;
563 }
564
565 // Check if the type can be concretely instantiated;
566 // and put substitutions in typeSubs.
567 assertf( inst->base, "Base data-type has parameters." );
568 ast::vector<ast::TypeExpr> typeSubs;
569 GenericType gt = makeSubstitutions( typeSubs, inst->base->params, inst->params );
570 switch ( gt ) {
571 case GenericType::dtypeStatic:
572 {
573 // This call to stripDtypeParams is used when a forward declaration
574 // has allowed an instance to appear before the full declaration.
575 auto mutInst = ast::mutate( inst );
576 assert( mutInst->base->unique() );
577 auto mutBase = mutInst->base.get_and_mutate();
578 stripDtypeParams( mutBase, mutBase->params, typeSubs );
579 stripInstParams( mutInst );
580 return mutInst;
581 }
582 case GenericType::concrete:
583 {
584 // Make concrete instantiation of generic type.
585 AggrDecl const * concDecl = lookup( inst, typeSubs );
586 if ( !concDecl ) {
587 // Set concDecl to new type, insert type declaration
588 // into statements to add.
589 AggrDecl * newDecl = new AggrDecl( *location,
590 typeNamer.newName( inst->name )
591 );
592 newDecl->body = inst->base->body;
593 newDecl->members = substituteMembers(
594 inst->base->members,
595 inst->base->params,
596 typeSubs
597 );
598
599 // Forward declare before recursion. (TODO: Only when needed, #199.)
600 insert( inst, typeSubs, newDecl );
601 if ( AggrDecl const * forwardDecl = ast::asForward( newDecl ) ) {
602 declsToAddBefore.push_back( forwardDecl );
603 }
604 // Recursively instantiate members:
605 concDecl = strict_dynamic_cast<AggrDecl const *>(
606 newDecl->accept( *visitor ) );
607 // Must occur before declaration is added so
608 // that member instantiation appear first.
609 declsToAddBefore.push_back( concDecl );
610 }
611 return new ast::SueInstType<AggrDecl>( concDecl, inst->qualifiers );
612 }
613 case GenericType::dynamic:
614 // Do nothing.
615 default:
616 // Should never happen.
617 return inst;
618 }
619}
620
621void GenericInstantiator::previsit( ast::MemberExpr const * expr ) {
622 GuardValue( location ) = &expr->location;
623 GuardValue( memberIndex ) = -1;
624 // Only run on expressions where the field being accessed is generic.
625 if ( isGenericType( expr->aggregate->result ) ) {
626 // Find the location of the member:
627 ast::AggregateDecl const * aggr =
628 expr->aggregate->result.strict_as<ast::BaseInstType>()->aggr();
629 ast::vector<ast::Decl> const & members = aggr->members;
630 auto it = std::find( members.begin(), members.end(), expr->member );
631 memberIndex = std::distance( members.begin(), it );
632 assertf( memberIndex < (int)members.size(), "Could not find member %s in generic type %s.", toString( expr->member ).c_str(), toString( expr->aggregate ).c_str() );
633 }
634}
635
636ast::Expr const * GenericInstantiator::postvisit(
637 ast::MemberExpr const * expr ) {
638 if ( memberIndex == -1 ) {
639 return expr;
640 }
641
642 // Using the location from the generic type, find the member
643 // in the instantiation and rebuild the member expression.
644 ast::AggregateDecl const * aggr =
645 expr->aggregate->result.strict_as<ast::BaseInstType>()->aggr();
646 assertf( memberIndex < (int)aggr->members.size(), "Instantiation somehow has fewer members than the generic type." );
647 ast::Decl const * member = *std::next( aggr->members.begin(), memberIndex );
648 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() );
649 auto field = strict_dynamic_cast< ast::DeclWithType const * >( member );
650 ast::MemberExpr * ret = new ast::MemberExpr( expr->location,
651 field,
652 ast::deepCopy( expr->aggregate )
653 );
654 // For pointer decay:
655 ret->result = ResolvExpr::adjustExprType(
656 ret->result,
657 ast::TypeEnvironment(),
658 ast::SymbolTable()
659 );
660 ret->env = expr->env;
661 return ret;
662}
663
664ast::Expr const * GenericInstantiator::postvisit( ast::Expr const * expr ) {
665 // We are not modifying env on MemberExpr, but that seems to work.
666 if ( expr->env ) {
667 auto newEnv = expr->env->accept( *visitor );
668 expr = ast::mutate_field( expr, &ast::Expr::env, newEnv );
669 }
670 return expr;
671}
672
673// This attempts to figure out what the final name of the field will be.
674// Pretty printing can cause this to become incorrect.
675std::string getPrintName( ast::DeclWithType const * decl ) {
676 return ( decl->linkage.is_mangled && decl->mangleName != "" )
677 ? decl->scopedMangleName() : decl->name;
678}
679
680ast::Designation const * GenericInstantiator::postvisit(
681 ast::Designation const * designation ) {
682 // Disconnect designator names from their fields.
683 // It is now incorrect to point at the generic definition where the used
684 // type now is replaced with a concrete instance. Ideally, new variable
685 // expressions would point at fields in the concrete instances, but that
686 // is work and that information should not be needed this late in
687 // compilation.
688
689 // Modify all designations, even if not needed.
690 auto mutNode = mutate( designation );
691 for ( ast::ptr<ast::Expr> & designator : mutNode->designators ) {
692 if ( auto var = designator.as<ast::VariableExpr>() ) {
693 designator = new ast::NameExpr(
694 var->location, getPrintName( var->var ) );
695 }
696 }
697 return mutNode;
698}
699
700ast::StructDecl const * GenericInstantiator::lookup(
701 ast::StructInstType const * inst,
702 type_vector const & typeSubs ) const {
703 auto ret = instantiations.lookup( inst->base, typeSubs );
704 return strict_dynamic_cast<ast::StructDecl const *, nullptr>( ret );
705}
706
707ast::UnionDecl const * GenericInstantiator::lookup(
708 ast::UnionInstType const * inst,
709 type_vector const & typeSubs ) const {
710 auto ret = instantiations.lookup( inst->base, typeSubs );
711 return strict_dynamic_cast<ast::UnionDecl const *, nullptr>( ret );
712}
713
714void GenericInstantiator::insert( ast::StructInstType const * inst,
715 type_vector const & typeSubs, ast::StructDecl const * decl ) {
716 instantiations.insert( inst->base, typeSubs, decl );
717}
718
719void GenericInstantiator::insert( ast::UnionInstType const * inst,
720 type_vector const & typeSubs, ast::UnionDecl const * decl ) {
721 instantiations.insert( inst->base, typeSubs, decl );
722}
723
724void GenericInstantiator::replaceParametersWithConcrete(
725 ast::vector<ast::Expr> & params ) {
726 for ( ast::ptr<ast::Expr> & param : params ) {
727 auto paramType = param.as<ast::TypeExpr>();
728 assertf( paramType, "Aggregate parameters should be type expressions." );
729 auto type = replaceWithConcrete( paramType->type, false );
730 param = ast::mutate_field( paramType, &ast::TypeExpr::type, type );
731 }
732}
733
734ast::Type const * GenericInstantiator::replaceWithConcrete(
735 ast::Type const * type, bool doClone ) {
736 if ( auto inst = dynamic_cast<ast::TypeInstType const *>( type ) ) {
737 if ( typeSubs && !inFunctionType ) {
738 ast::Type const * concType = typeSubs->lookup( inst );
739 return ast::deepCopy( ( concType ) ? concType : inst );
740 }
741 } else if ( auto inst = dynamic_cast<ast::StructInstType const *>( type ) ) {
742 auto mut = ( doClone ) ? ast::deepCopy( inst ) : ast::mutate( inst );
743 replaceParametersWithConcrete( mut->params );
744 return mut;
745 } else if ( auto inst = dynamic_cast<ast::UnionInstType const *>( type ) ) {
746 auto mut = ( doClone ) ? ast::deepCopy( inst ) : ast::mutate( inst );
747 replaceParametersWithConcrete( mut->params );
748 return mut;
749 }
750 return type;
751}
752
753void GenericInstantiator::stripDtypeParams(
754 ast::AggregateDecl * base,
755 ast::vector<ast::TypeDecl> & baseParams,
756 ast::vector<ast::TypeExpr> const & typeSubs ) {
757 substituteMembersHere( base->members, baseParams, typeSubs );
758
759 baseParams.clear();
760
761 dtypeStatics.insert( base );
762}
763
764} // namespace
765
766void instantiateGeneric( ast::TranslationUnit & translationUnit ) {
767 ast::Pass<FixDtypeStatic>::run( translationUnit );
768 ast::Pass<GenericInstantiator>::run( translationUnit );
769}
770
771} // namespace GenPoly
772
773// Local Variables: //
774// tab-width: 4 //
775// mode: c++ //
776// compile-command: "make install" //
777// End: //
Note: See TracBrowser for help on using the repository browser.