source: src/GenPoly/InstantiateGenericNew.cpp @ 1ee0a4da

Last change on this file since 1ee0a4da was 1ee0a4da, checked in by Andrew Beach <ajbeach@…>, 9 months 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.