source: src/GenPoly/InstantiateGenericNew.cpp@ 8fd1b7c

ADT ast-experimental
Last change on this file since 8fd1b7c was 5bf3976, checked in by Andrew Beach <ajbeach@…>, 3 years ago

Header Clean-Up: Created new headers for new AST typeops and moved declarations.

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