diff --git a/src/operators.c b/src/operators.c index 32f1ca487b2aae391468d009fc7559cbf6b73f2b..3616d43c2d02a99c778bd76c58d405a05c64daa8 100644 --- a/src/operators.c +++ b/src/operators.c @@ -1080,10 +1080,16 @@ void o_check_soft_cast(struct svalue *s, struct pike_type *type) */ struct pike_type *sval_type = get_type_of_svalue(s); struct pike_string *t1; - struct pike_string *t2; + struct string_builder s; char *fname = "__soft-cast"; + ONERROR tmp0; ONERROR tmp1; - ONERROR tmp2; + + init_string_builder(&s, 0); + + SET_ONERROR(tmp0, free_string_builder, &s); + + string_builder_explain_nonmatching_types(&s, type, sval_type); if (Pike_fp->current_program) { /* Look up the function-name */ @@ -1096,19 +1102,14 @@ void o_check_soft_cast(struct svalue *s, struct pike_type *type) t1 = describe_type(type); SET_ONERROR(tmp1, do_free_string, t1); - t2 = describe_type(sval_type); - SET_ONERROR(tmp2, do_free_string, t2); - free_type(sval_type); bad_arg_error(NULL, Pike_sp-1, 1, 1, t1->str, Pike_sp-1, - "%s(): Soft cast failed. Expected %s, got %s\n", - fname, t1->str, t2->str); + "%s(): Soft cast failed.\n%S", + fname, s.s); /* NOT_REACHED */ - UNSET_ONERROR(tmp2); - UNSET_ONERROR(tmp1); - free_string(t2); - free_string(t1); + CALL_AND_UNSET_ONERROR(tmp1); + CALL_AND_UNSET_ONERROR(tmp0); } } diff --git a/src/pike_types.c b/src/pike_types.c index a66677ecf5f0e9f1d2f7b8230298beca34f3782c..d09ef2b0418573f5bdbfbf8d36e2d51804c9a663 100644 --- a/src/pike_types.c +++ b/src/pike_types.c @@ -7,8 +7,8 @@ #include "global.h" #include <ctype.h> #include "svalue.h" -#include "pike_types.h" #include "stralloc.h" +#include "pike_types.h" #include "stuff.h" #include "array.h" #include "program.h" @@ -7679,6 +7679,50 @@ void yyexplain_nonmatching_types(int severity_level, END_CYCLIC(); } +/* FIXME: Code duplication! */ +void string_builder_explain_nonmatching_types(struct string_builder *s, + struct pike_type *type_a, + struct pike_type *type_b) +{ + DECLARE_CYCLIC(); + + implements_a=0; + implements_b=0; + implements_mode=0; + + /* Note the argument order. */ + pike_types_le(type_b, type_a); + +#if 0 + if(!(implements_a && implements_b && + type_a->str[0]==T_OBJECT && + type_b->str[0]==T_OBJECT)) +#endif /* 0 */ + { + ref_push_type_value(type_a); + ref_push_type_value(type_b); + string_builder_sprintf(s, + "Expected: %O.\n" + "Got : %O.\n", + Pike_sp-2, Pike_sp-1); + } + + /* Protect against circularities. */ + if (BEGIN_CYCLIC(type_a, type_b)) { + END_CYCLIC(); + return; + } + SET_CYCLIC_RET(1); + + if(implements_a && implements_b) { + if (implements_mode) { + string_builder_explain_not_implements(s, implements_a, implements_b); + } else { + string_builder_explain_not_compatible(s, implements_a, implements_b); + } + } + END_CYCLIC(); +} /******/ diff --git a/src/pike_types.h b/src/pike_types.h index 277ec34b82e633b3cc558f3b63894af61ec3cf80..6feee0a0259ca538d15b409f25c8e4e83723c87d 100644 --- a/src/pike_types.h +++ b/src/pike_types.h @@ -304,6 +304,9 @@ void yyexplain_nonmatching_types(int severity_level, struct pike_string *b_file, INT32 b_line, struct pike_type *type_b); +void string_builder_explain_nonmatching_types(struct string_builder *s, + struct pike_type *type_a, + struct pike_type *type_b); struct pike_type *debug_make_pike_type(const char *t); struct pike_string *type_to_string(struct pike_type *t); int pike_type_allow_premature_toss(struct pike_type *type); diff --git a/src/program.c b/src/program.c index 100ff0ec9c59cee2a673b6d3be3eb0bf48aaca5a..f210607d6bebdc3e02df7902b140ec22ad1d8b18 100644 --- a/src/program.c +++ b/src/program.c @@ -11440,6 +11440,134 @@ void yyexplain_not_implements(int severity_level, END_CYCLIC(); } +/* FIXME: Code duplication of yyexplain_not_compatible() above! */ +/* Explains why a is not compatible with b */ +void string_builder_explain_not_compatible(struct string_builder *s, + struct program *a, + struct program *b) +{ + int e; + struct pike_string *init_string = findstring("__INIT"); + int res = 1; + DECLARE_CYCLIC(); + + /* Optimize the loop somewhat */ + if (a->num_identifier_references < b->num_identifier_references) { + struct program *tmp = a; + a = b; + b = tmp; + } + + if (BEGIN_CYCLIC(a, b)) { + END_CYCLIC(); + return; + } + SET_CYCLIC_RET(1); + + for(e=0;e<b->num_identifier_references;e++) + { + struct identifier *bid; + int i; + if (b->identifier_references[e].id_flags & (ID_PROTECTED|ID_HIDDEN)) + continue; /* Skip protected & hidden */ + + /* FIXME: What if they aren't protected & hidden in a? */ + + bid = ID_FROM_INT(b,e); + if(init_string == bid->name) continue; /* Skip __INIT */ + i = find_shared_string_identifier(bid->name,a); + if (i == -1) { + continue; /* It's ok... */ + } + + /* Note: Uses weaker check for constant integers. */ + if(((bid->run_time_type != PIKE_T_INT) || + (ID_FROM_INT(a, i)->run_time_type != PIKE_T_INT)) && + !match_types(ID_FROM_INT(a,i)->type, bid->type)) { + ref_push_program(a); + ref_push_program(b); + ref_push_type_value(ID_FROM_INT(a, i)->type); + ref_push_type_value(bid->type); + string_builder_sprintf(s, + "Identifier %S in %O is incompatible with " + "the same in %O.\n" + "Expected: %O\n" + "Got : %O\n", + bid->name, Pike_sp-4, + Pike_sp-3, + Pike_sp-2, + Pike_sp-1); + pop_n_elems(4); + } + } + END_CYCLIC(); + return; +} + +/* FIXME: code duplication of yyexplain_not_implements() above! */ +/* Explains why a does not implement b */ +void string_builder_explain_not_implements(struct string_builder *s, + struct program *a, + struct program *b) +{ + int e; + struct pike_string *init_string = findstring("__INIT"); + DECLARE_CYCLIC(); + + if (BEGIN_CYCLIC(a, b)) { + END_CYCLIC(); + return; + } + SET_CYCLIC_RET(1); + + for(e=0;e<b->num_identifier_references;e++) + { + struct identifier *bid; + int i; + if (b->identifier_references[e].id_flags & (ID_PROTECTED|ID_HIDDEN)) + continue; /* Skip protected & hidden */ + bid = ID_FROM_INT(b,e); + if(init_string == bid->name) continue; /* Skip __INIT */ + i = find_shared_string_identifier(bid->name,a); + if (i == -1) { + if (b->identifier_references[e].id_flags & (ID_OPTIONAL)) + continue; /* It's ok... */ + ref_push_type_value(bid->type); + string_builder_sprintf(s, + "Missing identifier %S.\n" + "Expected: %O.\n", + bid->name, Pike_sp-1); + pop_stack(); + continue; + } + + if (!pike_types_le(bid->type, ID_FROM_INT(a, i)->type)) { + ref_push_type_value(bid->type); + ref_push_type_value(ID_FROM_INT(a, i)->type); + if(!match_types(ID_FROM_INT(a,i)->type, bid->type)) { + string_builder_sprintf(s, + "Type of identifier %S does not match.\n" + "Expected: %O.\n" + "Got : %O.\n", + bid->name, + Pike_sp-2, + Pike_sp-1); + } else { + string_builder_sprintf(s, + "Type of identifier %S is not strictly compatible.", + "Expected: %O.\n" + "Got : %O.\n", + bid->name, + Pike_sp-2, + Pike_sp-1); + } + pop_n_elems(2); + continue; + } + } + END_CYCLIC(); +} + PMOD_EXPORT void *parent_storage(int depth) { struct external_variable_context loc; diff --git a/src/program.h b/src/program.h index 9e1f5f6829bb6d850f90f751aaa5e7f25b99bb7e..488337ebfc7e01e8ea4d5a44322437fa92096a0e 100644 --- a/src/program.h +++ b/src/program.h @@ -1044,6 +1044,12 @@ void yyexplain_not_compatible(int severity_level, struct program *a, struct program *b); void yyexplain_not_implements(int severity_level, struct program *a, struct program *b); +void string_builder_explain_not_compatible(struct string_builder *s, + struct program *a, + struct program *b); +void string_builder_explain_not_implements(struct string_builder *s, + struct program *a, + struct program *b); PMOD_EXPORT void *parent_storage(int depth); PMOD_EXPORT void change_compiler_compatibility(int major, int minor); void make_area_executable (char *start, size_t len);