15
15
#include "util/debug.hpp"
16
16
#include "lang/dump.hpp"
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); \
27
type_identifier::resolve_t type_identifier::determine( shared_ptr<type_spec const> vt, unsigned flags ) {
29
return cerr::null_spec;
30
return determine( *vt, flags );
33
cerr_base type_identifier::expand_into( type_spec & to, type_spec const & from,
34
param_map_t const & params, unsigned flags ) {
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 );
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 ) );
53
for( auto & from_part : from.get_parts() ) {
54
auto copy_params = [&]( type_spec::part & to_part ) -> cerr {
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 );
62
to_part.sub.push_back( pex.result );
67
auto merge_params = [&]( type_spec::part & to_part ) -> cerr {
69
for( size_t i=0; i < from_part.sub.size(); ++i ) {
70
auto pex = expand( *from_part.sub[i], params );
74
if( i >= to_part.sub.size() ) {
75
to_part.sub.push_back( pex.result );
77
auto q = make_shared<type_spec>(*to_part.sub[i]);
78
auto rex = expand_into( *q, *pex.result, params, flags );
89
auto merge = [&]( type_spec const & other ) -> cerr_base {
90
if( from_part.sub.size() != other.params.size() ) {
91
return cerr::mismatch_params;
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 );
101
//DEBUG( "MAP", other.params[i].name, dump::get( pex.result ) );
102
pm[ other.params[i].name ] = type_ref::create_spec( *pex.result );
104
return expand_into( to, other, pm, flags );
107
auto merge_type_ref = [&]( type_ref tr ) -> cerr_base {
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 );
115
STATE_FAIL( "unsupported-type-ref" );
118
if( is_singular_part_type( from_part.type ) ) {
119
auto hp = to.has_alternate_part( from_part.type );
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;
127
merge_params( to.get_part(*hp) );
130
auto & s = to.set_part( from_part.type, from_part.value );
131
auto c = copy_params( s );
132
if( c != cerr::okay ) {
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 ) {
150
auto c = merge_type_ref( pit->second );
158
STATE_CHECK( from_part.type == pt_symbol );
160
auto name_parts = boost::get<type_spec_symbol>(&from_part.value);
161
STATE_CHECK( name_parts);
162
auto &name = name_parts->primary();
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 );
175
if( name == "type_infer" ) {
176
if( !from_part.expr ) {
177
return cerr::missing_expression;
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();
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);
192
//return cerr::unknown_identifier;
194
auto ptype = pex->type.extr().if_cast<intr_type_value_list>();
195
if( !ptype || ptype->sub.size() != 1 ) {
196
return cerr::invalid_expression;
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);
205
DEBUG( "end_type_infer" );
209
auto symbol = get_symbol_scope()->resolve_symbol( name );
210
if( !symbol.okay() ) {
211
return cerr_base( symbol.error, name );
214
if( symbol.result.what == scope_symbol::w_type_alias ) {
215
auto r = merge( *symbol.result.type_alias );
222
if( symbol.result.what == scope_symbol::w_fun_type ) {
223
if( to.has<pt_fun_class>() ) {
224
return cerr::redundant_fundamental;
227
auto & s = to.set<pt_fun_prototype>( symbol.result.fun_type );
232
return cerr_base( cerr::invalid_symbol_type, name );
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();
240
for( size_t i=0; i < from.sub.size(); ++i ) {
241
auto r = expand( *from.sub[i].type, params );
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 );
255
to.sub[i].type = r.result;
258
if( to.sub[i].name.empty() ) {
259
to.sub[i].name = from.sub[i].name;
262
to.push_sub( from.sub[i].name, r.result );
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);
274
DEBUG("EndIdentFunction");
277
//DEBUG( "=>", &to, dump::get(to) );
281
type_identifier::resolve_spec_t type_identifier::expand( type_spec const & vt ) {
283
//DEBUG( "EXPAND", dump::get( vt ) );
284
//replace these with their appropriate placeholders (just retains the notation)
286
for( auto & p : vt.params ) {
288
ts.push_part<pt_param>( p.name );
289
retain[p.name] = type_ref::create_spec(ts); //TODO: p.type constraints?
292
auto r = expand( vt, retain );
294
r.result->params = vt.params;
299
type_identifier::resolve_spec_t type_identifier::expand( type_spec const & from,
300
param_map_t const & params, unsigned flags ) {
302
auto to = make_shared<type_spec>();
303
auto r = expand_into( *to, from, params, flags | df_single );
305
return resolve_spec_t(r);
308
//DEBUG( "EXPAND-OUT", dump::get( *to ) );
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_ );
316
return resolve_t(ex);
318
type_spec const & vt = *ex.result;
320
shared_ptr<intr_type const> cret =
321
vt.get<pt_fun_prototype>( shared_ptr<intr_type const>() ); //may be null
323
//DEBUG( "CRET", dump::get( vt ),
324
// cret && cret->contains_parametric(),
327
if( cret && cret->contains_parametric() ) {
328
auto & p = vt.get_part( pt_fun_prototype );
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 );
337
if (!c.result.is_extr()) {
338
if( flags & df_allow_param ) {
339
return type_ref::create_spec( vt );
341
return cerr::unresolved_param;
343
pt.push_back( c.result.extr() );
346
auto ir = instantiate( cret, pt );
348
return resolve_t(ir);
350
//DEBUG( "PARAM-INST", dump::get(ir.result));
353
} else if( !cret && vt.has<pt_param>()) {
355
if( flags & df_allow_param ) {
356
return type_ref::create_spec( vt );
358
return cerr::unresolved_param;
361
shared_ptr<intr_type> ret;
363
auto fund = vt.get<pt_fun_class>( intr_type::f_invalid );
366
case intr_type::f_boolean:
367
ret = make_shared<intr_type_boolean>();
370
case intr_type::f_char:
371
ret = make_shared<intr_type_char>();
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>();
382
for( size_t i=0; i < vt.sub.size(); ++i ) {
383
auto pt = determine( vt.sub[i].type, flags | df_sub_type );
386
tt->push_sub( vt.sub[i].name, pt.result );
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();
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)
401
tt->push_sub( vt.sub[i].name, pt.result );
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);
416
case intr_type::f_function: {
417
auto ft = make_shared<intr_type_function>();
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);
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;
428
auto fctx = get_symbol_scope()->resolve_symbol(
429
vt.get<pt_context_name>() );
431
return resolve_t( fctx.error, vt.get<pt_context_name>() );
433
if( fctx.result.what != scope_symbol::w_fun_type
434
|| !fctx.result.fun_type->is<intr_type_custom>() ) {
435
return cerr::invalid_context;
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();
443
if( vt.has<pt_function_access>() ) {
444
ft->access = vt.get<pt_function_access>();
447
if( vt.has<pt_function_throw>() ) {
448
ft->can_fail = vt.get<pt_function_throw>();
451
if( vt.sub.size() != 1 && vt.sub.size() != 2 )
452
return cerr::mismatch_size;
454
auto args = determine( vt.sub[0].type, flags | df_sub_type );
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);
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() )
466
if( returns.result.is_spec() ) {
467
//leave ft->returns as null
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);
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 ) {
487
auto rt = determine( p.sub[0], flags | df_sub_type );
491
if( !rt.result.is_extr() ) {
492
if( flags & df_allow_param ) {
493
return type_ref::create_spec( vt );
495
return cerr::unresolved_param;
498
at->sub = rt.result.extr();
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 );
513
if( !rt.result.is_extr() ) {
514
if( flags & df_allow_param ) {
515
return type_ref::create_spec( vt );
517
return cerr::unresolved_param;
520
at->sub = rt.result.extr();
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;
531
auto ct = make_shared<intr_type_contextual>();
532
auto rt = determine( p.sub[0], flags | df_sub_type );
536
ct->get_context() = rt.result;
538
rt = determine( p.sub[1], flags | df_sub_type );
542
ct->get_unbound() = rt.result;
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>();
554
it = make_shared<intr_type_binary>();
556
if( vt.has<pt_data_bitsize>() ) {
557
it->data_bitsize = vt.get<pt_data_bitsize>();
559
it->data_bitsize = platform::natural_integer_size;
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;
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>() );
577
return cerr::unknown_variant;
578
ft->data_bitsize = nf->size;
580
ft->data_bitsize = platform::natural_float_size;
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>();
591
auto signed_ = vt.if_get<pt_signed>();
593
rt->integer_signed = *signed_;
599
case intr_type::f_module:
600
case intr_type::f_class:
601
case intr_type::f_closure: {
602
STATE_FAIL( "not-expected-here" );
605
case intr_type::f_compat: {
606
auto rt = make_shared<intr_type_compat>();
607
rt->type = vt.get<pt_compat_type>();
614
//return cerr::missing_intrinsic;
615
return type_ref::create_spec(vt);
618
for( auto & p : vt.params ) {
619
intr_type::param_spec ps;
621
ret->params.push_back( ps );
630
if( vt.has<pt_lvalue>() ) {
631
tr.set_lvalue( vt.get<pt_lvalue>() );
633
if( vt.has<pt_reference>() ) {
634
tr.set_reference( vt.get<pt_reference>() );
636
if( vt.has<pt_optional>() ) {
637
tr.set_optional( vt.get<pt_optional>() );
639
if( vt.has<pt_cvt_optional>() ) {
640
tr.set_cvt_optional( vt.get<pt_cvt_optional>() );
642
if( vt.has<pt_lossy>() ) {
643
tr.set_lossy( vt.get<pt_lossy>() );
645
if( vt.has<pt_literal>() )
646
tr.set_literal( vt.get<pt_literal>() );
649
if( vt.get<pt_tuple>(false) && !tr.is<intr_type_tuple>() ) {
650
return cerr::requires_tuple;
653
//DEBUG( "OUT-DETERMINE", dump::get( vt ) );
654
auto q = type_ref(tr);
658
type_identifier::resolve_spec_t type_identifier::get_spec( type_ref assign_ ) {
660
//DEBUG( "GET_SPEC", dump::get( assign_ ) );
662
if( assign_.is_spec() ) {
663
return make_shared<type_spec>(assign_.spec());
666
if( !assign_.is_defined() ) {
667
return make_shared<type_spec>();
670
STATE_CHECK( assign_.is_extr() );
671
return get_spec(assign_.extr());
674
type_identifier::resolve_spec_t type_identifier::get_spec( extr_type assign ) {
675
auto rt = get_spec( *assign.intr );
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() );
690
type_identifier::resolve_spec_t type_identifier::get_spec( intr_type const & intr ) {
691
auto spec = make_shared<type_spec>();
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 );
700
pt.sub.push_back( res.result );
702
} else if( intr.is_whole() ){
703
spec->set<pt_fun_prototype>( intr.shared_from_this() );
704
} else switch( intr.get_fun_class() ) {
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 );
712
spec->set<pt_signed>( rt.integer_signed );
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 );
727
spec->sub[i].type = lit.result;
728
spec->sub[i].name = comp.sub[i].name;
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 );
737
if( !spec->has<pt_selectable>() ) {
738
spec->set<pt_selectable>( tt.selectable );
743
case intr_type::f_function: {
744
auto & func = intr.cast<intr_type_function>();
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() );
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?
755
spec->set<pt_function_throw>(false);
757
for( size_t i=0; i < sub_size; ++i ) {
758
auto store = get_spec( extr_type(i ? func.returns : func.args) );
761
spec->sub[i].type = store.result;
765
case intr_type::f_contextual: {
766
auto & ct = intr.cast<intr_type_contextual>();
768
auto & sr = spec->set<pt_fun_class>( intr_type::f_contextual );
770
auto context = get_spec( ct.get_context() );
771
if( !context.okay() ) {
775
auto unbound = get_spec( ct.get_unbound() );
776
if( !unbound.okay() ) {
780
sr.sub.push_back( context.result );
781
sr.sub.push_back( unbound.result );
784
case intr_type::f_array: {
785
auto & arr = intr.cast<intr_type_array>();
787
//return to symbol space here to generate the array spec
788
auto store = get_spec( arr.sub.extr() );
789
if( !store.okay() ) {
793
auto & sr = spec->set<pt_fun_class>( intr_type::f_array );
794
sr.sub.push_back( store.result );
797
spec->set<pt_function_access>( intr_type_function::a_raw );
802
//TODO: shares a lot with f_array
803
case intr_type::f_type: {
804
auto & arr = intr.cast<intr_type_type>();
806
//return to symbol space here to generate the array spec
807
auto store = get_spec( arr.sub.extr() );
808
if( !store.okay() ) {
812
auto & sr = spec->set<pt_fun_class>( intr_type::f_type );
813
sr.sub.push_back( store.result );
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 );
828
case intr_type::f_boolean:
829
case intr_type::f_char: {
830
spec->set<pt_fun_class>( intr.get_fun_class() );
834
case intr_type::f_module:
835
case intr_type::f_class:
836
case intr_type::f_closure: {
837
STATE_FAIL( "not-expected-here" );
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 );
849
if( intr.params.size() ) {
850
for( auto & s : intr.params ) {
851
spec->push_param( s.name, shared_ptr<type_spec const>() );
858
type_identifier::resolve_t type_identifier::morph( type_spec const * spec_,
859
type_ref assign, unsigned flags )
861
auto spec = morph_spec( spec_, assign, flags );
863
return resolve_t(spec);
865
//DEBUG( "MORPH", spec.result->get<pt_tuple>(false) );
866
return determine( *spec.result, flags );
869
type_identifier::resolve_spec_t type_identifier::morph_spec( type_spec const * spec_,
870
type_ref assign, unsigned flags ) {
19
namespace type_identifier {
21
typedef std::map<std::string, type_ref> param_map_t;
22
typedef std::vector<extr_type> param_vector_t;
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 );
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 );
33
void complete_defaults( context const & ctx, type_spec & ts );
34
void apply_infer( context const & ctx, type_spec & ts );
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 );
40
return ctx.derive( fs );
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"
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) );
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) );
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) );
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) );
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.
68
resolve_t constrain( context const & ctx, type_spec const & constraint, type_ref const & source ) {
69
return morph( ctx, &constraint, source, df_allow_param );
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 );
76
Infers a value-list (such as for inferred return types).
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) );
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);
87
//OPT: this needlessly expands the source again
88
return determine( ctx, *constrained.result, flags );
91
resolve_spec_t morph_spec( context const & ctx, type_spec const * constraint_, type_ref source, unsigned flags ) {
872
93
static type_spec const empty_spec;
873
auto & spec = spec_ ? *spec_ : empty_spec;
94
auto & constraint = constraint_ ? *constraint_ : empty_spec;
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>();
882
102
if( vl->sub.size() != 1 ) {
883
103
return cerr::disallow_value_list;
885
assign = vl->sub[0].type;
105
source = vl->sub[0].type;
888
108
//we need to work with an expanded spec
889
auto ex = expand( spec );
109
auto ex_constraint = expand( ctx, constraint );
110
if( !ex_constraint.okay() ) {
111
return ex_constraint;
893
complete_defaults( *ex.result );
113
complete_defaults( ctx, *ex_constraint.result );
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 );
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;
907
as.result->set<pt_reference>( extr_type::r_shared );
123
source_spec.result->set<pt_reference>( extr_type::r_shared );
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);
131
return ex_constraint.result;
918
type_identifier::resolve_value_list_t type_identifier::morph_value_list( type_ref assign,
134
resolve_value_list_t morph_value_list( context const & ctx, type_ref source, unsigned flags ) {
920
135
//decompose value-list
922
auto vl = assign.extr().if_cast<intr_type_value_list>();
137
auto vl = source.extr().if_cast<intr_type_value_list>();
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);
952
type_identifier::resolve_intr_type_t type_identifier::instantiate( shared_ptr<intr_type const> & pt,
953
param_vector_t const & params ) {
955
STATE_CHECK( pt->contains_parametric() );
956
STATE_CHECK( params.size() == pt->params.size() );
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 );
962
//DEBUG( "FOUND INSTANCE", dump::get(cur) );
966
shared_ptr<intr_type> dup;
968
//DEBUG( "INSTANTIATE", dump::get( pt ) );
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];
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 );
981
return resolve_intr_type_t(ir);
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 );
993
return resolve_intr_type_t(ir);
995
tdup->sub = ir.result;
998
} else if( pt->is<intr_type_custom>() ) {
1002
STATE_FAIL( "invalid-parameterized-type" );
1005
for( size_t i = 0; i < params.size(); ++i ) {
1006
dup->applied_params.push_back( params[i] );
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());
1014
if( pt->is_instance() ) {
1015
dup->instance_of = pt->instance_of;
1018
if( dup->is<intr_type_class>() ) {
1019
class_typer::instantiate( std::static_pointer_cast<intr_type_class>(dup), ctx );
1021
pt->instances.push_back( dup );
1022
return resolve_intr_type_t(dup);
1025
type_identifier::resolve_t type_identifier::instantiate( type_ref pt, param_map_t const & params ) {
1027
if( !pt.contains_parametric() ) {
1031
switch( pt.type() ) {
1032
case type_ref::t_undefined:
1033
STATE_FAIL( "unexpected-parametric-type-ref" );
1035
case type_ref::t_spec: {
1036
auto r = expand( pt.spec(), params, df_instantiate );
1038
return resolve_t(r);
1041
auto q = determine( r.result );
1043
return resolve_t(r);
1049
case type_ref::t_extr:
1050
switch( pt.extr().intr->get_fun_class() ) {
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 );
1058
return resolve_t(r);
1062
return resolve_t(extr_type(dup));
1066
STATE_FAIL( "unexpected-parametric-fundamental" );
1070
STATE_FAIL( "unreachable" );
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)
1077
void type_identifier::complete_defaults( type_spec & ts ) {
1078
if( !ts.has_known_intrinsic() ) {
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);
1088
auto fc = ts.get_any_fun_class();
1090
case intr_type::f_integer:
1091
ts.default_set<pt_data_bitsize>(platform::natural_integer_size);
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);
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);
1106
ts.default_set<pt_function_access>(intr_type_function::a_bound);
1110
case intr_type::f_tuple:
1111
ts.default_set<pt_pack>(intr_type_tuple::p_normal);
1119
void type_identifier::apply_infer( type_spec & ts ) {
1120
auto fc = ts.get_any_fun_class();
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>();
1128
ts.set<pt_fun_class>( intr_type::f_float );
1130
ts.clear<pt_fun_prototype>();
1131
} else if( fc == intr_type::f_function ) {
1132
auto context = ts.if_get<pt_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);
1144
ts.clear<pt_lvalue>();
1145
ts.clear<pt_literal>();
1147
for( auto & s : ts.sub ) {
1148
auto c = make_shared<type_spec>(*s.type);
1154
type_identifier::resolve_t type_identifier::parameterize_type(
1155
type_ref const & param_type_, type_ref const & apply_, unsigned /*flags*/ ) {
1157
//DEBUG( "PARAMETERIZE_TYPE", param_type_.contains_parametric(), param_type_.is_complete(),
1158
// dump::get( param_type_ ), dump::get( apply_ ) );
1160
if( !param_type_.contains_parametric() || param_type_.is_complete() ) {
1164
auto ps = get_spec( param_type_ );
1166
return resolve_t(ps);
1168
//need to expand target since get_spec might have been from a unexpanded type_spec
1169
auto pes = expand( *ps.result );
1171
return resolve_t(pes);
1173
auto param_type = pes.result;
1175
auto apply = get_spec( apply_ );
1176
if( !apply.okay() ) {
1177
return resolve_t(apply);
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 );
1184
return resolve_t(c);
1186
//DEBUG("POST-EXPAND", dump::get(param_type));
1187
apply_infer(*param_type);
1188
return determine(param_type);
1191
type_identifier::resolve_t type_identifier::parameterize_type(
1192
intr_type const & param_type_, intr_type const & apply_, unsigned /*flags*/ ) {
1194
auto ps = get_spec( param_type_ );
1196
return resolve_t(ps);
1198
auto param_type = make_shared<type_spec>( *ps.result );
1200
auto apply = get_spec( apply_ );
1201
if( !apply.okay() ) {
1202
return resolve_t(apply);
1206
auto c = expand_into( *param_type, *apply.result, empty, df_infer );
1208
return resolve_t(c);
1210
apply_infer(*param_type);
1211
return determine(param_type);
1215
shared_ptr<scope> type_identifier::get_decl_scope() {
1216
return ctx.get_decl_scope();
1219
shared_ptr<scope> type_identifier::get_symbol_scope() {
1220
if( symbol_scope ) {
1221
return symbol_scope;
1223
return ctx.get_decl_scope();
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 );
1230
auto old = symbol_scope;
1235
void type_identifier::pop_function_scope( shared_ptr<scope> sc ) {
167
} //eon type_identifier
b'\\ No newline at end of file'