diff --git a/analyze/aps-bind.c b/analyze/aps-bind.c index 5b6b0daf..491ded81 100644 --- a/analyze/aps-bind.c +++ b/analyze/aps-bind.c @@ -1104,6 +1104,7 @@ static void *activate_pragmas(void *ignore, void *node) { } if (ABSTRACT_APS_tnode_phylum(node) == KEYDeclaration) { Declaration decl=(Declaration)node; + Declaration_info(decl)->is_circular = FALSE; // set default value of is_circular switch (Declaration_KEY(decl)) { case KEYpragma_call: { Symbol pragma_sym = pragma_call_name(decl); diff --git a/analyze/aps-dnc.c b/analyze/aps-dnc.c index 39e1076e..41bc5544 100644 --- a/analyze/aps-dnc.c +++ b/analyze/aps-dnc.c @@ -80,7 +80,7 @@ DEPENDENCY dependency_trans(DEPENDENCY k1, DEPENDENCY k2) (k2 & DEPENDENCY_NOT_JUST_FIBER)) | ((k1 & DEPENDENCY_MAYBE_CARRYING)& (k2 & DEPENDENCY_MAYBE_CARRYING)) | - ((k1 & DEPENDENCY_MAYBE_SIMPLE)& + ((k1 & DEPENDENCY_MAYBE_SIMPLE) | (k2 & DEPENDENCY_MAYBE_SIMPLE)) | SOME_DEPENDENCY); } @@ -1056,11 +1056,119 @@ BOOL decl_is_circular(Declaration d) return direction_is_circular(value_decl_direction(d)); case KEYattribute_decl: return direction_is_circular(attribute_decl_direction(d)); + case KEYformal: + return Declaration_info(d)->is_circular; default: return FALSE; } } +/** + * Utility function that detects if canonical type is circular + * by checking if its inferred signature set includes any of the + * LATTICE types. + * + * @param ctype canonical type + * @return BOOL indicating whether canonical type can be considered circular + */ +static BOOL canonical_type_is_lattice_type(CanonicalType* ctype) { + CanonicalSignatureSet cset = infer_canonical_signatures(ctype); + + int i; + for (i = 0; i < cset->num_elements; i++) { + CanonicalSignature* csig = (CanonicalSignature*)cset->elements[i]; + + // If class declaration extends any of the LATTICE types (UNION_LATTICE, MAKE_LATTICE and etc.) + if (canonical_signature_hierarchy_contains(csig, module_lattice)) { + return TRUE; + } + } + + return FALSE; +} + +/** + * Utility function that detects if use of result of some function call is monotone + * by checking if the result of function call equals the LHS type and is extending + * lattice. + * + * @param sink_type LHS type + * @param expr function call expression + * @param fdecl function declaration + * @return BOOL indicating whether result of some function call is monotone + */ +static BOOL funcall_result_is_monotone_use(Type sink_type, Expression expr, Declaration fdecl) { + Use use = value_use_use(funcall_f(expr)); + TypeEnvironment te = USE_TYPE_ENV(use); + + if (analysis_debug & ADD_EDGE) { + printf("fdecl: %s (lineno %d)\n", decl_name(fdecl), tnode_line_number(expr)); + printf("type environment: "); + print_TypeEnvironment(te, stdout); + printf("\n"); + } + + Type fdecl_type = some_function_decl_type(fdecl); + + // return type should be equal to sink type and be circular + Type fdecl_return_type = type_subst(use, function_type_return_type(fdecl_type)); + + if (analysis_debug & ADD_EDGE) { + printf(" return type: "); + print_Type(fdecl_return_type, stdout); + printf("\n"); + printf(" sink type: "); + print_Type(sink_type, stdout); + printf("\n"); + } + + CanonicalType* fdecl_return_ctype = canonical_type(fdecl_return_type); + CanonicalType* sink_ctype = canonical_type(sink_type); + + return fdecl_return_ctype == sink_ctype && canonical_type_is_lattice_type(fdecl_return_ctype); +} + +/** + * Utility function that detects if use of actual of some function call is monotone + * by checking if formal and actual type are equal and is extending lattice. + * + * @param expr function call expression + * @param actual function call actual expression + * @param fdecl function declaration + * @return BOOL indicating whether use of actual of some function call is monotone + */ +static BOOL funcall_actual_is_monotone_use(Expression expr, Expression actual, Declaration fdecl) { + Use use = value_use_use(funcall_f(expr)); + TypeEnvironment te = USE_TYPE_ENV(use); + + if (analysis_debug & ADD_EDGE) { + printf("fdecl: %s (lineno %d)\n", decl_name(fdecl), tnode_line_number(expr)); + printf("type environment: "); + print_TypeEnvironment(te, stdout); + printf("\n"); + } + + Declaration formal = function_actual_formal(fdecl, actual, expr); + + Type formal_ty = type_subst(use, infer_formal_type(formal)); + Type actual_ty = infer_expr_type(actual); + + if (analysis_debug & ADD_EDGE) { + printf(" formal type: "); + print_Type(formal_ty, stdout); + printf("\n"); + printf(" actual type: "); + print_Type(actual_ty, stdout); + printf("\n"); + } + + CanonicalType* formal_ctype = canonical_type(formal_ty); + CanonicalType* actual_ctype = canonical_type(actual_ty); + + // formal and actual should be equal and be circular + return formal_ctype == actual_ctype && canonical_type_is_lattice_type(formal_ctype); +} + // return true if we are sure this vertex represents an input dependency static BOOL vertex_is_input(VERTEX* v) { @@ -1134,6 +1242,9 @@ void add_edges_to_graph(VERTEX* v1, // if carrying, then we add fiber dependencies. kind &= ~DEPENDENCY_NOT_JUST_FIBER; + + // Fiber dependencies are always monotone. + kind &= ~DEPENDENCY_MAYBE_SIMPLE; for (i=0; i < s->fibers.length; ++i) { FIBER f = s->fibers.array[i]; @@ -1168,7 +1279,7 @@ Declaration attr_ref_node_decl(Expression e) * @param mod modifier to apply to instances found * @param kind whether carrying/non-fiber etc. */ -static void record_expression_dependencies(VERTEX *sink, CONDITION *cond, +static void record_expression_dependencies(VERTEX *sink, Type sink_type, CONDITION *cond, DEPENDENCY kind, MODIFIER *mod, Expression e, AUG_GRAPH *aug_graph) { @@ -1195,14 +1306,16 @@ static void record_expression_dependencies(VERTEX *sink, CONDITION *cond, /* nothing to do */ break; case KEYrepeat: - record_expression_dependencies(sink,cond,kind,mod, + record_expression_dependencies(sink,sink_type,cond,kind,mod, repeat_expr(e),aug_graph); break; case KEYvalue_use: { Declaration decl=Use_info(value_use_use(e))->use_decl; Declaration rdecl; int new_kind = kind; - if (!decl_is_circular(decl)) new_kind |= DEPENDENCY_MAYBE_SIMPLE; + if (!decl_is_circular(decl) && mod == NO_MODIFIER) { + new_kind |= DEPENDENCY_MAYBE_SIMPLE; + } if (decl == NULL) fatal_error("%d: unbound expression",tnode_line_number(e)); if (DECL_IS_LOCAL(decl) && @@ -1231,6 +1344,8 @@ static void record_expression_dependencies(VERTEX *sink, CONDITION *cond, source.attr = decl; source.modifier = mod; if (vertex_is_output(&source)) aps_warning(e,"Dependence on output value"); + // XXX: this needs to be revisited after modifying aps-dnc to not treat functions as procedures + new_kind &= ~DEPENDENCY_MAYBE_SIMPLE; add_edges_to_graph(&source,sink,cond,new_kind,aug_graph); } else { source.node = NULL; @@ -1245,34 +1360,39 @@ static void record_expression_dependencies(VERTEX *sink, CONDITION *cond, { Declaration decl; int new_kind = kind; if ((decl = attr_ref_p(e)) != NULL) { - if (!decl_is_circular(decl)) new_kind |= DEPENDENCY_MAYBE_SIMPLE; else new_kind = kind; + if (!decl_is_circular(decl) && mod == NO_MODIFIER) new_kind |= DEPENDENCY_MAYBE_SIMPLE; else new_kind = kind; source.node = attr_ref_node_decl(e); source.attr = decl; source.modifier = mod; if (vertex_is_output(&source)) aps_warning(e,"Dependence on output value"); add_edges_to_graph(&source,sink,cond,new_kind,aug_graph); } else if ((decl = field_ref_p(e)) != NULL) { - if (!decl_is_circular(decl)) new_kind |= DEPENDENCY_MAYBE_SIMPLE; else new_kind = kind; + if (!decl_is_circular(decl) && mod == NO_MODIFIER) new_kind |= DEPENDENCY_MAYBE_SIMPLE; else new_kind = kind; Expression object = field_ref_object(e); new_mod.field = decl; new_mod.next = mod; // first the dependency on the pointer itself (NOT carrying) - record_expression_dependencies(sink,cond, + record_expression_dependencies(sink,sink_type,cond, new_kind&~DEPENDENCY_MAYBE_CARRYING, NO_MODIFIER,object,aug_graph); // then the dependency on the field (possibly carrying) - record_expression_dependencies(sink,cond,new_kind,&new_mod,object, + record_expression_dependencies(sink,sink_type,cond,new_kind,&new_mod,object, aug_graph); } else if ((decl = local_call_p(e)) != NULL) { - if (!decl_is_circular(decl)) new_kind |= DEPENDENCY_MAYBE_SIMPLE; else new_kind = kind; Declaration result = some_function_decl_result(decl); Expression actual = first_Actual(funcall_actuals(e)); /* first depend on the arguments (not carrying, no fibers) */ if (mod == NO_MODIFIER) { for (;actual!=NULL; actual=Expression_info(actual)->next_actual) { - record_expression_dependencies(sink,cond, + + if (!funcall_actual_is_monotone_use(e, actual, decl)) { + new_kind |= DEPENDENCY_MAYBE_SIMPLE; + } + + record_expression_dependencies(sink,sink_type,cond, new_kind&~DEPENDENCY_MAYBE_CARRYING, NO_MODIFIER,actual,aug_graph); + new_kind = kind; // restore new_kind } } @@ -1281,18 +1401,35 @@ static void record_expression_dependencies(VERTEX *sink, CONDITION *cond, * tnode_line_number(e),decl_name(decl)); */ { + if (!funcall_result_is_monotone_use(sink_type, e, decl)) { + new_kind |= DEPENDENCY_MAYBE_SIMPLE; + } + Declaration proxy = Expression_info(e)->funcall_proxy; source.node = proxy; source.attr = result; source.modifier = mod; if (vertex_is_output(&source)) aps_warning(e,"Dependence on output value"); - add_edges_to_graph(&source,sink,cond,kind,aug_graph); + + // XXX: If we have procedure, this code needs to be revisted. + if (Declaration_KEY(decl) == KEYfunction_decl && some_function_decl_result(decl) == result) { + if (analysis_debug & ADD_EDGE) { + printf("skipped adding a SIMPLE edge between: "); + print_dep_vertex(&source, stdout); + printf("->"); + print_dep_vertex(sink, stdout); + printf("\n"); + } + + new_kind &= ~DEPENDENCY_MAYBE_SIMPLE; + } + add_edges_to_graph(&source,sink,cond,new_kind,aug_graph); } } else { /* some random (external) function call */ Expression actual = first_Actual(funcall_actuals(e)); for (; actual != NULL; actual=Expression_info(actual)->next_actual) { - record_expression_dependencies(sink,cond,kind,mod, + record_expression_dependencies(sink,sink_type,cond,new_kind,mod, actual,aug_graph); } } @@ -1359,6 +1496,8 @@ static void record_lhs_dependencies(Expression lhs, CONDITION *cond, case KEYvalue_use: { Declaration decl = USE_DECL(value_use_use(lhs)); + Use use = value_use_use(lhs); + Type sink_type = type_subst(use, infer_expr_type(lhs)); VERTEX sink; MODIFIER new_mod; @@ -1405,17 +1544,20 @@ static void record_lhs_dependencies(Expression lhs, CONDITION *cond, set_value_for(&sink,rhs,aug_graph); if (vertex_is_input(&sink)) aps_error(lhs,"Assignment of input value"); // don't make error even if not output: local attributes! - record_expression_dependencies(&sink,cond,kind,NULL,rhs,aug_graph); + record_expression_dependencies(&sink,sink_type,cond,kind,NULL,rhs,aug_graph); record_condition_dependencies(&sink,cond,aug_graph); } break; case KEYfuncall: { + Use use = value_use_use(funcall_f(lhs)); + Type sink_type = type_subst(use, infer_expr_type(lhs)); + int new_kind = kind; Declaration field, attr, fdecl, decl; VERTEX sink; if ((field = field_ref_p(lhs)) != NULL) { - if (!decl_is_circular(field)) new_kind |= DEPENDENCY_MAYBE_SIMPLE; else new_kind = kind; + if (!decl_is_circular(field) && mod == NO_MODIFIER) new_kind |= DEPENDENCY_MAYBE_SIMPLE; else new_kind = kind; /* Assignment of a field, or a field of a field */ Expression object = field_ref_object(lhs); MODIFIER new_mod; @@ -1429,16 +1571,16 @@ static void record_lhs_dependencies(Expression lhs, CONDITION *cond, record_lhs_dependencies(object,cond,control_dependency, &new_mod,object,aug_graph); } else if ((attr = attr_ref_p(lhs)) != NULL) { - if (!decl_is_circular(attr)) new_kind |= DEPENDENCY_MAYBE_SIMPLE; else new_kind = kind; + if (!decl_is_circular(attr) && mod == NO_MODIFIER) new_kind |= DEPENDENCY_MAYBE_SIMPLE; else new_kind = kind; sink.node = attr_ref_node_decl(lhs); sink.attr = attr; sink.modifier = mod; set_value_for(&sink,rhs,aug_graph); if (vertex_is_input(&sink)) aps_error(lhs,"Assignment of input value"); - record_expression_dependencies(&sink,cond,kind,NULL,rhs,aug_graph); + record_expression_dependencies(&sink,sink_type,cond,kind,NULL,rhs,aug_graph); record_condition_dependencies(&sink,cond,aug_graph); } else if ((fdecl = local_call_p(lhs)) != NULL) { - if (!decl_is_circular(fdecl)) new_kind |= DEPENDENCY_MAYBE_SIMPLE; else new_kind = kind; + if (!decl_is_circular(fdecl) && mod == NO_MODIFIER) new_kind |= DEPENDENCY_MAYBE_SIMPLE; else new_kind = kind; Declaration result = some_function_decl_result(decl); Declaration proxy = Expression_info(lhs)->funcall_proxy; if (mod == NO_MODIFIER) { @@ -1449,7 +1591,7 @@ static void record_lhs_dependencies(Expression lhs, CONDITION *cond, sink.modifier = mod; set_value_for(&sink,rhs,aug_graph); if (vertex_is_input(&sink)) aps_error(lhs,"Assignment of input value"); - record_expression_dependencies(&sink,cond,new_kind,NULL,rhs,aug_graph); + record_expression_dependencies(&sink,sink_type,cond,new_kind,NULL,rhs,aug_graph); record_condition_dependencies(&sink,cond,aug_graph); } else { Expression actual = first_Actual(funcall_actuals(lhs)); @@ -1506,6 +1648,7 @@ static void *get_edges(void *vaug_graph, void *node) { return NULL; case KEYformal: { Declaration case_stmt = formal_in_case_p(decl); + Type sink_type = infer_formal_type(decl); if (case_stmt != NULL) { Expression expr = some_case_stmt_expr(case_stmt); VERTEX f; @@ -1513,7 +1656,7 @@ static void *get_edges(void *vaug_graph, void *node) { f.attr = decl; f.modifier = NO_MODIFIER; record_condition_dependencies(&f,cond,aug_graph); - record_expression_dependencies(&f,cond,dependency,NO_MODIFIER, + record_expression_dependencies(&f,sink_type,cond,dependency,NO_MODIFIER, expr,aug_graph); } } @@ -1532,10 +1675,10 @@ static void *get_edges(void *vaug_graph, void *node) { case KEYsimple: /* XXX: I don't know I have to do it both ways. */ - record_expression_dependencies(&sink,cond,dependency,NO_MODIFIER, + record_expression_dependencies(&sink,no_type(),cond,dependency,NO_MODIFIER, simple_value(def),aug_graph); sink.node = 0; - record_expression_dependencies(&sink,cond,dependency,NO_MODIFIER, + record_expression_dependencies(&sink,no_type(),cond,dependency,NO_MODIFIER, simple_value(def),aug_graph); if ((cdecl = constructor_call_p(simple_value(def))) != NULL) { FIBERSET fs = fiberset_for(decl,FIBERSET_NORMAL_FINAL); @@ -1578,7 +1721,7 @@ static void *get_edges(void *vaug_graph, void *node) { } break; case KEYcomposite: - record_expression_dependencies(&sink,cond,dependency,NO_MODIFIER, + record_expression_dependencies(&sink,no_type(),cond,dependency,NO_MODIFIER, composite_initial(def),aug_graph); break; } @@ -1622,13 +1765,14 @@ static void *get_edges(void *vaug_graph, void *node) { case KEYif_stmt: { Expression test = if_stmt_cond(decl); + Type sink_type = infer_expr_type(test); VERTEX sink; sink.node = 0; sink.attr = decl; sink.modifier = NO_MODIFIER; record_condition_dependencies(&sink,cond,aug_graph); - record_expression_dependencies(&sink,cond,control_dependency, + record_expression_dependencies(&sink,sink_type,cond,control_dependency, NO_MODIFIER, test, aug_graph); } break; @@ -1638,13 +1782,31 @@ static void *get_edges(void *vaug_graph, void *node) { VERTEX sink; sink.node = 0; sink.modifier = NO_MODIFIER; + + Expression case_expr = some_case_stmt_expr(decl); + BOOL case_expr_is_circular = canonical_type_is_lattice_type(canonical_type(infer_expr_type(case_expr))); + for (m=first_Match(some_case_stmt_matchers(decl)); m; m=MATCH_NEXT(m)) { + + if (case_expr_is_circular) { + Declaration match_formal = match_first_rhs_decl(m); + while (match_formal != NULL) { + // XXX: strictly should look at the parent calls in-between + if (canonical_type_is_lattice_type(canonical_type(infer_formal_type(match_formal)))) { + Declaration_info(match_formal)->is_circular = TRUE; + } + + match_formal = next_rhs_decl(match_formal); + } + } + Expression test = Match_info(m)->match_test; sink.attr = (Declaration)m; + Type sink_type = infer_expr_type(test); record_condition_dependencies(&sink,cond,aug_graph); for (; test != 0; test = Expression_info(test)->next_expr) { - record_expression_dependencies(&sink,cond,control_dependency, + record_expression_dependencies(&sink,sink_type,cond,control_dependency, NO_MODIFIER, test, aug_graph); } } @@ -1653,12 +1815,13 @@ static void *get_edges(void *vaug_graph, void *node) { case KEYfor_in_stmt: { Declaration formal = for_in_stmt_formal(decl); Expression expr = for_in_stmt_seq(decl); + Type formal_type = infer_formal_type(formal); VERTEX f; f.node = 0; f.attr = formal; f.modifier = NO_MODIFIER; record_condition_dependencies(&f,cond,aug_graph); - record_expression_dependencies(&f,cond,dependency,NO_MODIFIER, + record_expression_dependencies(&f,formal_type,cond,dependency,NO_MODIFIER, expr,aug_graph); } break; @@ -1697,13 +1860,14 @@ static void *get_edges(void *vaug_graph, void *node) { { Type ft = some_function_decl_type(fdecl); Declaration f = first_Declaration(function_type_formals(ft)); + Type formal_type = infer_formal_type(f); Expression a = first_Actual(funcall_actuals(e)); for (; f != NULL; f = DECL_NEXT(f), a = EXPR_NEXT(a)) { VERTEX sink; sink.node = proxy; sink.attr = f; sink.modifier = NO_MODIFIER; - record_expression_dependencies(&sink,cond,dependency, + record_expression_dependencies(&sink,formal_type,cond,dependency, NO_MODIFIER,a,aug_graph); record_condition_dependencies(&sink,cond,aug_graph); } diff --git a/analyze/aps-fiber.h b/analyze/aps-fiber.h index 2059dce1..1cc41634 100644 --- a/analyze/aps-fiber.h +++ b/analyze/aps-fiber.h @@ -101,6 +101,7 @@ extern Declaration shared_use_p(Expression); extern Declaration responsible_node_shared_info(void *, struct analysis_state *); extern Declaration formal_in_case_p(Declaration); +Declaration function_actual_formal(Declaration func, Expression actual, Expression call); diff --git a/analyze/aps-info.h b/analyze/aps-info.h index 1d0135f9..ca4f11c3 100644 --- a/analyze/aps-info.h +++ b/analyze/aps-info.h @@ -43,6 +43,7 @@ struct Declaration_info { unsigned decl_flags; void * call_sites; void *analysis_state; + BOOL is_circular; /* boolean indicating if decl is circular */ #define DECL_LHS_FLAG 1 #define DECL_RHS_FLAG 2 #define DECL_OBJECT_FLAG 4 diff --git a/analyze/aps-type.c b/analyze/aps-type.c index b9022163..6fd2c96c 100644 --- a/analyze/aps-type.c +++ b/analyze/aps-type.c @@ -441,6 +441,7 @@ static void* validate_canonicals(void* ignore, void*node) { static Declaration module_TYPE; static Declaration module_PHYLUM; +Declaration module_lattice; static void* set_root_phylum(void *ignore, void *node) { @@ -451,7 +452,7 @@ static void* set_root_phylum(void *ignore, void *node) Declaration d = (Declaration)node; switch (Declaration_KEY(d)) { - case KEYmodule_decl: + case KEYsome_class_decl: { if (module_TYPE == 0 && streq(decl_name(d), "TYPE")) { @@ -461,6 +462,10 @@ static void* set_root_phylum(void *ignore, void *node) { module_PHYLUM = d; } + else if (streq(decl_name(d), "LATTICE")) + { + module_lattice = d; + } return NULL; } diff --git a/analyze/aps-type.h b/analyze/aps-type.h index b1bb07cb..06d42eaf 100644 --- a/analyze/aps-type.h +++ b/analyze/aps-type.h @@ -1,6 +1,9 @@ #ifndef APS_TYPE_H #define APS_TYPE_H +// Lattice module declaration. +extern Declaration module_lattice; + extern Type function_type_return_type(Type); /* We use local type inference a la Turner and Pierce diff --git a/analyze/canonical-signature.c b/analyze/canonical-signature.c index fea01ac9..8e0dca49 100644 --- a/analyze/canonical-signature.c +++ b/analyze/canonical-signature.c @@ -482,6 +482,17 @@ static CanonicalSignature* join_canonical_signature_actuals(CanonicalType *sourc struct Canonical_use_type *ctype_use = (struct Canonical_use_type *)source_ctype; Declaration tdecl = ctype_use->decl; + switch (Declaration_KEY(tdecl)) + { + case KEYsome_type_decl: + break; + default: + // short-circuit. + // only when the source declaration of canonical type is some kind of + // type declaration then "join" (or simplifying) would be possible. + return canonical_sig; + } + Declaration mdecl = USE_DECL(module_use_use(type_inst_module(some_type_decl_type(tdecl)))); CanonicalType **substituted_actuals = (CanonicalType **)alloca(canonical_sig->num_actuals); @@ -693,3 +704,41 @@ void initialize_canonical_signature(Declaration module_TYPE_decl, Declaration mo initialized = true; } + +/** + * Given a signature, it returns whether it contains module declaration + * @param sig signature + * @param module_or_class_decl module or class declaration + * @return boolean indicating if module is in the type hierarchy of signature + */ +bool signature_hierarchy_contains(Signature sig, Declaration module_or_class_decl) +{ + switch (Signature_KEY(sig)) + { + case KEYsig_inst: + Declaration some_mdecl = USE_DECL(class_use_use(sig_inst_class(sig))); + return some_mdecl == module_or_class_decl || + signature_hierarchy_contains(some_class_decl_parent(some_mdecl), module_or_class_decl); + case KEYmult_sig: + return signature_hierarchy_contains(mult_sig_sig1(sig), module_or_class_decl) || + signature_hierarchy_contains(mult_sig_sig2(sig), module_or_class_decl); + case KEYsig_use: + return USE_DECL(sig_use_use(sig)) == module_or_class_decl; + case KEYno_sig: + case KEYfixed_sig: + return false; + } +} + +/** + * Given a canonical signature, it returns whether it contains module declaration + * @param csig canonical signature + * @param module_or_class_decl module or class declaration + * @return boolean indicating if module is in the type hierarchy of signature + */ +bool canonical_signature_hierarchy_contains(CanonicalSignature* csig, Declaration module_or_class_decl) +{ + if (csig->source_class == module_or_class_decl) return true; + + return signature_hierarchy_contains(some_class_decl_parent(csig->source_class), module_or_class_decl); +} diff --git a/analyze/canonical-signature.h b/analyze/canonical-signature.h index fdf7742c..b6b36ee4 100644 --- a/analyze/canonical-signature.h +++ b/analyze/canonical-signature.h @@ -1,6 +1,9 @@ #ifndef CANONICAL_SIGNATURE_H #define CANONICAL_SIGNATURE_H +#include +#include "canonical-type.h" + struct CanonicalSignature_type { bool is_input; @@ -42,4 +45,12 @@ void print_canonical_signature(void *untyped, FILE *f); */ void print_canonical_signature_set(void *untyped, FILE *f); +/** + * Given a canonical signature, it returns whether it contains module declaration + * @param csig canonical signature + * @param module_or_class_decl module or class declaration + * @return boolean indicating if module is in the type hierarchy of signature + */ +bool canonical_signature_hierarchy_contains(CanonicalSignature* csig, Declaration module_or_class_decl); + #endif diff --git a/analyze/canonical-type.c b/analyze/canonical-type.c index df01d7b5..424772ce 100755 --- a/analyze/canonical-type.c +++ b/analyze/canonical-type.c @@ -371,6 +371,8 @@ static CanonicalType *canonical_type_use(Use use) case KEYfunction_type: return canonical_type(some_type_decl_type(td)); + case KEYremote_type: + return canonical_type(remote_type_nodetype(some_type_decl_type(td))); default: fatal_error("Unknown type use_decl type key %d", (int)Type_KEY(some_type_decl_type(td))); return NULL; @@ -514,6 +516,9 @@ CanonicalType *canonical_type(Type t) } case KEYfunction_type: return canonical_type_function(t); + case KEYno_type: + // canonical type representation of no-type is itself. + return (CanonicalType*)t; default: aps_error(t, "Case of type %d is not implemented in canonical_type()", (int)Type_KEY(t)); return NULL; diff --git a/examples/first.aps b/examples/first.aps index 67054d97..a76f44cc 100644 --- a/examples/first.aps +++ b/examples/first.aps @@ -67,11 +67,11 @@ module FIRST[T :: var GRAMMAR[]] extends T begin end; - var function contains_epsilon(s_set: Symbols) :Boolean begin + function contains_epsilon(s_set: Symbols) :Boolean begin result := Symbols$member(epsilon, s_set); end; - var function black_dot(s1 :Symbols; s2 :Symbols) : Symbols begin + function black_dot(s1 :SymbolLattice; s2 :SymbolLattice) : SymbolLattice begin if contains_epsilon(s1) then result := (s1 /\~ { epsilon }) \/ s2; else