Rémi Bernon : widl: Support partially specialized parameterized type.

Alexandre Julliard julliard at winehq.org
Wed Feb 17 16:23:34 CST 2021


Module: wine
Branch: master
Commit: d5bf8f4e8a0c6f87c18580d6699c2f91614a4bf8
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=d5bf8f4e8a0c6f87c18580d6699c2f91614a4bf8

Author: Rémi Bernon <rbernon at codeweavers.com>
Date:   Wed Feb 17 19:33:34 2021 +0100

widl: Support partially specialized parameterized type.

This allows parameterized types to reference each other with a different
set of parameters. This is required for instance for IIterable<T>, that
needs to reference IIterator<T>.

The partial specialization is recorded by adding a new parameterized
type, referencing the original one as its template. The parameterized
type chain will be resolved all at once when the type is declared.

Signed-off-by: Rémi Bernon <rbernon at codeweavers.com>
Signed-off-by: Jacek Caban <jacek at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 include/windows.foundation.idl |  9 +++++++++
 tools/widl/parser.y            | 41 +++++++++++++++++++++++++++++++++++++++++
 tools/widl/typetree.c          | 41 ++++++++++++++++++++++++++++++++++++++---
 tools/widl/typetree.h          |  3 +++
 tools/widl/widltypes.h         |  1 +
 5 files changed, 92 insertions(+), 3 deletions(-)

diff --git a/include/windows.foundation.idl b/include/windows.foundation.idl
index ab7c4753c3b..5f7a49c38e4 100644
--- a/include/windows.foundation.idl
+++ b/include/windows.foundation.idl
@@ -127,6 +127,15 @@ namespace Windows {
                 HRESULT GetMany([in] UINT32 count, [out] T *items, [out, retval] UINT32 *value);
             }
 
+            [
+                contract(Windows.Foundation.FoundationContract, 1.0),
+                uuid(faa585ea-6214-4217-afda-7f46de5869b3)
+            ]
+            interface IIterable<T> : IInspectable
+            {
+                HRESULT First([out, retval] Windows.Foundation.Collections.IIterator<T> **value);
+            }
+
             [
                 contract(Windows.Foundation.FoundationContract, 1.0),
                 uuid(bbe1fa4c-b0e3-4583-baef-1f1b2e483e56)
diff --git a/tools/widl/parser.y b/tools/widl/parser.y
index 31ee9405455..58ae8c624dc 100644
--- a/tools/widl/parser.y
+++ b/tools/widl/parser.y
@@ -291,6 +291,9 @@ static typelib_t *current_typelib;
 %type <type> type unqualified_type qualified_type
 %type <type> type_parameter
 %type <typeref_list> type_parameters
+%type <type> parameterized_type
+%type <type> parameterized_type_arg
+%type <typeref_list> parameterized_type_args
 %type <typeref> class_interface
 %type <typeref_list> class_interfaces
 %type <typeref_list> requires required_types
@@ -912,6 +915,24 @@ qualified_type:
 	| namespace_pfx typename		{ $$ = find_type_or_error($1, $2); }
 	;
 
+parameterized_type: qualified_type '<' parameterized_type_args '>'
+						{ $$ = find_parameterized_type($1, $3); }
+	;
+
+parameterized_type_arg:
+	  base_type				{ $$ = $1; }
+	| qualified_type			{ $$ = $1; }
+	| qualified_type '*'			{ $$ = type_new_pointer($1); }
+	| parameterized_type			{ $$ = $1; }
+	| parameterized_type '*'		{ $$ = type_new_pointer($1); }
+	;
+
+parameterized_type_args:
+	  parameterized_type_arg		{ $$ = append_typeref(NULL, make_typeref($1)); }
+	| parameterized_type_args ',' parameterized_type_arg
+						{ $$ = append_typeref($1, make_typeref($3)); }
+	;
+
 coclass:  tCOCLASS typename			{ $$ = type_coclass_declare($2); }
 	;
 
@@ -968,6 +989,7 @@ dispinterfacedef:
 
 inherit:					{ $$ = NULL; }
 	| ':' qualified_type                    { $$ = $2; }
+	| ':' parameterized_type		{ $$ = $2; }
 	;
 
 type_parameter: typename			{ $$ = get_type(TYPE_PARAMETER, $1, parameters_namespace, 0); }
@@ -986,7 +1008,9 @@ interface:
 
 required_types:
 	  qualified_type			{ $$ = append_typeref(NULL, make_typeref($1)); }
+	| parameterized_type			{ $$ = append_typeref(NULL, make_typeref($1)); }
 	| required_types ',' qualified_type	{ $$ = append_typeref($1, make_typeref($3)); }
+	| required_types ',' parameterized_type	{ $$ = append_typeref($1, make_typeref($3)); }
 
 requires:					{ $$ = NULL; }
 	| tREQUIRES required_types		{ $$ = $2; }
@@ -1210,6 +1234,7 @@ unqualified_type:
 type:
 	  unqualified_type
 	| namespace_pfx typename		{ $$ = find_type_or_error($1, $2); }
+	| parameterized_type			{ $$ = $1; }
 	;
 
 typedef: m_attributes tTYPEDEF m_attributes decl_spec declarator_list
@@ -3255,3 +3280,19 @@ void init_loc_info(loc_info_t *i)
     i->line_number = line_number;
     i->near_text = parser_text;
 }
