~eda-qa/leaflang/cpp

« back to all changes in this revision

Viewing changes to src/lang/type_identifier.cpp

  • Committer: edA-qa mort-ora-y
  • Date: 2017-06-03 05:03:54 UTC
  • mfrom: (98.1.18 typefixes)
  • Revision ID: eda-qa@disemia.com-20170603050354-6hfg5huvq56zjs66
merging typefixes

Show diffs side-by-side

added added

removed removed

Lines of Context:
15
15
#include "util/debug.hpp"
16
16
#include "lang/dump.hpp"
17
17
 
18
 
#define PUSH_FUNCTION_SCOPE() \
19
 
        auto old_scope = push_function_scope(); \
20
 
        auto restore_scope = util::defer([&,this]{ \
21
 
                pop_function_scope(old_scope); \
22
 
        });
23
 
 
24
 
 
25
18
namespace leaf {
26
 
 
27
 
type_identifier::resolve_t type_identifier::determine( shared_ptr<type_spec const> vt, unsigned flags ) {
28
 
        if( !vt )
29
 
                return cerr::null_spec;
30
 
        return determine( *vt, flags );
31
 
}
32
 
 
33
 
cerr_base type_identifier::expand_into( type_spec & to, type_spec const & from,
34
 
        param_map_t const & params, unsigned flags ) {
35
 
        
36
 
        //special allowance to merge value-list into signature parameters
37
 
        if( from.get_any_fun_class() == intr_type::f_value_list &&
38
 
                to.get_any_fun_class() == intr_type::f_function ) {
39
 
                auto fp = make_shared<type_spec>();
40
 
                fp->set<pt_fun_class>(intr_type::f_function);
41
 
                fp->push_sub( make_shared<type_spec>(from) );
42
 
                //DEBUG("param->signature");
43
 
                return expand_into( to, *fp, params, flags );
44
 
        }
45
 
                
46
 
#if SHOW_DEBUG
47
 
        //DEBUG( "EXPAND_INTO", &to, dump::get(to),  dump::get( from ) );
48
 
        //for( auto & mt : params ) {
49
 
                //DEBUG( "MT", mt.first, dump::get( mt.second ) );
50
 
        //}
51
 
#endif
52
 
        
53
 
        for( auto & from_part : from.get_parts() ) {
54
 
                auto copy_params = [&]( type_spec::part & to_part ) -> cerr {
55
 
                        
56
 
                        for( size_t i=0; i < from_part.sub.size(); ++i ) {
57
 
                                //the parameter symbols must be resolved in our namespace
58
 
                                auto pex = expand( *from_part.sub[i], params );
59
 
                                if( !pex.okay() ) {
60
 
                                        return pex.error;
61
 
                                }
62
 
                                to_part.sub.push_back( pex.result );
63
 
                        }
64
 
                        return cerr::okay;
65
 
                };
66
 
                
67
 
                auto merge_params = [&]( type_spec::part & to_part ) -> cerr {
68
 
                        
69
 
                        for( size_t i=0; i < from_part.sub.size(); ++i ) {
70
 
                                auto pex = expand( *from_part.sub[i], params );
71
 
                                if( !pex.okay() ) {
72
 
                                        return pex.error;
73
 
                                }
74
 
                                if( i >= to_part.sub.size() ) {
75
 
                                        to_part.sub.push_back( pex.result );
76
 
                                } else {
77
 
                                        auto q = make_shared<type_spec>(*to_part.sub[i]);
78
 
                                        auto rex = expand_into( *q, *pex.result, params, flags );
79
 
                                        if( !rex.okay() ) {
80
 
                                                return rex.error;
81
 
                                        }
82
 
                                        to_part.sub[i] = q;
83
 
                                }
84
 
                        }
85
 
                        
86
 
                        return cerr::okay;
87
 
                };
88
 
                
89
 
                auto merge = [&]( type_spec const & other ) -> cerr_base {
90
 
                        if( from_part.sub.size() != other.params.size() ) {
91
 
                                return cerr::mismatch_params;
92
 
                        }
93
 
                        
94
 
                        param_map_t pm;
95
 
                        for( size_t i=0; i < other.params.size(); ++i ) {
96
 
                                //the parameter symbols must be resolved in our namespace
97
 
                                auto pex = expand( *from_part.sub[i], params );
98
 
                                if( !pex.okay() ) {
99
 
                                        return pex.error;
100
 
                                }
101
 
                                //DEBUG( "MAP", other.params[i].name, dump::get( pex.result ) );
102
 
                                pm[ other.params[i].name ] = type_ref::create_spec( *pex.result );
103
 
                        }
104
 
                        return expand_into( to, other, pm, flags );
105
 
                };
106
 
                
107
 
                auto merge_type_ref = [&]( type_ref tr ) -> cerr_base {
108
 
                        if( tr.is_spec() ) {
109
 
                                return merge( tr.spec() );
110
 
                        } else if( tr.is_extr() ) {
111
 
                                auto ts = get_spec( tr );
112
 
                                STATE_CHECK( ts.okay(), ts.explain_error() );
113
 
                                return merge( *ts.result );
114
 
                        }
115
 
                        STATE_FAIL( "unsupported-type-ref" );
116
 
                };
117
 
                
118
 
                if( is_singular_part_type( from_part.type ) ) {
119
 
                        auto hp = to.has_alternate_part( from_part.type );
120
 
                        if( hp ) {
121
 
                                if( !(from_part.value == to.get_part(*hp).value) )  {
122
 
                                        if( flags & (df_instantiate | df_single) ) { //TODO: shouldn't need df_instantiate, callers set df_single
123
 
                                                return cerr::redundant_spec;
124
 
                                        }
125
 
                                }
126
 
 
127
 
                                merge_params( to.get_part(*hp) );
128
 
                                continue;
129
 
                        }
130
 
                        auto & s = to.set_part( from_part.type, from_part.value );
131
 
                        auto c = copy_params( s );
132
 
                        if( c != cerr::okay ) {
133
 
                                return c;
134
 
                        }
135
 
                        continue;
136
 
                }
137
 
                
138
 
                if( from_part.type == pt_param ) {
139
 
                        auto name_ = boost::get<std::string>(&from_part.value);
140
 
                        STATE_CHECK( name_ );
141
 
                        auto pit = params.find( *name_ );
142
 
                        if( pit == params.end() ) {
143
 
                                //not mapped at this level so just copy across
144
 
                                auto s = to.push_part<pt_param>(*name_);
145
 
                                auto c = copy_params( s );
146
 
                                if( c != cerr::okay ) {
147
 
                                        return c;
148
 
                                }
149
 
                        } else {
150
 
                                auto c = merge_type_ref( pit->second );
151
 
                                if( !c.okay() ) {
152
 
                                        return c;
153
 
                                }
154
 
                        }
155
 
                        continue;
156
 
                }
157
 
                
158
 
                STATE_CHECK( from_part.type == pt_symbol );
159
 
                
160
 
                auto name_parts = boost::get<type_spec_symbol>(&from_part.value);
161
 
                STATE_CHECK( name_parts);
162
 
                auto &name = name_parts->primary();
163
 
                
164
 
                
165
 
                //locally defined param names take precedence
166
 
                auto pt = params.find( name );
167
 
                if( pt != params.end() ) {
168
 
                        auto r = merge_type_ref( pt->second );
169
 
                        if( !r.okay() ) {
170
 
                                return r;
171
 
                        }
172
 
                        continue;
173
 
                }
174
 
                
175
 
                if( name == "type_infer" ) {
176
 
                        if( !from_part.expr ) {
177
 
                                return cerr::missing_expression;
178
 
                        }
179
 
                        //cannot modify source since it might be shared, such as in parametric functions
180
 
                        auto dup = from_part.expr->pre_clone(); 
181
 
                        //and a new scope to prevent captures from causing clashes (actually, the capturing to higher
182
 
                        //scopes must be blocked entirely somehow, otherwise this can have side-effects)
183
 
                        PUSH_FUNCTION_SCOPE();
184
 
 
185
 
                        DEBUG( "type_infer", dump::get(dup), dump::get(from_part.expr), dump::get(from_part.expr->type) );
186
 
                        auto pex = expression_typer::process_expression(dup, 
187
 
                                context(ctx.get_owner(),get_symbol_scope()));
188
 
                        if( pex->get_extant() < extant_level::resolved) {
189
 
                                //TODO: only if param type allowed do the merge
190
 
                                to.get_parts().push_back(from_part);
191
 
                                continue;
192
 
                                //return cerr::unknown_identifier;
193
 
                        }
194
 
                        auto ptype = pex->type.extr().if_cast<intr_type_value_list>();
195
 
                        if( !ptype || ptype->sub.size() != 1 ) {
196
 
                                return cerr::invalid_expression;
197
 
                        }
198
 
                        auto as = get_spec( ptype->sub[0].type );
199
 
                        STATE_CHECK( as.okay(), as.explain_error() );
200
 
                        apply_infer( *as.result );
201
 
                        auto c = merge(*as.result);
202
 
                        if( !c.okay() ) {
203
 
                                return c;
204
 
                        }
205
 
                        DEBUG( "end_type_infer" );
206
 
                        continue;
207
 
                }
208
 
                
209
 
                auto symbol = get_symbol_scope()->resolve_symbol( name );
210
 
                if( !symbol.okay() ) {
211
 
                        return cerr_base( symbol.error, name );
212
 
                }
213
 
                
214
 
                if( symbol.result.what == scope_symbol::w_type_alias ) {
215
 
                        auto r = merge( *symbol.result.type_alias );
216
 
                        if( !r.okay() ) {
217
 
                                return r;
218
 
                        }
219
 
                        continue;
220
 
                }
221
 
                
222
 
                if( symbol.result.what == scope_symbol::w_fun_type ) {
223
 
                        if( to.has<pt_fun_class>() ) {
224
 
                                return cerr::redundant_fundamental;
225
 
                        }
226
 
                        
227
 
                        auto & s = to.set<pt_fun_prototype>( symbol.result.fun_type );
228
 
                        copy_params( s );
229
 
                        continue;
230
 
                }
231
 
                
232
 
                return cerr_base( cerr::invalid_symbol_type, name );
233
 
        }
234
 
        
235
 
        if( from.sub.size() && from.get_any_fun_class() == to.get_any_fun_class() ) { 
236
 
                DEBUG("IdentFunction");
237
 
                //create a new scope to allow subsequence params/returns to reference previous ones
238
 
                PUSH_FUNCTION_SCOPE();
239
 
        
240
 
                for( size_t i=0; i < from.sub.size(); ++i ) {
241
 
                        auto r = expand( *from.sub[i].type, params );
242
 
                        if( !r.okay() ) {
243
 
                                return r.error;
244
 
                        }
245
 
                        
246
 
                        if( i < to.sub.size() ) {
247
 
                                if( to.sub[i].type ) {
248
 
                                        auto tc = make_shared<type_spec>( *to.sub[i].type );
249
 
                                        auto mr = expand_into( *tc, *r.result, params, flags );
250
 
                                        if( !mr.okay() ){
251
 
                                                return mr;
252
 
                                        }
253
 
                                        to.sub[i].type = tc;
254
 
                                } else {
255
 
                                        to.sub[i].type = r.result;
256
 
                                }
257
 
                                
258
 
                                if( to.sub[i].name.empty() ) {
259
 
                                        to.sub[i].name = from.sub[i].name;
260
 
                                }
261
 
                        } else {
262
 
                                to.push_sub( from.sub[i].name, r.result );
263
 
                        }
264
 
                        
265
 
                        if( to.sub[i].name.size() && symbol_scope ) {
266
 
                                auto sd = declaration::create();
267
 
                                sd->symbol = to.sub[i].name;
268
 
                                sd->spec_type = r.result;
269
 
                                sd->auto_resolve = true;
270
 
                                DEBUG( "ADD-A", sd->symbol );
271
 
                                symbol_scope->add(sd);
272
 
                        }
273
 
                }
274
 
                DEBUG("EndIdentFunction");
275
 
        }
276
 
        
277
 
        //DEBUG( "=>", &to, dump::get(to) );
278
 
        return cerr::okay;
279
 
}
280
 
 
281
 
type_identifier::resolve_spec_t type_identifier::expand( type_spec const & vt ) {
282
 
 
283
 
        //DEBUG( "EXPAND", dump::get( vt ) );
284
 
        //replace these with their appropriate placeholders (just retains the notation)
285
 
        param_map_t retain;
286
 
        for( auto & p : vt.params ) {
287
 
                type_spec ts;
288
 
                ts.push_part<pt_param>( p.name );
289
 
                retain[p.name] = type_ref::create_spec(ts); //TODO: p.type constraints?
290
 
        }
291
 
        
292
 
        auto r = expand( vt, retain );
293
 
        if( r.okay() ) {
294
 
                r.result->params = vt.params;
295
 
        }
296
 
        return r;
297
 
}
298
 
 
299
 
type_identifier::resolve_spec_t type_identifier::expand( type_spec const & from, 
300
 
        param_map_t const & params, unsigned flags ) {
301
 
        
302
 
        auto to = make_shared<type_spec>();
303
 
        auto r = expand_into( *to, from, params, flags | df_single );
304
 
        if( !r.okay() ) {
305
 
                return resolve_spec_t(r);
306
 
        }
307
 
 
308
 
        //DEBUG( "EXPAND-OUT", dump::get( *to ) );
309
 
        return to;
310
 
}
311
 
 
312
 
type_identifier::resolve_t type_identifier::determine( type_spec const & vt_, unsigned flags ) {
313
 
        //DEBUG( "DETERMINE", dump::get( vt_ ) );
314
 
        auto ex = expand( vt_ );
315
 
        if( !ex.okay() ) {
316
 
                return resolve_t(ex);
317
 
        }
318
 
        type_spec const & vt = *ex.result;
319
 
                
320
 
        shared_ptr<intr_type const> cret = 
321
 
                vt.get<pt_fun_prototype>( shared_ptr<intr_type const>() ); //may be null
322
 
        
323
 
        //DEBUG( "CRET", dump::get( vt ), 
324
 
        //      cret && cret->contains_parametric(),
325
 
        //      flags);
326
 
 
327
 
        if( cret && cret->contains_parametric() ) {
328
 
                auto & p = vt.get_part( pt_fun_prototype );
329
 
                
330
 
                param_vector_t pt;
331
 
                for( size_t i = 0; i < p.sub.size(); ++i ) {
332
 
                        //this forces instantances to use fully defined extrinsics
333
 
                        auto c = determine( *p.sub[i], flags );
334
 
                        if( !c.okay() ) { 
335
 
                                return c;
336
 
                        }
337
 
                        if (!c.result.is_extr()) {
338
 
                                if( flags & df_allow_param ) {
339
 
                                        return type_ref::create_spec( vt );
340
 
                                }
341
 
                                return cerr::unresolved_param;
342
 
                        }
343
 
                        pt.push_back( c.result.extr() );
344
 
                }
345
 
                
346
 
                auto ir = instantiate( cret, pt );
347
 
                if(!ir.okay()) {
348
 
                        return resolve_t(ir);
349
 
                }
350
 
                //DEBUG( "PARAM-INST", dump::get(ir.result));
351
 
                cret = ir.result;
352
 
                
353
 
        } else if( !cret && vt.has<pt_param>()) {
354
 
                
355
 
                if( flags & df_allow_param ) {
356
 
                        return type_ref::create_spec( vt );
357
 
                }
358
 
                return cerr::unresolved_param;
359
 
                
360
 
        } else if( !cret ) {
361
 
                shared_ptr<intr_type> ret;
362
 
                
363
 
                auto fund = vt.get<pt_fun_class>( intr_type::f_invalid );
364
 
                switch( fund ) {
365
 
                                
366
 
                        case intr_type::f_boolean:
367
 
                                ret = make_shared<intr_type_boolean>();
368
 
                                break;
369
 
                                
370
 
                        case intr_type::f_char:
371
 
                                ret = make_shared<intr_type_char>();
372
 
                                break;
373
 
 
374
 
                        case intr_type::f_tuple: {
375
 
                                auto tt = make_shared<intr_type_tuple>();
376
 
                                if( vt.has<pt_pack>() )
377
 
                                        tt->pack = vt.get<pt_pack>();
378
 
                                if( vt.has<pt_selectable>() ) {
379
 
                                        tt->selectable = vt.get<pt_selectable>();
380
 
                                }
381
 
                                        
382
 
                                for( size_t i=0; i < vt.sub.size(); ++i ) {
383
 
                                        auto pt = determine( vt.sub[i].type, flags | df_sub_type );
384
 
                                        if( !pt.okay() )
385
 
                                                return pt;
386
 
                                        tt->push_sub( vt.sub[i].name, pt.result );
387
 
                                }
388
 
                                ret = tt;
389
 
                                break;
390
 
                        }
391
 
                        
392
 
                        case intr_type::f_value_list: {
393
 
                                //create a new scope to allow subsequence params/returns to reference previous ones
394
 
                                PUSH_FUNCTION_SCOPE();
395
 
                        
396
 
                                auto tt = make_shared<intr_type_value_list>();
397
 
                                for( size_t i=0; i < vt.sub.size(); ++i ) {
398
 
                                        auto pt = determine( vt.sub[i].type, flags ); //do not add df_sub_type here (it may already be applied however)
399
 
                                        if( !pt.okay() )
400
 
                                                return pt;
401
 
                                        tt->push_sub( vt.sub[i].name, pt.result );
402
 
                                        
403
 
                                        if( vt.sub[i].name.size() ) {
404
 
                                                auto sd = declaration::create();
405
 
                                                sd->symbol = vt.sub[i].name;
406
 
                                                sd->type = pt.result;
407
 
                                                //DEBUG( "ADD-B", sd->symbol );
408
 
                                                symbol_scope->add(sd);
409
 
                                        }
410
 
                                        
411
 
                                }
412
 
                                ret = tt;
413
 
                                break;
414
 
                        }
415
 
                        
416
 
                        case intr_type::f_function: {
417
 
                                auto ft = make_shared<intr_type_function>();
418
 
                                
419
 
                                bool immediate_member = (flags && df_imply_context) &&
420
 
                                        get_decl_scope()->is_class_root() && 
421
 
                                        vt.get<pt_member>(true) && !(flags & df_sub_type);
422
 
                                        
423
 
                                if( vt.has<pt_context>() ) {
424
 
                                        ft->context = extr_type(vt.get<pt_context>());
425
 
                                } else if( vt.has<pt_context_name>() ) {
426
 
                                        ft->access = intr_type_function::a_unbound;
427
 
                                        
428
 
                                        auto fctx = get_symbol_scope()->resolve_symbol( 
429
 
                                                vt.get<pt_context_name>() );
430
 
                                        if( !fctx.okay() ) {
431
 
                                                return resolve_t( fctx.error, vt.get<pt_context_name>() );
432
 
                                        }
433
 
                                        if( fctx.result.what != scope_symbol::w_fun_type
434
 
                                                || !fctx.result.fun_type->is<intr_type_custom>() ) {
435
 
                                                return cerr::invalid_context;
436
 
                                        }
437
 
                                        ft->context = extr_type(std::static_pointer_cast<intr_type_custom const>(fctx.result.fun_type));
438
 
                                } else if( immediate_member || vt.get<pt_member>(false) ) {
439
 
                                        ft->access = intr_type_function::a_unbound;
440
 
                                        ft->context = get_decl_scope()->get_class_scope_context();
441
 
                                }
442
 
                                
443
 
                                if( vt.has<pt_function_access>() ) {
444
 
                                        ft->access = vt.get<pt_function_access>();
445
 
                                }
446
 
                                
447
 
                                if( vt.has<pt_function_throw>() ) {
448
 
                                        ft->can_fail = vt.get<pt_function_throw>();
449
 
                                }
450
 
                                
451
 
                                if( vt.sub.size() != 1 && vt.sub.size() != 2 )
452
 
                                        return cerr::mismatch_size;
453
 
 
454
 
                                auto args = determine( vt.sub[0].type, flags | df_sub_type );
455
 
                                if( !args.okay() )
456
 
                                        return args;
457
 
                                if( !args.result.extr().is<intr_type_value_list>() )
458
 
                                        return cerr::requires_value_list;
459
 
                                ft->args = std::static_pointer_cast<intr_type_value_list const>(args.result.extr().intr);
460
 
                                
461
 
                                if( vt.sub.size() > 1 ) {
462
 
                                        auto returns = determine( vt.sub[1].type, flags | df_sub_type );
463
 
                                        //DEBUG( "RETURNS", dump::get(returns.result) );
464
 
                                        if( !returns.okay() )
465
 
                                                return returns;
466
 
                                        if( returns.result.is_spec() ) {
467
 
                                                //leave ft->returns as null
468
 
                                        } else {
469
 
                                                if( !returns.result.extr().is<intr_type_value_list>() )
470
 
                                                        return cerr::requires_value_list;
471
 
                                                ft->returns = std::static_pointer_cast<intr_type_value_list const>(returns.result.extr().intr);
472
 
                                        }
473
 
                                }
474
 
                                
475
 
                                ret = ft;
476
 
                                break;
477
 
                        }
478
 
                        
479
 
                        case intr_type::f_array: {
480
 
                                auto & p = vt.get_part(pt_fun_class);
481
 
                                if( p.sub.size() != 1 )
482
 
                                        return cerr::mismatch_size;
483
 
                                auto at = make_shared<intr_type_array>();
484
 
                                if( vt.has<pt_function_access>() && vt.get<pt_function_access>() == intr_type_function::a_raw ) {
485
 
                                        at->raw = true;
486
 
                                }
487
 
                                auto rt = determine( p.sub[0], flags | df_sub_type );
488
 
                                if( !rt.okay() ) {
489
 
                                        return rt;
490
 
                                }
491
 
                                if( !rt.result.is_extr() ) {
492
 
                                        if( flags & df_allow_param ) {
493
 
                                                return type_ref::create_spec( vt );
494
 
                                        }
495
 
                                        return cerr::unresolved_param;
496
 
                                }
497
 
                                
498
 
                                at->sub = rt.result.extr();
499
 
                                ret = at;
500
 
                                break;
501
 
                        }
502
 
                        
503
 
                        //TODO: shares a lot with f_array (both intr_type_wrap)
504
 
                        case intr_type::f_type: {
505
 
                                auto & p = vt.get_part(pt_fun_class);
506
 
                                if( p.sub.size() != 1 )
507
 
                                        return cerr::mismatch_size;
508
 
                                auto at = make_shared<intr_type_type>();
509
 
                                auto rt = determine( p.sub[0], flags | df_sub_type );
510
 
                                if( !rt.okay() ) {
511
 
                                        return rt;
512
 
                                }
513
 
                                if( !rt.result.is_extr() ) {
514
 
                                        if( flags & df_allow_param ) {
515
 
                                                return type_ref::create_spec( vt );
516
 
                                        }
517
 
                                        return cerr::unresolved_param;
518
 
                                }
519
 
                                
520
 
                                at->sub = rt.result.extr();
521
 
                                ret = at;
522
 
                                break;
523
 
                        }
524
 
                        
525
 
                        case intr_type::f_contextual: {
526
 
                                auto & p = vt.get_part(pt_fun_class);
527
 
                                if( p.sub.size() != 2 ) {
528
 
                                        return cerr::mismatch_size;
529
 
                                }
530
 
                                
531
 
                                auto ct = make_shared<intr_type_contextual>();
532
 
                                auto rt = determine( p.sub[0], flags | df_sub_type );
533
 
                                if( !rt.okay() ) {
534
 
                                        return rt;
535
 
                                }
536
 
                                ct->get_context() = rt.result;
537
 
                                
538
 
                                rt = determine( p.sub[1], flags | df_sub_type );
539
 
                                if( !rt.okay() ) {
540
 
                                        return rt;
541
 
                                }
542
 
                                ct->get_unbound() = rt.result;
543
 
                                
544
 
                                ret = ct;
545
 
                                break;
546
 
                        }
547
 
 
548
 
                        case intr_type::f_integer:
549
 
                        case intr_type::f_binary: {
550
 
                                shared_ptr<intr_type_fixed_number> it;
551
 
                                if( fund == intr_type::f_integer )
552
 
                                        it = make_shared<intr_type_integer>();
553
 
                                else
554
 
                                        it = make_shared<intr_type_binary>();
555
 
                                        
556
 
                                if( vt.has<pt_data_bitsize>() ) {
557
 
                                        it->data_bitsize = vt.get<pt_data_bitsize>();
558
 
                                } else {
559
 
                                        it->data_bitsize = platform::natural_integer_size;
560
 
                                }
561
 
                                ret = it;
562
 
                                break;
563
 
                        }
564
 
                        
565
 
                        case intr_type::f_float: {
566
 
                                auto ft = make_shared<intr_type_float>();
567
 
                                if( vt.has<pt_data_bitsize>() ) {
568
 
                                        if( vt.has<pt_precision_variant>() ) {
569
 
                                                return cerr::redundant_bitsize;
570
 
                                        }
571
 
                                        ft->data_bitsize = vt.get<pt_data_bitsize>();
572
 
                                        if( !platform::if_get_float( ft->data_bitsize ) )
573
 
                                                return cerr::unknown_variant;
574
 
                                } else if( vt.has<pt_precision_variant>() ) {
575
 
                                        auto nf = platform::if_get_float_precision( vt.get<pt_precision_variant>() );
576
 
                                        if( !nf )
577
 
                                                return cerr::unknown_variant;
578
 
                                        ft->data_bitsize = nf->size;
579
 
                                } else {
580
 
                                        ft->data_bitsize = platform::natural_float_size;
581
 
                                }
582
 
                                ret = ft;
583
 
                                break;
584
 
                        }
585
 
                        
586
 
                        case intr_type::f_rational: {
587
 
                                auto rt = make_shared<intr_type_rational>();
588
 
                                if( vt.has<pt_data_bitsize>() )
589
 
                                        rt->integer_bitsize = vt.get<pt_data_bitsize>();
590
 
                                        
591
 
                                auto signed_ = vt.if_get<pt_signed>();
592
 
                                if( signed_ ) {
593
 
                                        rt->integer_signed = *signed_;
594
 
                                }
595
 
                                ret = rt;
596
 
                                break;
597
 
                        }
598
 
                        
599
 
                        case intr_type::f_module:
600
 
                        case intr_type::f_class: 
601
 
                        case intr_type::f_closure: {
602
 
                                STATE_FAIL( "not-expected-here" );
603
 
                        }
604
 
                        
605
 
                        case intr_type::f_compat: {
606
 
                                auto rt = make_shared<intr_type_compat>();
607
 
                                rt->type = vt.get<pt_compat_type>();
608
 
                                ret = rt;
609
 
                                break;
610
 
                        }
611
 
                }
612
 
                
613
 
                if( !ret ) {
614
 
                        //return cerr::missing_intrinsic;
615
 
                        return type_ref::create_spec(vt);
616
 
                }
617
 
                
618
 
                for( auto & p : vt.params ) {
619
 
                        intr_type::param_spec ps;
620
 
                        ps.name = p.name;
621
 
                        ret->params.push_back( ps );
622
 
                }
623
 
                
624
 
                cret = ret;
625
 
        }
626
 
        STATE_CHECK(cret);
627
 
 
628
 
        extr_type tr(cret);
629
 
        
630
 
        if( vt.has<pt_lvalue>() ) {
631
 
                tr.set_lvalue( vt.get<pt_lvalue>() );
632
 
        }
633
 
        if( vt.has<pt_reference>() ) {
634
 
                tr.set_reference( vt.get<pt_reference>() );
635
 
        }
636
 
        if( vt.has<pt_optional>() ) {
637
 
                tr.set_optional( vt.get<pt_optional>() );
638
 
        }
639
 
        if( vt.has<pt_cvt_optional>() ) {
640
 
                tr.set_cvt_optional( vt.get<pt_cvt_optional>() );
641
 
        }
642
 
        if( vt.has<pt_lossy>() ) {
643
 
                tr.set_lossy( vt.get<pt_lossy>() );
644
 
        }
645
 
        if( vt.has<pt_literal>() )
646
 
                tr.set_literal( vt.get<pt_literal>() );
647
 
                
648
 
        //apply constraints
649
 
        if( vt.get<pt_tuple>(false) && !tr.is<intr_type_tuple>() ) {
650
 
                return cerr::requires_tuple;
651
 
        }
652
 
        
653
 
        //DEBUG( "OUT-DETERMINE", dump::get( vt ) );
654
 
        auto q = type_ref(tr);
655
 
        return q;
656
 
}
657
 
 
658
 
type_identifier::resolve_spec_t type_identifier::get_spec( type_ref assign_ ) {
659
 
        
660
 
        //DEBUG( "GET_SPEC", dump::get( assign_ ) );
661
 
        
662
 
        if( assign_.is_spec() ) {
663
 
                return make_shared<type_spec>(assign_.spec());
664
 
        }
665
 
        
666
 
        if( !assign_.is_defined() ) {
667
 
                return make_shared<type_spec>();
668
 
        }
669
 
        
670
 
        STATE_CHECK( assign_.is_extr() );
671
 
        return get_spec(assign_.extr());
672
 
}
673
 
        
674
 
type_identifier::resolve_spec_t type_identifier::get_spec( extr_type assign ) {
675
 
        auto rt = get_spec( *assign.intr );
676
 
        if( !rt.okay() ) {
677
 
                return rt;
678
 
        }
679
 
        
680
 
        auto spec = rt.result;
681
 
        spec->set<pt_optional>( assign.is_optional() );
682
 
        spec->set<pt_reference>( assign.get_reference() );
683
 
        spec->set<pt_lvalue>( assign.is_lvalue() );
684
 
        spec->set<pt_lossy>( assign.is_lossy() );
685
 
        spec->set<pt_literal>( assign.is_literal() );
686
 
 
687
 
        return spec;
688
 
}
689
 
        
690
 
type_identifier::resolve_spec_t type_identifier::get_spec( intr_type const & intr ) {
691
 
        auto spec = make_shared<type_spec>();
692
 
 
693
 
        if( intr.instance_of ) {
694
 
                auto & pt = spec->set<pt_fun_prototype>( intr.instance_of );
695
 
                for( auto & p : intr.applied_params ) {
696
 
                        auto res = get_spec( p );
697
 
                        if( !res.okay() ) {
698
 
                                return res;
699
 
                        }
700
 
                        pt.sub.push_back( res.result );
701
 
                }
702
 
        } else if( intr.is_whole() ){
703
 
                spec->set<pt_fun_prototype>( intr.shared_from_this() );
704
 
        } else switch( intr.get_fun_class() ) {
705
 
        
706
 
                case intr_type::f_rational: {
707
 
                        auto & rt = intr.cast<intr_type_rational>();
708
 
                        spec->set<pt_fun_class>( intr_type::f_rational );
709
 
                        if( rt.integer_bitsize ) {
710
 
                                spec->set<pt_data_bitsize>( *rt.integer_bitsize );
711
 
                        }
712
 
                        spec->set<pt_signed>( rt.integer_signed );
713
 
                        break;
714
 
                }
715
 
                case intr_type::f_value_list:
716
 
                case intr_type::f_tuple: {
717
 
                        if( spec->sub.empty() ) {
718
 
                                auto & comp = intr.cast<intr_type_compound>();
719
 
                                spec->set<pt_fun_class>( intr.get_fun_class() );
720
 
                                //each part of the tuple must be inferred (this similar to the above when the spec matches)
721
 
                                spec->sub.resize( comp.sub.size() );
722
 
                                for( size_t i=0; i < comp.sub.size(); ++i ) {
723
 
                                        auto lit = get_spec( comp.sub[i].type );
724
 
                                        if( !lit.okay() ) {
725
 
                                                return lit;
726
 
                                        }
727
 
                                        spec->sub[i].type = lit.result;
728
 
                                        spec->sub[i].name = comp.sub[i].name;
729
 
                                }
730
 
                        }
731
 
                        
732
 
                        if( intr.is<intr_type_tuple>() ) {
733
 
                                auto & tt = intr.cast<intr_type_tuple>();
734
 
                                if( !spec->has<pt_pack>() ) {
735
 
                                        spec->set<pt_pack>( tt.pack );
736
 
                                }
737
 
                                if( !spec->has<pt_selectable>() ) {
738
 
                                        spec->set<pt_selectable>( tt.selectable );
739
 
                                }
740
 
                        }
741
 
                        break;
742
 
                }
743
 
                case intr_type::f_function: {
744
 
                        auto & func = intr.cast<intr_type_function>();
745
 
 
746
 
                        spec->set<pt_fun_class>( intr_type::f_function );
747
 
                        spec->set<pt_function_access>( func.access );
748
 
                        if( func.context.is_extr() ) {
749
 
                                spec->set<pt_context>( func.context.extr() );
750
 
                        }
751
 
                        size_t sub_size = func.returns ? 2 : 1;
752
 
                        spec->sub.resize( sub_size );
753
 
                        //TODO: Perhaps this should not be inferred and they should just be wrapped as throwing?
754
 
                        if( !func.can_fail )
755
 
                                spec->set<pt_function_throw>(false);
756
 
                        
757
 
                        for( size_t i=0; i < sub_size; ++i ) {
758
 
                                auto store = get_spec( extr_type(i ? func.returns : func.args) );
759
 
                                if( !store.okay() )
760
 
                                        return store;
761
 
                                spec->sub[i].type = store.result;
762
 
                        }
763
 
                        break;
764
 
                }
765
 
                case intr_type::f_contextual: {
766
 
                        auto & ct = intr.cast<intr_type_contextual>();
767
 
                        
768
 
                        auto & sr = spec->set<pt_fun_class>( intr_type::f_contextual );
769
 
                        
770
 
                        auto context = get_spec( ct.get_context() );
771
 
                        if( !context.okay() ) {
772
 
                                return context;
773
 
                        }
774
 
                        
775
 
                        auto unbound = get_spec( ct.get_unbound() );
776
 
                        if( !unbound.okay() ) {
777
 
                                return unbound;
778
 
                        }
779
 
                        
780
 
                        sr.sub.push_back( context.result );
781
 
                        sr.sub.push_back( unbound.result );
782
 
                        break;
783
 
                }
784
 
                case intr_type::f_array: {
785
 
                        auto & arr = intr.cast<intr_type_array>();
786
 
 
787
 
                        //return to symbol space here to generate the array spec
788
 
                        auto store = get_spec( arr.sub.extr() );
789
 
                        if( !store.okay() ) {
790
 
                                return store;
791
 
                        }
792
 
                        
793
 
                        auto & sr = spec->set<pt_fun_class>( intr_type::f_array );
794
 
                        sr.sub.push_back( store.result );
795
 
                        
796
 
                        if( arr.raw ) {
797
 
                                spec->set<pt_function_access>( intr_type_function::a_raw );
798
 
                        }
799
 
                        break;
800
 
                }
801
 
                
802
 
                //TODO: shares a lot with f_array
803
 
                case intr_type::f_type: {
804
 
                        auto & arr = intr.cast<intr_type_type>();
805
 
 
806
 
                        //return to symbol space here to generate the array spec
807
 
                        auto store = get_spec( arr.sub.extr() );
808
 
                        if( !store.okay() ) {
809
 
                                return store;
810
 
                        }
811
 
                        
812
 
                        auto & sr = spec->set<pt_fun_class>( intr_type::f_type );
813
 
                        sr.sub.push_back( store.result );
814
 
                        break;
815
 
                }
816
 
                        
817
 
                case intr_type::f_integer:
818
 
                case intr_type::f_binary:
819
 
                case intr_type::f_float: {
820
 
                        auto & num = intr.cast<intr_type_fixed_number>();
821
 
                        spec->set<pt_fun_class>( intr.get_fun_class() );
822
 
                        if( !spec->has<pt_data_bitsize>() ) {
823
 
                                spec->set<pt_data_bitsize>( num.data_bitsize );
824
 
                        }
825
 
                        break;
826
 
                }
827
 
                
828
 
                case intr_type::f_boolean:
829
 
                case intr_type::f_char: {
830
 
                        spec->set<pt_fun_class>( intr.get_fun_class() );
831
 
                        break;
832
 
                }
833
 
                        
834
 
                case intr_type::f_module:
835
 
                case intr_type::f_class:
836
 
                case intr_type::f_closure: {
837
 
                        STATE_FAIL( "not-expected-here" );
838
 
                }
839
 
                
840
 
                case intr_type::f_compat: {
841
 
                        auto & ct = intr.cast<intr_type_compat>();
842
 
                        spec->set<pt_fun_class>( intr_type::f_compat );
843
 
                        spec->set<pt_compat_type>( ct.type );
844
 
                        break;
845
 
                }
846
 
                
847
 
        }
848
 
 
849
 
        if( intr.params.size() ) {
850
 
                for( auto & s : intr.params ) {
851
 
                        spec->push_param( s.name, shared_ptr<type_spec const>() );
852
 
                }
853
 
        }
854
 
        
855
 
        return spec;
856
 
}
857
 
 
858
 
type_identifier::resolve_t type_identifier::morph( type_spec const * spec_, 
859
 
        type_ref assign, unsigned flags )
860
 
{
861
 
        auto spec = morph_spec( spec_, assign, flags );
862
 
        if( !spec.okay() )
863
 
                return resolve_t(spec);
864
 
                
865
 
        //DEBUG( "MORPH", spec.result->get<pt_tuple>(false) );
866
 
        return determine( *spec.result, flags );
867
 
}
868
 
 
869
 
type_identifier::resolve_spec_t type_identifier::morph_spec( type_spec const * spec_, 
870
 
        type_ref assign, unsigned flags ) {
 
19
namespace type_identifier {
 
20
 
 
21
typedef std::map<std::string, type_ref> param_map_t;
 
22
typedef std::vector<extr_type> param_vector_t;
 
23
 
 
24
resolve_t morph( context const & ctx, type_spec const * constraint, type_ref source, unsigned flags );
 
25
resolve_spec_t morph_spec( context const & ctx, type_spec const * constraint, type_ref source, unsigned flags );
 
26
resolve_value_list_t morph_value_list( context const & ctx, type_ref source, unsigned flags );
 
27
 
 
28
resolve_spec_t expand( context const & ctx, type_spec const & cvt, param_map_t const & params, unsigned flags = 0 );
 
29
cerr_base expand_into( context const & ctx, type_spec & to, type_spec const & from,
 
30
        param_map_t const & params, unsigned flags );
 
31
        
 
32
 
 
33
void complete_defaults( context const & ctx, type_spec & ts );
 
34
void apply_infer( context const & ctx, type_spec & ts );
 
35
 
 
36
context create_function_scope(context const & ctx) {
 
37
        auto fs = scope::create_pseudo( scope_style_t::declarative );
 
38
        fs->set_base( ctx.sc, scope::bt_parent );
 
39
 
 
40
        return ctx.derive( fs );
 
41
}
 
42
 
 
43
#include "type_identifier/get_spec.inc.cpp"
 
44
#include "type_identifier/instantiate.inc.cpp"
 
45
#include "type_identifier/defaults.inc.cpp"
 
46
#include "type_identifier/determine.inc.cpp"
 
47
#include "type_identifier/parameterize.inc.cpp"
 
48
#include "type_identifier/expand.inc.cpp"
 
49
 
 
50
resolve_t infer( context const & ctx, type_spec const & constraint, type_ref const & source, bool init_refer ) {
 
51
        return morph( ctx, &constraint, source, df_infer | (init_refer ? df_refer : 0) );
 
52
}
 
53
resolve_t infer( context const & ctx, shared_ptr<type_spec const> constraint, 
 
54
        type_ref const & source, bool init_refer ) {
 
55
        return morph( ctx, constraint.get(), source, df_infer | (init_refer ? df_refer : 0) ); 
 
56
}
 
57
resolve_spec_t infer_spec( context const & ctx, type_spec const & spec, type_ref assign, bool init_refer ) {
 
58
        return morph_spec( ctx, &spec, assign, df_infer | (init_refer ? df_refer : 0) );
 
59
}
 
60
resolve_t infer( context const & ctx, type_ref const & source, bool init_refer ) {
 
61
        return morph( ctx, nullptr, source, df_infer | (init_refer ? df_refer : 0) );
 
62
}
 
63
 
 
64
/**
 
65
        Constrains the given type to the indicated spec. This is a lesser reduction
 
66
        than "infer" since it may retain literals and virtual types like rationals.
 
67
*/
 
68
resolve_t constrain( context const & ctx, type_spec const & constraint, type_ref const & source ) {
 
69
        return morph( ctx, &constraint, source, df_allow_param );
 
70
}
 
71
resolve_t constrain( context const & ctx, shared_ptr<type_spec const> constraint, type_ref const & source ) {
 
72
        return morph( ctx, constraint.get(), source, df_allow_param ); 
 
73
}
 
74
 
 
75
/**
 
76
        Infers a value-list (such as for inferred return types).
 
77
*/
 
78
resolve_value_list_t infer_value_list( context const & ctx, type_ref source, bool init_refer ) {
 
79
        return morph_value_list( ctx, source, df_infer | (init_refer ? df_refer : 0) );
 
80
}
 
81
 
 
82
resolve_t morph( context const & ctx, type_spec const * constraint_, type_ref source, unsigned flags ) {
 
83
        auto constrained = morph_spec( ctx, constraint_, source, flags );
 
84
        if( !constrained.okay() )
 
85
                return resolve_t(constrained);
 
86
                
 
87
        //OPT: this needlessly expands the source again
 
88
        return determine( ctx, *constrained.result, flags );
 
89
}
 
90
 
 
91
resolve_spec_t morph_spec( context const & ctx, type_spec const * constraint_, type_ref source, unsigned flags ) {
871
92
        
872
93
        static type_spec const empty_spec;
873
 
        auto & spec = spec_ ? *spec_ : empty_spec;
874
 
 
 
94
        auto & constraint = constraint_ ? *constraint_ : empty_spec;
875
95
        
876
96
        //decompose value-list
877
 
        while( true && assign.is_extr() ) {
878
 
                auto vl = assign.extr().if_cast<intr_type_value_list>();
 
97
        while( source.is_extr() ) {
 
98
                auto vl = source.extr().if_cast<intr_type_value_list>();
879
99
                if( !vl )
880
100
                        break;
881
101
                        
882
102
                if( vl->sub.size() != 1 ) {
883
103
                        return cerr::disallow_value_list;
884
104
                }
885
 
                assign = vl->sub[0].type;
 
105
                source = vl->sub[0].type;
886
106
        }
887
107
        
888
108
        //we need to work with an expanded spec
889
 
        auto ex = expand( spec );
890
 
        if( !ex.okay() ) {
891
 
                return ex;
 
109
        auto ex_constraint = expand( ctx, constraint );
 
110
        if( !ex_constraint.okay() ) {
 
111
                return ex_constraint;
892
112
        }
893
 
        complete_defaults( *ex.result );
 
113
        complete_defaults( ctx, *ex_constraint.result );
894
114
        
895
 
        auto as = get_spec( assign );
896
 
        STATE_CHECK( as.okay(), as.explain_error() );
 
115
        auto source_spec = get_spec( ctx, source );
 
116
        STATE_CHECK( source_spec.okay(), source_spec.explain_error() );
897
117
        if( flags & df_infer ) {
898
 
                apply_infer( *as.result );
 
118
                apply_infer( ctx, *source_spec.result );
899
119
        }
900
120
 
901
121
        //init_refer requires a shared type
902
122
        if( flags & df_refer ) {
903
 
                //DEBUG( "MORPH_SPEC_REFER", dump::get( ex.result ), dump::get( as.result ) );
904
 
                /*if( as.result->has<pt_shared>() && !as.result->get<pt_shared>() ) {
905
 
                        return cerr::mismatch_shared;
906
 
                }*/
907
 
                as.result->set<pt_reference>( extr_type::r_shared );
 
123
                source_spec.result->set<pt_reference>( extr_type::r_shared );
908
124
        }
909
125
        
910
126
        param_map_t pt;
911
 
        auto r = expand_into( *ex.result, *as.result, pt, flags );
 
127
        auto r = expand_into( ctx, *ex_constraint.result, *source_spec.result, pt, flags );
912
128
        if( !r.okay() ) {
913
129
                return resolve_spec_t(r);
914
130
        }
915
 
        return ex.result;
 
131
        return ex_constraint.result;
916
132
}
917
133
 
918
 
type_identifier::resolve_value_list_t type_identifier::morph_value_list( type_ref assign, 
919
 
        unsigned flags ) {
 
134
resolve_value_list_t morph_value_list( context const & ctx, type_ref source, unsigned flags ) {
920
135
        //decompose value-list
921
136
        while( true ) {
922
 
                auto vl = assign.extr().if_cast<intr_type_value_list>();
 
137
                auto vl = source.extr().if_cast<intr_type_value_list>();
923
138
                if( !vl ) {
924
 
                        auto part = morph( nullptr, assign, flags );
 
139
                        auto part = morph( ctx, nullptr, source, flags );
925
140
                        if( !part.okay() ) {
926
141
                                return resolve_value_list_t(part);
927
142
                        }
932
147
                }
933
148
                        
934
149
                if( vl->sub.size() == 1 ) {
935
 
                        assign = type_ref(vl->sub[0].type);
 
150
                        source = type_ref(vl->sub[0].type);
936
151
                        continue;
937
152
                }
938
153
                
939
154
                auto list = make_shared<intr_type_value_list>();
940
155
                for( auto & sub : vl->sub ) {
941
 
                        auto part = morph( nullptr, sub.type, flags );
 
156
                        auto part = morph( ctx, nullptr, sub.type, flags );
942
157
                        if( !part.okay() ) {
943
158
                                return resolve_value_list_t(part);
944
159
                        }
949
164
        
950
165
}
951
166
 
952
 
type_identifier::resolve_intr_type_t type_identifier::instantiate( shared_ptr<intr_type const> & pt, 
953
 
        param_vector_t const & params ) {
954
 
        
955
 
        STATE_CHECK( pt->contains_parametric() );
956
 
        STATE_CHECK( params.size() == pt->params.size() );
957
 
 
958
 
        //look for exisintg instance first, multiple instances must be the same object, otherwise
959
 
        //other logic becomes harder
960
 
        auto cur = pt->if_find_instance( params );
961
 
        if( cur ) {
962
 
                //DEBUG( "FOUND INSTANCE", dump::get(cur) );
963
 
                return cur;
964
 
        }
965
 
        
966
 
        shared_ptr<intr_type> dup;
967
 
        
968
 
        //DEBUG( "INSTANTIATE", dump::get( pt ) );
969
 
        param_map_t pmap;
970
 
        for( size_t i = 0; i < params.size(); ++i ) {
971
 
                //DEBUG( "PARAM", pt->params[i].name, dump::get( params[i] ) );
972
 
                pmap[pt->params[i].name] = params[i];
973
 
        }
974
 
        
975
 
        if( pt->is<intr_type_tuple>() ) {
976
 
                auto & tt = pt->cast<intr_type_tuple>();
977
 
                auto tdup = tt.clone_derived();
978
 
                for( auto & sr : tdup->sub ) {
979
 
                        auto ir = instantiate( sr.type, pmap );
980
 
                        if(!ir.okay()) {
981
 
                                return resolve_intr_type_t(ir);
982
 
                        }
983
 
                        sr.type = ir.result;
984
 
                }
985
 
                
986
 
                dup = tdup;
987
 
        
988
 
        } else if( pt->is<intr_type_array>() ) {
989
 
                auto & tw = pt->cast<intr_type_array>();
990
 
                auto tdup = tw.clone_derived();
991
 
                auto ir = instantiate( tdup->sub, pmap );
992
 
                if( !ir.okay() ) {
993
 
                        return resolve_intr_type_t(ir);
994
 
                }
995
 
                tdup->sub = ir.result;
996
 
                dup = tdup;
997
 
                
998
 
        } else if( pt->is<intr_type_custom>() ) {
999
 
                dup = pt->clone();
1000
 
        
1001
 
        } else {
1002
 
                STATE_FAIL( "invalid-parameterized-type" );
1003
 
        }
1004
 
        
1005
 
        for( size_t i = 0; i < params.size(); ++i ) {
1006
 
                dup->applied_params.push_back( params[i] );
1007
 
        }
1008
 
        
1009
 
        dup->clear_param();
1010
 
        dup->instance_of = pt;
1011
 
        dup->style = intr_type::s_plain; //loses distinctness
1012
 
        //DEBUG( "POST-INSTANCE", dump::get(dup), !!dup->instance_of, pt->is_instance());
1013
 
        
1014
 
        if( pt->is_instance() ) {
1015
 
                dup->instance_of = pt->instance_of;
1016
 
        }
1017
 
        
1018
 
        if( dup->is<intr_type_class>() ) {
1019
 
                class_typer::instantiate( std::static_pointer_cast<intr_type_class>(dup), ctx );
1020
 
        }
1021
 
        pt->instances.push_back( dup );
1022
 
        return resolve_intr_type_t(dup);
1023
 
}
1024
 
 
1025
 
type_identifier::resolve_t type_identifier::instantiate( type_ref pt, param_map_t const & params ) {
1026
 
        
1027
 
        if( !pt.contains_parametric() ) {
1028
 
                return pt;
1029
 
        }
1030
 
        
1031
 
        switch( pt.type() ) {
1032
 
                case type_ref::t_undefined:
1033
 
                        STATE_FAIL( "unexpected-parametric-type-ref" );
1034
 
 
1035
 
                case type_ref::t_spec: {
1036
 
                        auto r = expand( pt.spec(), params, df_instantiate );
1037
 
                        if (!r.okay()) {
1038
 
                                return resolve_t(r);
1039
 
                        }
1040
 
                        
1041
 
                        auto q = determine( r.result );
1042
 
                        if(!r.okay()) {
1043
 
                                return resolve_t(r);
1044
 
                        }
1045
 
                        
1046
 
                        return q.result;
1047
 
                }
1048
 
                
1049
 
                case type_ref::t_extr:
1050
 
                        switch( pt.extr().intr->get_fun_class() ) {
1051
 
                                        
1052
 
                                case intr_type::f_tuple: {
1053
 
                                        auto & tt = pt.extr().cast<intr_type_tuple>();
1054
 
                                        auto dup = tt.clone_derived();
1055
 
                                        for( auto & sr : dup->sub ) {
1056
 
                                                auto r =instantiate( sr.type, params );
1057
 
                                                if(!r.okay()) {
1058
 
                                                        return resolve_t(r);
1059
 
                                                }
1060
 
                                                sr.type = r.result;
1061
 
                                        }
1062
 
                                        return resolve_t(extr_type(dup));
1063
 
                                }
1064
 
                                        
1065
 
                                default:
1066
 
                                        STATE_FAIL( "unexpected-parametric-fundamental" );
1067
 
                        }
1068
 
        }
1069
 
        
1070
 
        STATE_FAIL( "unreachable" );
1071
 
}
1072
 
 
1073
 
/**
1074
 
        Adds defaults to the spec.  This is done in situations where the input spec is incomplete, but was
1075
 
        meant to be a complete spec by the user (such as var inference and constraint)
1076
 
*/
1077
 
void type_identifier::complete_defaults( type_spec & ts ) {
1078
 
        if( !ts.has_known_intrinsic() ) {
1079
 
                return;
1080
 
        }
1081
 
        
1082
 
        ts.default_set<pt_lossy>(false);
1083
 
        ts.default_set<pt_lvalue>(false);
1084
 
        ts.default_set<pt_optional>(false);
1085
 
        ts.default_set<pt_cvt_optional>(false);
1086
 
        ts.default_set<pt_reference>(extr_type::r_value);
1087
 
        
1088
 
        auto fc = ts.get_any_fun_class();
1089
 
        switch( fc ) {
1090
 
                case intr_type::f_integer:
1091
 
                        ts.default_set<pt_data_bitsize>(platform::natural_integer_size);
1092
 
                        break;
1093
 
        
1094
 
                case intr_type::f_float:
1095
 
                        if( !ts.has<pt_data_bitsize>() ) {
1096
 
                                ts.default_set<pt_precision_variant>(platform::natural_float_precision_variant);
1097
 
                        }
1098
 
                        break;
1099
 
                        
1100
 
                case intr_type::f_function:
1101
 
                        if( ts.get<pt_member>(false) ) {
1102
 
                                ts.default_set<pt_function_access>(intr_type_function::a_unbound);
1103
 
                        } else if( ts.has<pt_context_name>() || ts.has<pt_context>() ) {
1104
 
                                ts.default_set<pt_function_access>(intr_type_function::a_unbound);
1105
 
                        } else {
1106
 
                                ts.default_set<pt_function_access>(intr_type_function::a_bound);
1107
 
                        }
1108
 
                        break;
1109
 
        
1110
 
                case intr_type::f_tuple:
1111
 
                        ts.default_set<pt_pack>(intr_type_tuple::p_normal);
1112
 
                        break;
1113
 
                        
1114
 
                default:
1115
 
                        break;
1116
 
        }
1117
 
}
1118
 
 
1119
 
void type_identifier::apply_infer( type_spec & ts ) {
1120
 
        auto fc = ts.get_any_fun_class();
1121
 
 
1122
 
        //rationals don't exist as actual variables (literal declarations exist however)
1123
 
        if( fc == intr_type::f_rational ) {
1124
 
                if( ts.has<pt_data_bitsize>() ) {
1125
 
                        ts.set<pt_fun_class>( intr_type::f_integer );
1126
 
                        ts.clear<pt_data_bitsize>();
1127
 
                } else {
1128
 
                        ts.set<pt_fun_class>( intr_type::f_float );
1129
 
                }
1130
 
                ts.clear<pt_fun_prototype>();
1131
 
        } else if( fc == intr_type::f_function ) {
1132
 
                auto context = ts.if_get<pt_context>();
1133
 
                if( context ) {
1134
 
                        auto & ft = (*context).intr->cast<intr_type_custom>();
1135
 
                        if( !ft.has_distinct_name() && 
1136
 
                                !get_decl_scope()->is_base_reachable( ft.context) ) {
1137
 
                                //infer bound version of any function belonging to a scope not avaiable in the declaration scope
1138
 
                                ts.clear<pt_context>();
1139
 
                                ts.set<pt_function_access>(intr_type_function::a_bound);
1140
 
                        }
1141
 
                }
1142
 
        }
1143
 
        
1144
 
        ts.clear<pt_lvalue>();
1145
 
        ts.clear<pt_literal>();
1146
 
        
1147
 
        for( auto & s : ts.sub ) {
1148
 
                auto c = make_shared<type_spec>(*s.type);
1149
 
                apply_infer( *c );
1150
 
                s.type = c;
1151
 
        }
1152
 
}
1153
 
 
1154
 
type_identifier::resolve_t type_identifier::parameterize_type( 
1155
 
        type_ref const & param_type_, type_ref const & apply_, unsigned /*flags*/ ) {
1156
 
        
1157
 
        //DEBUG( "PARAMETERIZE_TYPE", param_type_.contains_parametric(), param_type_.is_complete(),
1158
 
        //      dump::get( param_type_ ), dump::get( apply_ ) );
1159
 
                
1160
 
        if( !param_type_.contains_parametric() || param_type_.is_complete() ) {
1161
 
                return param_type_;
1162
 
        }
1163
 
        
1164
 
        auto ps = get_spec( param_type_ );
1165
 
        if( !ps.okay() ) {
1166
 
                return resolve_t(ps);
1167
 
        }
1168
 
        //need to expand target since get_spec might have been from a unexpanded type_spec
1169
 
        auto pes = expand( *ps.result );
1170
 
        if( !pes.okay() ){
1171
 
                return resolve_t(pes);
1172
 
        }
1173
 
        auto param_type = pes.result;
1174
 
        
1175
 
        auto apply = get_spec( apply_ );
1176
 
        if( !apply.okay() )  {
1177
 
                return resolve_t(apply);
1178
 
        }
1179
 
        
1180
 
        param_map_t empty;
1181
 
        //DEBUG("\n\nPRE-EXPAND", dump::get(param_type), dump::get(apply.result));
1182
 
        auto c = expand_into( *param_type, *apply.result, empty, df_infer );
1183
 
        if( !c.okay() ) {
1184
 
                return resolve_t(c);
1185
 
        }
1186
 
        //DEBUG("POST-EXPAND", dump::get(param_type));
1187
 
        apply_infer(*param_type);
1188
 
        return determine(param_type);
1189
 
}
1190
 
 
1191
 
type_identifier::resolve_t type_identifier::parameterize_type( 
1192
 
        intr_type const & param_type_, intr_type const & apply_, unsigned /*flags*/ ) {
1193
 
        
1194
 
        auto ps = get_spec( param_type_ );
1195
 
        if( !ps.okay() ) {
1196
 
                return resolve_t(ps);
1197
 
        }
1198
 
        auto param_type = make_shared<type_spec>( *ps.result );
1199
 
        
1200
 
        auto apply = get_spec( apply_ );
1201
 
        if( !apply.okay() )  {
1202
 
                return resolve_t(apply);
1203
 
        }
1204
 
        
1205
 
        param_map_t empty;
1206
 
        auto c = expand_into( *param_type, *apply.result, empty, df_infer );
1207
 
        if( !c.okay() ) {
1208
 
                return resolve_t(c);
1209
 
        }
1210
 
        apply_infer(*param_type);
1211
 
        return determine(param_type);
1212
 
}
1213
 
 
1214
 
 
1215
 
shared_ptr<scope> type_identifier::get_decl_scope() {
1216
 
        return ctx.get_decl_scope();
1217
 
}
1218
 
 
1219
 
shared_ptr<scope> type_identifier::get_symbol_scope() {
1220
 
        if( symbol_scope ) {
1221
 
                return symbol_scope;
1222
 
        }
1223
 
        return ctx.get_decl_scope();
1224
 
}
1225
 
 
1226
 
shared_ptr<scope> type_identifier::push_function_scope() {
1227
 
        auto fs = scope::create_pseudo( scope_style_t::declarative );
1228
 
        fs->set_base( get_symbol_scope(), scope::bt_parent );
1229
 
        
1230
 
        auto old = symbol_scope;
1231
 
        symbol_scope = fs;
1232
 
        return old;
1233
 
}
1234
 
 
1235
 
void type_identifier::pop_function_scope( shared_ptr<scope> sc ) {
1236
 
        symbol_scope = sc;
1237
 
}
1238
 
 
 
167
} //eon type_identifier
1239
168
} //eon leaf
 
 
b'\\ No newline at end of file'