source: src/GenPoly/InstantiateGeneric.cpp

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

Change to instantiateGeneric, removing some unneeded output. It isn't much more complex but it is and could be reverted need be. Fixes #199.

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