source: src/GenPoly/InstantiateGenericNew.cpp@ cf34e82

Last change on this file since cf34e82 was 1ee0a4da, checked in by Andrew Beach <ajbeach@…>, 2 years ago

Translated the box pass to the new AST. This includes direct as possible translations of the existing passes are two fix in passes which correct AST problems the direct translation causes. Outside the box pass there have already been many changes, ad there is another in Instantiate Generics, which disconnects designators instead of leaving them connected to the original polymorphic type, which breaks the invarants once the fields are removed in the Eraser sub-pass. There was also a change that was made and un-made in one commit. If translate from the new-AST to the old-AST part way you must, where possible, sort the TypeEnvKey values by string comparison. However, it now passes over that so it would be just extra complexity and run time, so I removed it. I stand at the exit from a great woods, just shy of a year from when I entered it. It has been a difficult and tiring journey. The path has been long and at times comically winding; but most often it was invisible, hidden under an impenetrable canopy and I spend days looking for it. All for a short jog forward before getting lost again. In front of me is another woods. It looks smaller, but I can't see the other side. Anyways, time to keep walking.

  • Property mode set to 100644
File size: 24.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 ( auto inst = type.as<ast::StructInstType>() ) {
338 if ( !inst->params.empty() ) return fixMemberExpr( inst, expr );
339 } else if ( auto inst = type.as<ast::UnionInstType>() ) {
340 if ( !inst->params.empty() ) return fixMemberExpr( inst, expr );
341 }
342 return expr;
343}
344
345template<typename Aggr>
346ast::Expr const * FixDtypeStatic::fixMemberExpr(
347 Aggr const * inst, ast::MemberExpr const * memberExpr ) {
348 return fixMemberExpr( inst->base->params, memberExpr );
349}
350
351ast::Expr const * FixDtypeStatic::fixMemberExpr(
352 ast::vector<ast::TypeDecl> const & baseParams,
353 ast::MemberExpr const * memberExpr ) {
354 // Need to cast dtype-static member expressions to their actual type
355 // before the actual type type is erased.
356 // NOTE: The casts here have the third argument (isGenerated) set to
357 // ExplicitCast so that they casts persist until Box, where they are needed.
358
359 if ( !isDtypeStatic( baseParams ) ||
360 ResolvExpr::typesCompatible(
361 memberExpr->result,
362 memberExpr->member->get_type() ) ) {
363 return memberExpr;
364 }
365
366 // Type of member and type of expression differ.
367 ast::Type const * concType = ast::deepCopy( memberExpr->result );
368 CodeLocation const & location = memberExpr->location;
369 if ( isLValueArg ) {
370 // The result must be a C lvalue expression. So make a new reference
371 // variable with the correct actual type to replace the
372 // member expression.
373 // forall(T &)
374 // struct Ptr {
375 // T * x;
376 // };
377 // Ptr(int) p;
378 // int i;
379 // The original expression:
380 // p.x = &i;
381 // Becomes the expression/declaration:
382 // int *& _dtype_static_member_0;
383 // (_dtype_static_member_0 = (int**)&p.x,
384 // _dtype_static_member_0) = &i;
385
386 // The declaration is simple:
387 static UniqueName tmpNamer( "_dtype_static_member_" );
388 ast::ObjectDecl * tmp = new ast::ObjectDecl( location,
389 tmpNamer.newName(),
390 new ast::ReferenceType( concType ),
391 nullptr,
392 ast::Storage::Classes(),
393 ast::Linkage::C
394 );
395 stmtsToAddBefore.push_back( new ast::DeclStmt( location, tmp ) );
396
397 // The expression is more complex, uses references and reference /
398 // pointer parity. But breaking it up risks reordering.
399 return new ast::CommaExpr( location,
400 ast::UntypedExpr::createAssign( location,
401 new ast::VariableExpr( location, tmp ),
402 new ast::CastExpr( location,
403 new ast::AddressExpr( location, memberExpr ),
404 new ast::PointerType( ast::deepCopy( concType ) ),
405 ast::ExplicitCast
406 )
407 ),
408 new ast::VariableExpr( location, tmp )
409 );
410 } else {
411 // Here, it can simply add a cast to actual types.
412 return new ast::CastExpr( location,
413 memberExpr,
414 concType,
415 ast::ExplicitCast
416 );
417 }
418}
419
420struct GenericInstantiator final :
421 public ast::WithCodeLocation,
422 public ast::WithConstTypeSubstitution,
423 public ast::WithDeclsToAdd<>,
424 public ast::WithGuards,
425 public ast::WithVisitorRef<GenericInstantiator>
426{
427 /// Map of (generic type, parameter list) pairs
428 /// to concrete type instantiations.
429 InstantiationMap instantiations;
430 /// Set of types which are dtype-only generic
431 /// (and therefore have static layout).
432 std::set<ast::AggregateDecl const *> dtypeStatics;
433 /// Namer for concrete types.
434 UniqueName typeNamer;
435 /// Should not make use of type environment to replace types of function
436 /// parameter and return values.
437 bool inFunctionType = false;
438 /// Index of current member, used to recreate MemberExprs with the
439 /// member from an instantiation.
440 int memberIndex = -1;
441
442 GenericInstantiator() :
443 instantiations(), dtypeStatics(), typeNamer("_conc_") {}
444
445 ast::Type const * postvisit( ast::StructInstType const * inst );
446 ast::Type const * postvisit( ast::UnionInstType const * inst );
447
448 void previsit( ast::MemberExpr const * expr );
449 ast::Expr const * postvisit( ast::MemberExpr const * expr );
450 ast::Expr const * postvisit( ast::Expr const * expr );
451 ast::Designation const * postvisit( ast::Designation const * );
452
453 void previsit( ast::ParseNode const * node ) {
454 GuardValue( location ) = &node->location;
455 }
456 void previsit( ast::FunctionType const * ) {
457 GuardValue( inFunctionType ) = true;
458 }
459 void beginScope() {
460 instantiations.beginScope();
461 }
462 void endScope() {
463 instantiations.endScope();
464 }
465private:
466 /// Wrap instantiation lookup for structures.
467 ast::StructDecl const * lookup(
468 ast::StructInstType const * inst, type_vector const & typeSubs ) const;
469 /// Wrap instantiation lookup for unions.
470 ast::UnionDecl const * lookup(
471 ast::UnionInstType const * inst, type_vector const & typeSubs ) const;
472 /// Wrap instantiation insertion for structures.
473 void insert( ast::StructInstType const * inst,
474 type_vector const & typeSubs, ast::StructDecl const * decl );
475 /// Wrap instantiation insertion for unions.
476 void insert( ast::UnionInstType const * inst,
477 type_vector const & typeSubs, ast::UnionDecl const * decl );
478
479 void replaceParametersWithConcrete( ast::vector<ast::Expr> & params );
480 ast::Type const * replaceWithConcrete( ast::Type const * type, bool doClone );
481
482 template<typename AggrDecl>
483 ast::Type const * fixInstType( ast::SueInstType<AggrDecl> const * inst );
484
485 /// Strips a dtype-static aggregate decl of its type parameters,
486 /// marks it as stripped.
487 void stripDtypeParams( ast::AggregateDecl * base,
488 ast::vector<ast::TypeDecl> & baseParams,
489 ast::vector<ast::TypeExpr> const & typeSubs );
490};
491
492ast::Type const * GenericInstantiator::postvisit(
493 ast::StructInstType const * inst ) {
494 return fixInstType( inst );
495}
496
497ast::Type const * GenericInstantiator::postvisit(
498 ast::UnionInstType const * inst ) {
499 return fixInstType( inst );
500}
501
502template<typename AggrDecl>
503ast::Type const * GenericInstantiator::fixInstType(
504 ast::SueInstType<AggrDecl> const * inst ) {
505 assert( location );
506
507 // There is nothing to mutate if the params are empty.
508 if ( inst->params.empty() ) return inst;
509
510 // Need to replace type variables to ensure that generic types are
511 // instantiated for the return values of polymorphic functions (in
512 // particular, for thunks, because they are not [currently] copy
513 // constructed).
514 // (This used to be run only on structures, but I believe both need it.)
515 inst = strict_dynamic_cast<ast::SueInstType<AggrDecl> const *>(
516 replaceWithConcrete( inst, false ) );
517
518 // Check for an already-instantiatiated dtype-static type.
519 if ( dtypeStatics.find( inst->base ) != dtypeStatics.end() ) {
520 auto mutInst = ast::mutate( inst );
521 stripInstParams( mutInst );
522 return mutInst;
523 }
524
525 // Check if the type can be concretely instantiated;
526 // and put substitutions in typeSubs.
527 assertf( inst->base, "Base data-type has parameters." );
528 ast::vector<ast::TypeExpr> typeSubs;
529 GenericType gt = makeSubstitutions( typeSubs, inst->base->params, inst->params );
530 switch ( gt ) {
531 case GenericType::dtypeStatic:
532 {
533 auto mutInst = ast::mutate( inst );
534 assert( mutInst->base->unique() );
535 auto mutBase = mutInst->base.get_and_mutate();
536 stripDtypeParams( mutBase, mutBase->params, typeSubs );
537 stripInstParams( mutInst );
538 return mutInst;
539 }
540 case GenericType::concrete:
541 {
542 // Make concrete instantiation of generic type.
543 AggrDecl const * concDecl = lookup( inst, typeSubs );
544 if ( !concDecl ) {
545 // Set concDecl to new type, insert type declaration
546 // into statements to add.
547 AggrDecl * newDecl = new AggrDecl( *location,
548 typeNamer.newName( inst->name )
549 );
550 newDecl->body = inst->base->body;
551 newDecl->members = substituteMembers(
552 inst->base->members,
553 inst->base->params,
554 typeSubs
555 );
556
557 // Forward declare before recursion. (TODO: Only when needed, #199.)
558 insert( inst, typeSubs, newDecl );
559 if ( AggrDecl const * forwardDecl = ast::asForward( newDecl ) ) {
560 declsToAddBefore.push_back( forwardDecl );
561 }
562 // Recursively instantiate members:
563 concDecl = strict_dynamic_cast<AggrDecl const *>(
564 newDecl->accept( *visitor ) );
565 // Must occur before declaration is added so
566 // that member instantiation appear first.
567 declsToAddBefore.push_back( concDecl );
568 }
569 return new ast::SueInstType<AggrDecl>( concDecl, inst->qualifiers );
570 }
571 case GenericType::dynamic:
572 // Do nothing.
573 default:
574 // Should never happen.
575 return inst;
576 }
577}
578
579void GenericInstantiator::previsit( ast::MemberExpr const * expr ) {
580 GuardValue( location ) = &expr->location;
581 GuardValue( memberIndex ) = -1;
582 // Only run on expressions where the field being accessed is generic.
583 if ( isGenericType( expr->aggregate->result ) ) {
584 // Find the location of the member:
585 ast::AggregateDecl const * aggr =
586 expr->aggregate->result.strict_as<ast::BaseInstType>()->aggr();
587 ast::vector<ast::Decl> const & members = aggr->members;
588 auto it = std::find( members.begin(), members.end(), expr->member );
589 memberIndex = std::distance( members.begin(), it );
590 assertf( memberIndex < (int)members.size(), "Could not find member %s in generic type %s.", toString( expr->member ).c_str(), toString( expr->aggregate ).c_str() );
591 }
592}
593
594ast::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
622ast::Expr const * GenericInstantiator::postvisit( ast::Expr const * expr ) {
623 // We are not modifying env on MemberExpr, but that seems to work.
624 if ( expr->env ) {
625 auto newEnv = expr->env->accept( *visitor );
626 expr = ast::mutate_field( expr, &ast::Expr::env, newEnv );
627 }
628 return expr;
629}
630
631// This attempts to figure out what the final name of the field will be.
632// Pretty printing can cause this to become incorrect.
633std::string getPrintName( ast::DeclWithType const * decl ) {
634 return ( decl->linkage.is_mangled )
635 ? decl->scopedMangleName() : decl->name;
636}
637
638ast::Designation const * GenericInstantiator::postvisit(
639 ast::Designation const * designation ) {
640 // Disconnect designator names from their fields.
641 // It is now incorrect to point at the generic definition where the used
642 // type now is replaced with a concrete instance. Ideally, new variable
643 // expressions would point at fields in the concrete instances, but that
644 // is work and that information should not be needed this late in
645 // compilation.
646
647 // Modify all designations, even if not needed.
648 auto mutNode = mutate( designation );
649 for ( ast::ptr<ast::Expr> & designator : mutNode->designators ) {
650 if ( auto var = designator.as<ast::VariableExpr>() ) {
651 designator = new ast::NameExpr(
652 var->location, getPrintName( var->var ) );
653 }
654 }
655 return mutNode;
656}
657
658ast::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
665ast::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
672void GenericInstantiator::insert( ast::StructInstType const * inst,
673 type_vector const & typeSubs, ast::StructDecl const * decl ) {
674 instantiations.insert( inst->base, typeSubs, decl );
675}
676
677void GenericInstantiator::insert( ast::UnionInstType const * inst,
678 type_vector const & typeSubs, ast::UnionDecl const * decl ) {
679 instantiations.insert( inst->base, typeSubs, decl );
680}
681
682void GenericInstantiator::replaceParametersWithConcrete(
683 ast::vector<ast::Expr> & params ) {
684 for ( ast::ptr<ast::Expr> & param : params ) {
685 auto paramType = param.as<ast::TypeExpr>();
686 assertf( paramType, "Aggregate parameters should be type expressions." );
687 auto type = replaceWithConcrete( paramType->type, false );
688 param = ast::mutate_field( paramType, &ast::TypeExpr::type, type );
689 }
690}
691
692ast::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
711void GenericInstantiator::stripDtypeParams(
712 ast::AggregateDecl * base,
713 ast::vector<ast::TypeDecl> & baseParams,
714 ast::vector<ast::TypeExpr> const & typeSubs ) {
715 substituteMembersHere( base->members, baseParams, typeSubs );
716
717 baseParams.clear();
718
719 dtypeStatics.insert( base );
720}
721
722} // namespace
723
724void 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: //
Note: See TracBrowser for help on using the repository browser.