[m-dev.] for review: use MR_CHECK_EXPR_TYPE() macro

Fergus Henderson fjh at cs.mu.OZ.AU
Mon Mar 27 04:06:52 AEST 2000


Another place where the MR_CHECK_EXPR_TYPE() macro
might be useful is in the various macros that we
use for the trailing interface.  But that can be
a separate change...

----------

Estimated hours taken: 1

Improve the static type checking and readability of
some of the macros that we define, by using a new
MR_CHECK_EXPR_TYPE() macro.

runtime/mercury_std.h:
	Define the MR_CHECK_EXPR_TYPE() macro.

runtime/mercury_type_info.h:
library/std_util.m:
	Make use of it.

library/std_util.m:
	Add a few comments, and reorder some macro definitions
	do improve readability.  Delete an incorrect XXX comment.

runtime/mercury_make_type_info_body.h:
	Add a type cast, where we were using an MR_TypeInfo
	as an MR_PseudoTypeInfo.

Workspace: /home/mercury0/fjh/mercury
Index: library/std_util.m
===================================================================
RCS file: /home/mercury1/repository/mercury/library/std_util.m,v
retrieving revision 1.186
diff -u -d -r1.186 std_util.m
--- library/std_util.m	2000/03/26 07:22:27	1.186
+++ library/std_util.m	2000/03/26 17:07:27
@@ -1212,6 +1212,7 @@
 ** values of type `private_builtin:type_info' (this representation is
 ** documented in compiler/polymorphism.m). Some parts of the library
 ** (e.g. the gc initialization code) depend on this.
+** The C type corresponding to these Mercury types is `MR_TypeInfo'.
 **
 ** Values of type `std_util:type_ctor_desc' are not guaranteed to be
 ** represented the same way as values of type `private_builtin:type_ctor_info'.
@@ -1220,58 +1221,80 @@
 ** containing a pointer to the type_ctor_info for pred/0 or func/0 and an
 ** arity, we have a single small encoded integer. This integer is double
 ** the arity, plus zero or one; plus zero encodes a predicate, plus one encodes
-** a function.
-**
-** The maximum arity that can be encoded should be set to twice the maximum
-** number of general purpose registers, since an predicate or function having
-** more arguments that this would run out of registers when passing the input
-** arguments, or the output arguments, or both.
-**
-** XXX This scheme does not properly handle the type_desc for the type
-** private_builtin:type_info, since that type also has a variable arity
-** (and because the current implementation lies about the arity).
+** a function.  The maximum arity that can be encoded is given by
+** MR_MAX_HO_ARITY (see below).
+** The C type corresponding to std_util:type_ctor_desc is `MR_TypeCtorInfo'.
+*/
+
+/*
+** Declare the MR_TypeCtorDesc ADT.
 **
-** Note that MR_TypeCtorDesc is declared as a pointer to a dummy structure
-** only in order to allow the C compiler to catch errors in which things other
+** Note that `struct MR_TypeCtorDesc_Struct' is deliberately left undefined.
+** MR_TypeCtorDesc is declared as a pointer to a dummy structure only
+** in order to allow the C compiler to catch errors in which things other
 ** than MR_TypeCtorDescs are given as arguments to macros that depend on their
 ** arguments being MR_TypeCtorDescs. The actual value is either a small integer
 ** or a pointer to a MR_TypeCtorInfo_Struct structure, as described above.
 */
-
-typedef struct {
-    Unsigned    type_ctor_desc_dummy_field;
-} *MR_TypeCtorDesc;
+typedef struct MR_TypeCtorDesc_Struct *MR_TypeCtorDesc;
 
+/*
+** The maximum arity that can be encoded should be set to twice the maximum
+** number of general purpose registers, since an predicate or function having
+** more arguments that this would run out of registers when passing the input
+** arguments, or the output arguments, or both.
+*/
 #define MR_MAX_HO_ARITY         (2 * MAX_VIRTUAL_REG)
