diff --git a/analyze/aps-bind.c b/analyze/aps-bind.c index 5b6b0da..cac4c15 100644 --- a/analyze/aps-bind.c +++ b/analyze/aps-bind.c @@ -42,8 +42,8 @@ struct env_item { }; typedef struct env_item *SCOPE; -static Declaration module_TYPE; -static Declaration module_PHYLUM; +Declaration module_TYPE; +Declaration module_PHYLUM; static TypeEnvironment current_type_env = 0; diff --git a/analyze/aps-bind.h b/analyze/aps-bind.h index 82ee8fa..f5e38b4 100644 --- a/analyze/aps-bind.h +++ b/analyze/aps-bind.h @@ -33,4 +33,7 @@ extern int decl_namespaces(Declaration d); extern int bind_debug; #define PRAGMA_ACTIVATION 1 +extern Declaration module_TYPE; +extern Declaration module_PHYLUM; + #endif diff --git a/analyze/aps-type.c b/analyze/aps-type.c index c09dce2..4d988ef 100644 --- a/analyze/aps-type.c +++ b/analyze/aps-type.c @@ -495,9 +495,6 @@ static void* validate_canonicals(void* ignore, void*node) { return node; } -static Declaration module_TYPE; -static Declaration module_PHYLUM; - static void* set_root_phylum(void *ignore, void *node) { switch (ABSTRACT_APS_tnode_phylum(node)) diff --git a/analyze/canonical-signature.c b/analyze/canonical-signature.c index fea01ac..9573a49 100644 --- a/analyze/canonical-signature.c +++ b/analyze/canonical-signature.c @@ -10,8 +10,6 @@ static CanonicalSignatureSet from_declaration(Declaration decl); static CanonicalSignatureSet substitute_canonical_signature_set_actuals(CanonicalType* source, CanonicalSignatureSet sig_set); static int canonical_signature_compare(CanonicalSignature *sig1, CanonicalSignature *sig2); -static Declaration module_TYPE; -static Declaration module_PHYLUM; static bool initialized = false; /** @@ -352,9 +350,9 @@ static int canonical_signature_compare(CanonicalSignature *sig1, CanonicalSignat return sig1->is_var - sig2->is_var; } - if (tnode_line_number(sig1->source_class) != tnode_line_number(sig2->source_class)) + if (sig1->source_class != sig2->source_class) { - return tnode_line_number(sig1->source_class) - tnode_line_number(sig2->source_class); + return (sig1->source_class > sig2->source_class) ? 1 : -1; } if (sig1->num_actuals != sig2->num_actuals) diff --git a/analyze/canonical-type.c b/analyze/canonical-type.c index e6860d5..e74e347 100755 --- a/analyze/canonical-type.c +++ b/analyze/canonical-type.c @@ -1006,9 +1006,12 @@ CanonicalType *canonical_type_join(CanonicalType *ctype_outer, CanonicalType *ct * Comparator for two canonical types * @param ctype1 first canonical type * @param ctype2 second canonical type + * @param ctype1_mdecl_result Result decl from the source (inherited) module, or NULL + * @param ctype2_mdecl_result Result decl from the target (implementing) module, or NULL * @return integer value representing the comparison */ -int canonical_type_compare(CanonicalType *ctype1, CanonicalType *ctype2) +int canonical_type_compare2(CanonicalType *ctype1, CanonicalType *ctype2, + Declaration ctype1_mdecl_result, Declaration ctype2_mdecl_result) { if (ctype1->key != ctype2->key) { @@ -1022,19 +1025,23 @@ int canonical_type_compare(CanonicalType *ctype1, CanonicalType *ctype2) struct Canonical_use_type *canonical_use_type1 = (struct Canonical_use_type *)ctype1; struct Canonical_use_type *canonical_use_type2 = (struct Canonical_use_type *)ctype2; - return tnode_line_number(canonical_use_type1->decl) - tnode_line_number(canonical_use_type2->decl); + Declaration d1 = (ctype1_mdecl_result != NULL && canonical_use_type1->decl == ctype1_mdecl_result) ? ctype2_mdecl_result : canonical_use_type1->decl; + Declaration d2 = canonical_use_type2->decl; + return (d1 > d2) ? 1 : (d1 < d2) ? -1 : 0; } case KEY_CANONICAL_QUAL: { struct Canonical_qual_type *canonical_qual_type1 = (struct Canonical_qual_type *)ctype1; struct Canonical_qual_type *canonical_qual_type2 = (struct Canonical_qual_type *)ctype2; - if (tnode_line_number(canonical_qual_type1->decl) != tnode_line_number(canonical_qual_type2->decl)) + Declaration d1 = (ctype1_mdecl_result != NULL && canonical_qual_type1->decl == ctype1_mdecl_result) ? ctype2_mdecl_result : canonical_qual_type1->decl; + Declaration d2 = canonical_qual_type2->decl; + if (d1 != d2) { - return tnode_line_number(canonical_qual_type1->decl) - tnode_line_number(canonical_qual_type2->decl); + return (d1 > d2) ? 1 : -1; } - return canonical_type_compare(canonical_qual_type1->source, canonical_qual_type2->source); + return canonical_type_compare2(canonical_qual_type1->source, canonical_qual_type2->source, ctype1_mdecl_result, ctype2_mdecl_result); } case KEY_CANONICAL_FUNC: { @@ -1043,10 +1050,10 @@ int canonical_type_compare(CanonicalType *ctype1, CanonicalType *ctype2) if (canonical_function_type1->num_formals != canonical_function_type2->num_formals) { - return canonical_function_type1->num_formals - canonical_function_type2->num_formals > 0 ? 1 : -1; + return (canonical_function_type1->num_formals > canonical_function_type2->num_formals) ? 1 : -1; } - int return_type_comp = canonical_type_compare(canonical_function_type1->return_type, canonical_function_type2->return_type); + int return_type_comp = canonical_type_compare2(canonical_function_type1->return_type, canonical_function_type2->return_type, ctype1_mdecl_result, ctype2_mdecl_result); if (return_type_comp != 0) { return return_type_comp; @@ -1055,7 +1062,7 @@ int canonical_type_compare(CanonicalType *ctype1, CanonicalType *ctype2) int i; for (i = 0; i < canonical_function_type1->num_formals; i++) { - int formal_type_comp = canonical_type_compare(canonical_function_type1->param_types[i], canonical_function_type2->param_types[i]); + int formal_type_comp = canonical_type_compare2(canonical_function_type1->param_types[i], canonical_function_type2->param_types[i], ctype1_mdecl_result, ctype2_mdecl_result); if (formal_type_comp != 0) { return formal_type_comp; @@ -1065,7 +1072,7 @@ int canonical_type_compare(CanonicalType *ctype1, CanonicalType *ctype2) return 0; } default: - fatal_error("canonical_type_compare failed"); + fatal_error("canonical_type_compare2 failed"); return 0; } } diff --git a/analyze/canonical-type.h b/analyze/canonical-type.h index 6833816..8d616f2 100755 --- a/analyze/canonical-type.h +++ b/analyze/canonical-type.h @@ -65,13 +65,29 @@ CanonicalType *canonical_type_join(CanonicalType *ctype_outer, CanonicalType *ct */ CanonicalType *new_canonical_type_use(Declaration decl); +/** + * Compares two canonical types with Result-decl substitution. + * The inherited module's Result maps to the implementing module's Result. + * @param ctype1 Canonical type to compare + * @param ctype2 Canonical type to compare against + * @param ctype1_mdecl_result Result decl of ctype1's enclosing module + * @param ctype2_mdecl_result Result decl of ctype2's enclosing module + * @return Integer value representing comparison of two canonical types + */ +int canonical_type_compare2(CanonicalType *ctype1, CanonicalType *ctype2, + Declaration ctype1_mdecl_result, + Declaration ctype2_mdecl_result); + /** * Compares two canonical types - * @param ctype1 Canonical type A - * @param ctype2 Canonical type B + * @param ctype1 Canonical type to compare + * @param ctype2 Canonical type to compare against * @return Integer value representing comparison of two canonical types */ -int canonical_type_compare(CanonicalType *ctype1, CanonicalType *ctype2); +static inline int canonical_type_compare(CanonicalType *ctype1, CanonicalType *ctype2) +{ + return canonical_type_compare2(ctype1, ctype2, NULL, NULL); +} /** * Given a canonical type, it returns a Declaration diff --git a/aps2scala/dump-scala.cc b/aps2scala/dump-scala.cc index c4e8750..b3910da 100644 --- a/aps2scala/dump-scala.cc +++ b/aps2scala/dump-scala.cc @@ -181,10 +181,10 @@ void dump_formal(Declaration formal, ostream&os) if (KEYseq_formal == Declaration_KEY(formal)) os << "*"; } -void dump_function_prototype(string name, Type ft, bool dump_anchor_actual, ostream& oss) +void dump_function_prototype(string name, Type ft, bool dump_anchor_actual, bool override_needed, ostream& oss) { - oss << indent() << "val v_" << name << " = f_" << name << " _;\n"; - oss << indent() << "def f_" << name << "("; + oss << indent() << (override_needed ? "override " : "") << "val v_" << name << " = f_" << name << " _;\n"; + oss << indent() << (override_needed ? "override " : "") << "def f_" << name << "("; bool started = false; Declarations formals = function_type_formals(ft); @@ -1392,7 +1392,7 @@ static void dump_scala_pattern_function( if (!body) { // the constructor function: - dump_function_prototype(name,ft,dump_anchor_actual,oss); + dump_function_prototype(name,ft,dump_anchor_actual,false /* override_needed */,oss); oss << " = c_" << name << args; if (is_syntax) oss << ".register"; oss << ";\n"; @@ -1451,6 +1451,78 @@ void dump_scala_Declaration_header(Declaration decl, ostream& oss) } } +// Recursive helper function to check given a surrounding declaration (module_decl, class_decl or type_decl) +// if it contains a function declaration that matches the given name and return type +// if true then override would be needed otherwise not needed +static void type_has_service_function(Declaration decl, Symbol fdecl_name, vector& found_decls) { + switch (Declaration_KEY(decl)) { + case KEYsome_type_decl: { + Type type = some_type_decl_type(decl); + switch (Type_KEY(type)) + { + case KEYno_type: { + bool is_phylum = Declaration_KEY(decl) == KEYphylum_decl; + return type_has_service_function(is_phylum ? module_PHYLUM : module_TYPE, fdecl_name, found_decls); + } + case KEYtype_use: + return type_has_service_function(canonical_type_decl(canonical_type(type)), fdecl_name, found_decls); + case KEYtype_inst: + return type_has_service_function(USE_DECL(module_use_use(type_inst_module(type))), fdecl_name, found_decls); + default: + break; + } + } + case KEYsome_class_decl: { + Block body = some_class_decl_contents(decl); + Declaration item; + for (item = first_Declaration(block_body(body)); item != NULL; item = DECL_NEXT(item)) { + switch (Declaration_KEY(item)) { + case KEYsome_function_decl: + if (def_name(some_function_decl_def(item)) == fdecl_name) { + found_decls.push_back(item); + } + + break; + default: + break; + } + } + + if (decl == module_PHYLUM || decl == module_TYPE) { + return; + } else { + type_has_service_function(some_class_decl_result_type(decl), fdecl_name, found_decls); + } + } + default: + break; + } +} + +Declaration get_enclosing_some_class_decl(Declaration source) { + void* node = (void*)source; + while (node != NULL) { + switch (ABSTRACT_APS_tnode_phylum(node)) { + case KEYDeclaration: { + Declaration decl = (Declaration) node; + switch (Declaration_KEY(decl)) { + case KEYsome_class_decl: + return decl; + default: + break; + } + break; + } + default: + break; + } + + node = tnode_parent(node); + } + + return NULL; +} + void dump_scala_Declaration(Declaration decl,ostream& oss) { const char *name = 0; @@ -1922,7 +1994,44 @@ void dump_scala_Declaration(Declaration decl,ostream& oss) Type fty = function_decl_type(decl); Declaration rdecl = first_Declaration(function_type_return_values(fty)); Block b = function_decl_body(decl); - dump_function_prototype(name,fty,false /* dump_anchor_actual */,oss); + Declaration mdecl = get_enclosing_some_class_decl(decl); + bool override_needed = false; + if (mdecl != NULL) { + vector found_fdecls; + type_has_service_function(some_class_decl_result_type(mdecl), def_name(declaration_def(decl)), found_fdecls); + + auto cftype2 = (struct Canonical_function_type *)canonical_type(fty); + // Result declaration of the current (implementing) module + Declaration current_result = some_class_decl_result_type(mdecl); + for (auto& found_fdecl : found_fdecls) { + auto cftype1 = (struct Canonical_function_type *)canonical_type(some_function_decl_type(found_fdecl)); + // Result declaration of the inherited (source) module + Declaration found_mdecl = get_enclosing_some_class_decl(found_fdecl); + Declaration ctype1_mdecl_result = found_mdecl ? some_class_decl_result_type(found_mdecl) : NULL; + if (cftype1->num_formals == cftype2->num_formals) { + bool formals_type_match = true; + for (int i = 0; i < cftype1->num_formals; ++i) { + if (canonical_type_compare2(cftype1->param_types[i], cftype2->param_types[i], + ctype1_mdecl_result, current_result) != 0) { + formals_type_match = false; + } + } + + if (formals_type_match) { + if (canonical_type_compare2(cftype1->return_type, cftype2->return_type, + ctype1_mdecl_result, current_result) == 0) { + override_needed = true; + break; + } else { + aps_error(decl, "Function %s has same name as inherited function but different return type; overriding not possible since return types are incompatible", decl_name(decl)); + return; + } + } + } + } + } + + dump_function_prototype(name, fty, false /* dump_anchor_actual */, override_needed, oss); // three kinds of definitions: // 1. the whole thing: a non-empty body: