2 * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
3 * See the copyright notice in the ACK home directory, in the file "Copyright".
5 * Author: Ceriel J.H. Jacobs
8 /* T Y P E E Q U I V A L E N C E */
10 /* $Id: typequiv.c,v 1.40 1996/08/14 07:42:40 ceriel Exp $ */
12 /* Routines for testing type equivalence, type compatibility, and
13 assignment compatibility
21 #include "strict3rd.h"
31 extern char *sprint();
34 TstTypeEquiv(tp1, tp2)
37 /* test if two types are equivalent.
49 register t_type *tp1, *tp2;
51 /* test if two parameter types are equivalent. This routine
52 is used to check if two different procedure declarations
53 (one in the definition module, one in the implementation
54 module) are equivalent. A complication comes from dynamic
59 TstTypeEquiv(tp1, tp2)
62 IsConformantArray(tp1)
64 IsConformantArray(tp2)
66 TstTypeEquiv(tp1->arr_elem, tp2->arr_elem)
71 TstProcEquiv(tp1, tp2)
74 /* Test if two procedure types are equivalent. This routine
75 may also be used for the testing of assignment compatibility
76 between procedure variables and procedures.
78 register t_param *p1, *p2;
80 /* First check if the result types are equivalent
82 if (! TstTypeEquiv(ResultType(tp1), ResultType(tp2))) return 0;
87 /* Now check the parameters
90 if (IsVarParam(p1) != IsVarParam(p2) ||
91 !TstParEquiv(TypeOfParam(p1), TypeOfParam(p2))) return 0;
96 /* Here, at least one of the parameterlists is exhausted.
97 Check that they are both.
104 register t_type *tp1, *tp2;
106 /* test if two types are compatible. See section 6.3 of the
107 Modula-2 Report for a definition of "compatible".
110 if (TstTypeEquiv(tp1, tp2)) return 1;
114 if (tp2->tp_fund != T_INTORCARD &&
115 (tp1->tp_fund == T_INTORCARD || tp1 == address_type)) {
124 ( tp2 == intorcard_type
126 (tp1 == int_type || tp1 == card_type || tp1 == address_type)
129 ( tp2 == longintorcard_type
131 (tp1 == longint_type || tp1 == longcard_type || tp1 == address_type)
134 ( tp2 == address_type
136 ( tp1->tp_fund == T_CARDINAL || tp1->tp_fund == T_POINTER)
142 TstAssCompat(tp1, tp2)
143 register t_type *tp1, *tp2;
145 /* Test if two types are assignment compatible.
149 if (TstCompat(tp1, tp2)) return 1;
154 if (((tp1->tp_fund & T_INTORCARD) || tp1 == address_type) &&
155 ((tp2->tp_fund & T_INTORCARD) || tp2 == address_type)) return 1;
157 if ((tp1->tp_fund == T_REAL) &&
158 (tp2->tp_fund == T_REAL)) return 1;
160 if (tp1->tp_fund == T_PROCEDURE &&
161 tp2->tp_fund == T_PROCEDURE) {
162 return TstProcEquiv(tp1, tp2);
165 if (tp1->tp_fund == T_ARRAY) {
168 if (IsConformantArray(tp1)) return 0;
171 BaseType(tp1->arr_elem) == char_type
172 && tp2->tp_fund == T_STRING
173 && (tp1->arr_high - tp1->arr_low + 1) >= tp2->tp_size
182 register t_type *tp1, *tp2;
185 if (tp1->tp_fund == T_HIDDEN || tp2->tp_fund == T_HIDDEN) {
186 return "properties of opaque type are hidden; illegal use";
188 return "type incompatibility";
192 TstParCompat(parno, formaltype, VARflag, nd, edf)
193 register t_type *formaltype;
197 /* Check type compatibility for a parameter in a procedure call.
198 Assignment compatibility may do if the parameter is
200 Otherwise, a conformant array may do, or an ARRAY OF (WORD|BYTE)
204 register t_type *actualtype = (*nd)->nd_type;
208 sprint(ebuf, "\"%s\", parameter %d: %%s", edf->df_idf->id_text, parno);
210 else sprint(ebuf, "parameter %d: %%s", parno);
213 TstTypeEquiv(formaltype, actualtype)
215 ( !VARflag && ChkAssCompat(nd, formaltype, (char *) 0))
217 ( formaltype == address_type
218 && actualtype->tp_fund == T_POINTER
221 ( formaltype == word_type
223 ( actualtype->tp_size == word_size
227 actualtype->tp_size <= word_size
229 ! IsConformantArray(actualtype)
234 ( formaltype == byte_type
235 && actualtype->tp_size == (arith) 1
238 ( IsConformantArray(formaltype)
240 ( formaltype->arr_elem == word_type
241 || formaltype->arr_elem == byte_type
243 ( actualtype->tp_fund == T_ARRAY
244 && TstTypeEquiv(formaltype->arr_elem,actualtype->arr_elem)
247 ( actualtype->tp_fund == T_STRING
248 && TstTypeEquiv(formaltype->arr_elem, char_type)
254 #ifndef STRICT_3RD_ED
255 if (! options['3'] && VARflag && TstCompat(formaltype, actualtype)) {
256 if (formaltype->tp_size == actualtype->tp_size) {
260 "identical types required");
263 node_error(*nd, ebuf, "equal sized types required");
267 node_error(*nd, ebuf, incompat(formaltype, actualtype));
271 CompatCheck(nd, tp, message, fc)
272 register t_node **nd;
277 if (! (*fc)(tp, (*nd)->nd_type)) {
279 node_error(*nd, "%s in %s",
280 incompat(tp, (*nd)->nd_type),
289 ChkAssCompat(nd, tp, message)
294 /* Check assignment compatibility of node "nd" with type "tp".
295 Give an error message when it fails
298 if ((*nd)->nd_symb == STRING) {
299 TryToString((*nd), tp);
301 return CompatCheck(nd, tp, message, TstAssCompat);
304 ChkCompat(nd, tp, message)
309 /* Check compatibility of node "nd" with type "tp".
310 Give an error message when it fails
313 return CompatCheck(nd, tp, message, TstCompat);