-
-#define MR_TYPECTOR_DESC_UNSIGNED(T)                                    \
-        ( (Unsigned) &(T)->type_ctor_desc_dummy_field )
-#define MR_TYPECTOR_DESC_GET_FIRST_ORDER_TYPE_CTOR_INFO(T)              \
-        ( (MR_TypeCtorInfo) &(T)->type_ctor_desc_dummy_field )
 
-#define MR_TYPECTOR_DESC_IS_HIGHER_ORDER(T)                             \
-        ( MR_TYPECTOR_DESC_UNSIGNED(T) <= (2 * MR_MAX_HO_ARITY + 1) )
+/*
+** Constructors for the MR_TypeCtorDesc ADT
+*/
 #define MR_TYPECTOR_DESC_MAKE_PRED(Arity)                               \
         ( (MR_TypeCtorDesc) ((Arity) * 2) )
 #define MR_TYPECTOR_DESC_MAKE_FUNC(Arity)                               \
         ( (MR_TypeCtorDesc) ((Arity) * 2 + 1) )
 #define MR_TYPECTOR_DESC_MAKE_FIRST_ORDER(type_ctor_info)               \
-        ( (MR_TypeCtorDesc) &type_ctor_info->arity )
+        ( MR_CHECK_EXPR_TYPE(type_ctor_info, MR_TypeCtorInfo),		\
+	  (MR_TypeCtorDesc) type_ctor_info )
+
+/*
+** Access macros for the MR_TypeCtor ADT.
+**
+** The MR_TYPECTOR_DESC_GET_HOT_* macros should only be called if
+** MR_TYPECTOR_DESC_IS_HIGHER_ORDER() returns true.
+** The MR_TYPECTOR_DESC_GET_FIRST_ORDER_TYPE_CTOR_INFO() macro
+** should only be called if MR_TYPECTOR_DESC_IS_HIGHER_ORDER() returns false.
+*/
+#define MR_TYPECTOR_DESC_IS_HIGHER_ORDER(T)                             \
+        ( MR_CHECK_EXPR_TYPE(T, MR_TypeCtorDesc),			\
+          (Unsigned) (T) <= (2 * MR_MAX_HO_ARITY + 1) )
+#define MR_TYPECTOR_DESC_GET_FIRST_ORDER_TYPE_CTOR_INFO(T)              \
+        ( MR_CHECK_EXPR_TYPE(T, MR_TypeCtorDesc),			\
+	  (MR_TypeCtorInfo) (T) )
 #define MR_TYPECTOR_DESC_GET_HOT_ARITY(T)                               \
-        ( MR_TYPECTOR_DESC_UNSIGNED(T) / 2 )
+        ( MR_CHECK_EXPR_TYPE(T, MR_TypeCtorDesc),			\
+          (Unsigned) (T) / 2 )
 #define MR_TYPECTOR_DESC_GET_HOT_NAME(T)                                \