+
+type_t *find_parameterized_type(type_t *type, typeref_list_t *params)
+{
+    char *name = format_parameterized_type_name(type, params);
+
+    if (parameters_namespace)
+    {
+        assert(type->type_type == TYPE_PARAMETERIZED_TYPE);
+        type = type_parameterized_type_specialize_partial(type, params);
+    }
+    /* FIXME: If not in another parameterized type, we'll have to look for the declared specialization. */
+    else error_loc("parameterized type '%s' not declared\n", name);
+
+    free(name);
+    return type;
+}
diff --git a/tools/widl/typetree.c b/tools/widl/typetree.c
index 3071307b353..a31bd383169 100644
--- a/tools/widl/typetree.c
+++ b/tools/widl/typetree.c
@@ -100,13 +100,40 @@ static size_t append_namespace(char **buf, size_t *len, size_t pos, struct names
     return n;
 }
 
+static size_t append_namespaces(char **buf, size_t *len, size_t pos, struct namespace *namespace, const char *prefix,
+                                const char *separator, const char *suffix, const char *abi_prefix)
+{
+    size_t n = 0;
+    n += strappend(buf, len, pos + n, "%s", prefix);
+    n += append_namespace(buf, len, pos + n, namespace, separator, abi_prefix);
+    n += strappend(buf, len, pos + n, "%s", suffix);
+    return n;
+}
+
 char *format_namespace(struct namespace *namespace, const char *prefix, const char *separator, const char *suffix, const char *abi_prefix)
+{
+    size_t len = 0;
+    char *buf = NULL;
+    append_namespaces(&buf, &len, 0, namespace, prefix, separator, suffix, abi_prefix);
+    return buf;
+}
+
+char *format_parameterized_type_name(type_t *type, typeref_list_t *params)
 {
     size_t len = 0, pos = 0;
     char *buf = NULL;
-    pos += strappend(&buf, &len, pos, "%s", prefix);
-    pos += append_namespace(&buf, &len, pos, namespace, separator, abi_prefix);
-    pos += strappend(&buf, &len, pos, "%s", suffix);
+    typeref_t *ref;
+
+    pos += strappend(&buf, &len, pos, "%s<", type->name);
+    if (params) LIST_FOR_EACH_ENTRY(ref, params, typeref_t, entry)
+    {
+        for (type = ref->type; type->type_type == TYPE_POINTER; type = type_pointer_get_ref_type(type)) {}
+        pos += append_namespaces(&buf, &len, pos, type->namespace, "", "::", type->name, use_abi_namespace ? "ABI" : NULL);
+        for (type = ref->type; type->type_type == TYPE_POINTER; type = type_pointer_get_ref_type(type)) pos += strappend(&buf, &len, pos, "*");
+        if (list_next(params, &ref->entry)) pos += strappend(&buf, &len, pos, ",");
+    }
+    pos += strappend(&buf, &len, pos, ">");
+
     return buf;
 }
 
@@ -642,6 +669,14 @@ type_t *type_parameterized_interface_define(type_t *type, attr_list_t *attrs, ty
     return type;
 }
 
+type_t *type_parameterized_type_specialize_partial(type_t *type, typeref_list_t *params)
+{
+    type_t *new_type = duptype(type, 0);
+    new_type->details.parameterized.type = type;
+    new_type->details.parameterized.params = params;
+    return new_type;
+}
+
 int type_is_equal(const type_t *type1, const type_t *type2)
 {
     if (type1 == type2)
diff --git a/tools/widl/typetree.h b/tools/widl/typetree.h
index a2185ae35ea..6408fc0e409 100644
--- a/tools/widl/typetree.h
+++ b/tools/widl/typetree.h
@@ -36,6 +36,8 @@ attr_list_t *check_interface_attrs(const char *name, attr_list_t *attrs);
 attr_list_t *check_module_attrs(const char *name, attr_list_t *attrs);
 attr_list_t *check_runtimeclass_attrs(const char *name, attr_list_t *attrs);
 
+type_t *find_parameterized_type(type_t *type, typeref_list_t *params);
+
 type_t *type_new_function(var_list_t *args);
 type_t *type_new_pointer(type_t *ref);
 type_t *type_new_alias(const decl_spec_t *t, const char *name);
@@ -64,6 +66,7 @@ type_t *type_apicontract_declare(char *name, struct namespace *namespace);
 type_t *type_apicontract_define(type_t *apicontract, attr_list_t *attrs);
 type_t *type_parameterized_interface_declare(char *name, struct namespace *namespace, typeref_list_t *params);
 type_t *type_parameterized_interface_define(type_t *type, attr_list_t *attrs, type_t *inherit, statement_list_t *stmts, typeref_list_t *requires);
+type_t *type_parameterized_type_specialize_partial(type_t *type, typeref_list_t *params);
 int type_is_equal(const type_t *type1, const type_t *type2);
 const char *type_get_name(const type_t *type, enum name_type name_type);
 char *gen_name(void);
diff --git a/tools/widl/widltypes.h b/tools/widl/widltypes.h
index e2f77fbadec..777aabc78ff 100644
--- a/tools/widl/widltypes.h
+++ b/tools/widl/widltypes.h
@@ -643,6 +643,7 @@ void init_loc_info(loc_info_t *);
 
 char *format_namespace(struct namespace *namespace, const char *prefix, const char *separator, const char *suffix,
                        const char *abi_prefix);
+char *format_parameterized_type_name(type_t *type, typeref_list_t *params);
 
 static inline enum type_type type_get_type_detect_alias(const type_t *type)
 {




More information about the wine-cvs mailing list