-        ((ConstString) ((MR_TYPECTOR_DESC_UNSIGNED(T) % 2 != 0)         \
+        ( MR_CHECK_EXPR_TYPE(T, MR_TypeCtorDesc),			\
+          (ConstString) (((Unsigned) (T) % 2 != 0)         		\
                 ? ""func""                                              \
                 : ""pred"" ))
 #define MR_TYPECTOR_DESC_GET_HOT_MODULE_NAME(T)                         \
-        ((ConstString) ""builtin"")
+        ( MR_CHECK_EXPR_TYPE(T, MR_TypeCtorDesc),			\
+          (ConstString) ""builtin"" )
 #define MR_TYPECTOR_DESC_GET_HOT_TYPE_CTOR_INFO(T)                      \
-        ((MR_TYPECTOR_DESC_UNSIGNED(T) % 2 != 0)      			\
-                ? (MR_TypeCtorInfo) (Word)				\
+        ( MR_CHECK_EXPR_TYPE(T, MR_TypeCtorDesc),			\
+          ((Unsigned) (T) % 2 != 0)      				\
+                ? (MR_TypeCtorInfo)					\
 			&mercury_data___type_ctor_info_func_0           \
-                : (MR_TypeCtorInfo) (Word)				\
+                : (MR_TypeCtorInfo)					\
 			&mercury_data___type_ctor_info_pred_0 )
 
+%-----------------------------------------------------------------------------%
+
+/*
+** Macros dealing with the MR_TypeCtorInfo type.
+*/
 #define MR_TYPE_CTOR_INFO_HO_PRED                                       \
         ((MR_TypeCtorInfo) &mercury_data___type_ctor_info_pred_0)
 #define MR_TYPE_CTOR_INFO_HO_FUNC                                       \
@@ -1287,6 +1310,8 @@
 
 ").
 
+%-----------------------------------------------------------------------------%
+
 :- pragma c_header_code("
 
 /* The `#ifndef ... #define ... #endif' guards against multiple inclusion */
@@ -1330,7 +1355,7 @@
 ").
 
 	% A type_ctor_desc is really just a subtype of type_desc,
-	% but we should hide this from users as it is an implementation
+	% but we hide this from users, since it is an implementation
 	% detail.
 :- type type_ctor_desc == type_desc.
 
Index: runtime/mercury_make_type_info_body.h
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_make_type_info_body.h,v
retrieving revision 1.1
diff -u -d -r1.1 mercury_make_type_info_body.h
--- runtime/mercury_make_type_info_body.h	2000/03/24 10:27:49	1.1
+++ runtime/mercury_make_type_info_body.h	2000/03/26 17:56:06
@@ -44,7 +44,9 @@
 		expanded_type_info = MR_get_arg_type_info(type_info_params, 
 			pseudo_type_info, data_value, functor_desc);
 
-		if (MR_PSEUDO_TYPEINFO_IS_VARIABLE(expanded_type_info)) {
+		if (MR_PSEUDO_TYPEINFO_IS_VARIABLE(
+			(MR_PseudoTypeInfo) expanded_type_info))
+		{
 			fatal_error(exist_func_string
 				": unbound type variable");
 		}
@@ -84,7 +86,9 @@
 				data_value, functor_desc
 				MAYBE_PASS_ALLOC_ARG);
 
-		if (MR_PSEUDO_TYPEINFO_IS_VARIABLE(expanded_type_info)) {
+		if (MR_PSEUDO_TYPEINFO_IS_VARIABLE(
+			(MR_PseudoTypeInfo) expanded_type_info))
+		{
 			fatal_error(exist_func_string
 				": unbound type variable");
 		}
Index: runtime/mercury_std.h
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_std.h,v
retrieving revision 1.10
diff -u -d -r1.10 mercury_std.h
--- runtime/mercury_std.h	2000/03/10 13:38:12	1.10
+++ runtime/mercury_std.h	2000/03/26 16:09:25
@@ -123,6 +123,26 @@
 #define MR_PASTE7(a,b,c,d,e,f,g)	MR_PASTE7_2(a,b,c,d,e,f,g)
 #define MR_PASTE7_2(a,b,c,d,e,f,g)	a##b##c##d##e##f##g
 
+/*
+** MR_CHECK_EXPR_TYPE(expr, type):
+** This macro checks that the given expression has a type
+** which is compatible with (assignable to) the specified type,
+** forcing a compile error if it does not.
+** It does not evaluate the expression.
+** Note that the specified type must be a complete type,
+** i.e. it must not be a pointer to a struct which has
+** not been defined.
+**
+** This macro is useful for defining type-safe function-like macros.
+**
+** The implementation of this macro looks like it dereferences
+** a null pointer, but because that code is inside sizeof(), it will
+** not get executed; the compiler will instead just check that it is
+** type-correct.
+*/
+#define MR_CHECK_EXPR_TYPE(expr, type) \
+	((void) sizeof(*(type *)NULL = (expr)))
+
 /*---------------------------------------------------------------------------*/
 
 #endif /* not MERCURY_STD_H */
Index: runtime/mercury_type_info.h
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_type_info.h,v
retrieving revision 1.42
diff -u -d -r1.42 mercury_type_info.h
--- runtime/mercury_type_info.h	2000/03/26 15:57:35	1.42
+++ runtime/mercury_type_info.h	2000/03/26 17:52:49
@@ -147,26 +147,41 @@
 ** A MR_TypeInfoParams array serves this purpose. Because type variables
 ** start at one, MR_TypeInfoParams arrays also start at one.
 */
-
 typedef MR_TypeInfo     *MR_TypeInfoParams;
 
 #define MR_PSEUDOTYPEINFO_EXIST_VAR_BASE    512
 #define MR_PSEUDOTYPEINFO_MAX_VAR           1024
 
+/*
+** Macros for accessing pseudo_type_infos.
+**
+** The MR_TYPE_VARIABLE_* macros should only be called if
+** MR_PSEUDO_TYPEINFO_IS_VARIABLE() returns TRUE.
+*/
+
 #define MR_PSEUDO_TYPEINFO_IS_VARIABLE(T)                           \
-    ( (Unsigned) T <= MR_PSEUDOTYPEINFO_MAX_VAR )
+    ( MR_CHECK_EXPR_TYPE((T), MR_PseudoTypeInfo),		    \
+      (Unsigned) (T) <= MR_PSEUDOTYPEINFO_MAX_VAR )
 
 #define MR_TYPE_VARIABLE_IS_EXIST_QUANT(T)                          \
-    ( (Word) (T) > MR_PSEUDOTYPEINFO_EXIST_VAR_BASE )
+    ( MR_CHECK_EXPR_TYPE((T), MR_PseudoTypeInfo),		    \
+      (Word) (T) > MR_PSEUDOTYPEINFO_EXIST_VAR_BASE )
 #define MR_TYPE_VARIABLE_IS_UNIV_QUANT(T)                           \
-    ( (Word) (T) <= MR_PSEUDOTYPEINFO_EXIST_VAR_BASE )
+    ( MR_CHECK_EXPR_TYPE((T), MR_PseudoTypeInfo),		    \
+      (Word) (T) <= MR_PSEUDOTYPEINFO_EXIST_VAR_BASE )
 
+/*
+** This macro converts a pseudo_type_info to a type_info.
+** It should only be called if the pseudo_type_info is ground,
+** i.e. contains no type variables.
+*/
 #define MR_pseudo_type_info_is_ground(pseudo_type_info)             \
-    ((MR_TypeInfo) &pseudo_type_info->MR_pti_type_ctor_info)
+    ( MR_CHECK_EXPR_TYPE((pseudo_type_info), MR_PseudoTypeInfo),    \
+      (MR_TypeInfo) (pseudo_type_info) )			    \
 
-    /*
-    ** Macros for retrieving things from type_infos and pseudo_type_infos.
-    */
+/*
+** Macros for retrieving things from type_infos and pseudo_type_infos.
+*/
 
 #define MR_TYPEINFO_GET_TYPE_CTOR_INFO(type_info)                   \
     (((type_info)->MR_ti_type_ctor_info != NULL)                    \
@@ -191,9 +206,9 @@
 #define MR_TYPEINFO_GET_FIRST_ORDER_ARG_VECTOR(type_info)           \
     ((MR_TypeInfoParams) &(type_info)->MR_ti_type_ctor_info)
 
-    /*
-    ** Macros for creating type_infos.
-    */
+/*
+** Macros for creating type_infos.
+*/
 
 #define MR_first_order_type_info_size(arity)                        \
     (1 + (arity))

-- 
Fergus Henderson <fjh at cs.mu.oz.au>  |  "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh>  |  of excellence is a lethal habit"
PGP: finger fjh at 128.250.37.3        |     -- the last words of T. S. Garp.
--------------------------------------------------------------------------
mercury-developers mailing list
Post messages to:       mercury-developers at cs.mu.oz.au
Administrative Queries: owner-mercury-developers at cs.mu.oz.au
Subscriptions:          mercury-developers-request at cs.mu.oz.au
--------------------------------------------------------------------------



More information about the developers mailing list