P4C
The P4 Compiler
 
Loading...
Searching...
No Matches
typeChecker.h
1/*
2Copyright 2013-present Barefoot Networks, Inc.
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15*/
16
17#ifndef TYPECHECKING_TYPECHECKER_H_
18#define TYPECHECKING_TYPECHECKER_H_
19
20#include "frontends/common/resolveReferences/referenceMap.h"
21#include "frontends/p4/methodInstance.h"
22#include "frontends/p4/typeChecking/typeSubstitution.h"
23#include "frontends/p4/typeChecking/typeSubstitutionVisitor.h"
24#include "frontends/p4/typeMap.h"
25#include "ir/ir.h"
26#include "ir/pass_manager.h"
27#include "ir/visitor.h"
28#include "lib/cstring.h"
29#include "lib/exceptions.h"
30#include "typeUnification.h"
31
32namespace P4 {
33
34// This pass only clears the typeMap if the program has changed
35// or the 'force' flag is set.
36// This is needed if the types of some objects in the program change.
37class ClearTypeMap : public Inspector {
38 TypeMap *typeMap;
39 bool force;
40
41 public:
42 explicit ClearTypeMap(TypeMap *typeMap, bool force = false) : typeMap(typeMap), force(force) {
43 CHECK_NULL(typeMap);
44 }
45 bool preorder(const IR::P4Program *program) override {
46 // Clear map only if program has not changed from last time
47 // otherwise we can reuse it. The 'force' flag is needed
48 // because the program is saved only *after* typechecking,
49 // so if the program changes during type-checking, the
50 // typeMap may not be complete.
51 if (force || !typeMap->checkMap(program)) typeMap->clear();
52 return false; // prune()
53 }
54};
55
60class TypeChecking : public PassManager {
61 public:
62 TypeChecking(/* out */ ReferenceMap *refMap, /* out */ TypeMap *typeMap,
63 bool updateExpressions = false);
64};
65
66template <typename... T>
67void typeError(const char *format, T... args) {
68 ::error(ErrorType::ERR_TYPE_ERROR, format, args...);
69}
71bool hasVarbitsOrUnions(const TypeMap *typeMap, const IR::Type *type);
72
73// Actual type checking algorithm.
74// In general this pass should not be called directly; call TypeChecking instead.
75// It is a transform because it may convert implicit casts into explicit casts.
76// But in general it operates like an Inspector; in fact, if it is instantiated
77// with readOnly = true, it will assert that the program is not changed.
78// It is expected that once a program has been type-checked and all casts have
79// been inserted it will not need to change ever again during type-checking.
80// In fact, several passes do modify the program such that types are invalidated.
81// For example, enum elimination converts enum values into integers. After such
82// changes the typemap has to be cleared and types must be recomputed from scratch.
83class TypeInference : public Transform {
84 // Input: reference map
85 ReferenceMap *refMap;
86 // Output: type map
87 TypeMap *typeMap;
88 const IR::Node *initialNode;
89
90 public:
91 // @param readOnly If true it will assert that it behaves like
92 // an Inspector.
93 TypeInference(ReferenceMap *refMap, TypeMap *typeMap, bool readOnly = false,
94 bool checkArrays = true);
95
96 protected:
97 // If true we expect to leave the program unchanged
98 bool readOnly;
99 bool checkArrays = true;
100 const IR::Type *getType(const IR::Node *element) const;
101 const IR::Type *getTypeType(const IR::Node *element) const;
102 void setType(const IR::Node *element, const IR::Type *type);
103 void setLeftValue(const IR::Expression *expression) { typeMap->setLeftValue(expression); }
104 bool isLeftValue(const IR::Expression *expression) const {
105 return typeMap->isLeftValue(expression) || expression->is<IR::DefaultExpression>();
106 }
107 void setCompileTimeConstant(const IR::Expression *expression) {
108 typeMap->setCompileTimeConstant(expression);
109 }
110 bool isCompileTimeConstant(const IR::Expression *expression) const {
111 return typeMap->isCompileTimeConstant(expression);
112 }
113
114 // This is needed because sometimes we invoke visitors recursively on subtrees explicitly.
115 // (visitDagOnce cannot take care of this).
116 bool done() const;
117
118 TypeVariableSubstitution *unifyBase(bool allowCasts, const IR::Node *errorPosition,
119 const IR::Type *destType, const IR::Type *srcType,
120 cstring errorFormat,
121 std::initializer_list<const IR::Node *> errorArgs);
122
126 TypeVariableSubstitution *unifyCast(const IR::Node *errorPosition, const IR::Type *destType,
127 const IR::Type *srcType, cstring errorFormat = nullptr,
128 std::initializer_list<const IR::Node *> errorArgs = {}) {
129 return unifyBase(true, errorPosition, destType, srcType, errorFormat, errorArgs);
130 }
132 TypeVariableSubstitution *unify(const IR::Node *errorPosition, const IR::Type *destType,
133 const IR::Type *srcType, cstring errorFormat = nullptr,
134 std::initializer_list<const IR::Node *> errorArgs = {}) {
135 return unifyBase(false, errorPosition, destType, srcType, errorFormat, errorArgs);
136 }
137
142 const IR::Expression *assignment(const IR::Node *errorPosition, const IR::Type *destType,
143 const IR::Expression *sourceExpression);
144 const IR::SelectCase *matchCase(const IR::SelectExpression *select,
145 const IR::Type_BaseList *selectType,
146 const IR::SelectCase *selectCase, const IR::Type *caseType);
147 bool canCastBetween(const IR::Type *dest, const IR::Type *src) const;
148 bool checkAbstractMethods(const IR::Declaration_Instance *inst, const IR::Type_Extern *type);
149 void addSubstitutions(const TypeVariableSubstitution *tvs);
150
151 const IR::Expression *constantFold(const IR::Expression *expression);
152
156 virtual const IR::Type *canonicalize(const IR::Type *type);
157 const IR::Type *canonicalizeFields(
158 const IR::Type_StructLike *type,
159 std::function<const IR::Type *(const IR::IndexedVector<IR::StructField> *)> constructor);
160 virtual const IR::ParameterList *canonicalizeParameters(const IR::ParameterList *params);
161
162 // various helpers
163 bool onlyBitsOrBitStructs(const IR::Type *type) const;
164 bool containsHeader(const IR::Type *canonType);
165 bool validateFields(const IR::Type *type, std::function<bool(const IR::Type *)> checker) const;
166 const IR::Node *binaryBool(const IR::Operation_Binary *op);
167 const IR::Node *binaryArith(const IR::Operation_Binary *op);
168 const IR::Node *unsBinaryArith(const IR::Operation_Binary *op);
169 const IR::Node *shift(const IR::Operation_Binary *op);
170 const IR::Node *typeSet(const IR::Operation_Binary *op);
171
172 const IR::Type *cloneWithFreshTypeVariables(const IR::IMayBeGenericType *type);
173 std::pair<const IR::Type *, const IR::Vector<IR::Argument> *> containerInstantiation(
174 const IR::Node *node, const IR::Vector<IR::Argument> *args,
175 const IR::IContainer *container);
176 const IR::Expression *actionCall(
177 bool inActionList, // if true this "call" is in the action list of a table
178 const IR::MethodCallExpression *actionCall);
179 std::pair<const IR::Type *, const IR::Vector<IR::Argument> *> checkExternConstructor(
180 const IR::Node *errorPosition, const IR::Type_Extern *ext,
181 const IR::Vector<IR::Argument> *arguments);
182
183 static constexpr bool forbidModules = true;
184 static constexpr bool forbidPackages = true;
185 bool checkParameters(const IR::ParameterList *paramList, bool forbidModules = false,
186 bool forbidPackage = false) const;
187 virtual const IR::Type *setTypeType(const IR::Type *type, bool learn = true);
188
190 const IR::ActionList *currentActionList;
194 const IR::ActionListElement *validateActionInitializer(const IR::Expression *actionCall);
195 bool containsActionEnum(const IR::Type *type) const;
196
199 const IR::Type_Bits *checkUnderlyingEnumType(const IR::Type *enumType);
200
202
203 public:
204 using Transform::postorder;
205 using Transform::preorder;
206
207 static const IR::Type *specialize(const IR::IMayBeGenericType *type,
208 const IR::Vector<IR::Type> *arguments);
209 const IR::Node *pruneIfDone(const IR::Node *node) {
210 if (done()) {
211 prune();
212 }
213 return node;
214 }
215 const IR::Node *preorder(IR::Expression *expression) override {
216 return pruneIfDone(expression);
217 }
218 const IR::Node *preorder(IR::Type *type) override { return pruneIfDone(type); }
219
220 struct Comparison {
221 const IR::Expression *left;
222 const IR::Expression *right;
223 };
224
225 // Helper function to handle comparisons
226 bool compare(const IR::Node *errorPosition, const IR::Type *ltype, const IR::Type *rtype,
227 Comparison *compare);
228
229 // do functions pre-order so we can check the prototype
230 // before the returns
231 const IR::Node *preorder(IR::Function *function) override;
232 const IR::Node *preorder(IR::P4Program *program) override;
233 const IR::Node *preorder(IR::Declaration_Instance *decl) override;
234 // check invariants for entire list before checking the entries
235 const IR::Node *preorder(IR::EntriesList *el) override;
236 const IR::Node *preorder(IR::Type_SerEnum *type) override;
237
238 const IR::Node *postorder(IR::Declaration_MatchKind *decl) override;
239 const IR::Node *postorder(IR::Declaration_Variable *decl) override;
240 const IR::Node *postorder(IR::Declaration_Constant *constant) override;
241 const IR::Node *postorder(IR::P4Control *cont) override;
242 const IR::Node *postorder(IR::P4Parser *cont) override;
243 const IR::Node *postorder(IR::Method *method) override;
244
245 const IR::Node *postorder(IR::Type_Type *type) override;
246 const IR::Node *postorder(IR::Type_Table *type) override;
247 const IR::Node *postorder(IR::Type_Error *decl) override;
248 const IR::Node *postorder(IR::Type_InfInt *type) override;
249 const IR::Node *postorder(IR::Type_Method *type) override;
250 const IR::Node *postorder(IR::Type_Action *type) override;
251 const IR::Node *postorder(IR::Type_Name *type) override;
252 const IR::Node *postorder(IR::Type_Base *type) override;
253 const IR::Node *postorder(IR::Type_Var *type) override;
254 const IR::Node *postorder(IR::Type_Enum *type) override;
255 const IR::Node *postorder(IR::Type_Extern *type) override;
256 const IR::Node *postorder(IR::StructField *field) override;
257 const IR::Node *postorder(IR::Type_Header *type) override;
258 const IR::Node *postorder(IR::Type_Stack *type) override;
259 const IR::Node *postorder(IR::Type_Struct *type) override;
260 const IR::Node *postorder(IR::Type_HeaderUnion *type) override;
261 const IR::Node *postorder(IR::Type_Typedef *type) override;
262 const IR::Node *postorder(IR::Type_Specialized *type) override;
263 const IR::Node *postorder(IR::Type_SpecializedCanonical *type) override;
264 const IR::Node *postorder(IR::Type_Tuple *type) override;
265 const IR::Node *postorder(IR::Type_P4List *type) override;
266 const IR::Node *postorder(IR::Type_List *type) override;
267 const IR::Node *postorder(IR::Type_Set *type) override;
268 const IR::Node *postorder(IR::Type_ArchBlock *type) override;
269 const IR::Node *postorder(IR::Type_Newtype *type) override;
270 const IR::Node *postorder(IR::Type_Package *type) override;
271 const IR::Node *postorder(IR::Type_ActionEnum *type) override;
272 const IR::Node *postorder(IR::P4Table *type) override;
273 const IR::Node *postorder(IR::P4Action *type) override;
274 const IR::Node *postorder(IR::P4ValueSet *type) override;
275 const IR::Node *postorder(IR::Key *key) override;
276 const IR::Node *postorder(IR::Entry *e) override;
277
278 const IR::Node *postorder(IR::Dots *expression) override;
279 const IR::Node *postorder(IR::Argument *arg) override;
280 const IR::Node *postorder(IR::SerEnumMember *member) override;
281 const IR::Node *postorder(IR::Parameter *param) override;
282 const IR::Node *postorder(IR::Constant *expression) override;
283 const IR::Node *postorder(IR::BoolLiteral *expression) override;
284 const IR::Node *postorder(IR::StringLiteral *expression) override;
285 const IR::Node *postorder(IR::Operation_Relation *expression) override;
286 const IR::Node *postorder(IR::Concat *expression) override;
287 const IR::Node *postorder(IR::ArrayIndex *expression) override;
288 const IR::Node *postorder(IR::LAnd *expression) override { return binaryBool(expression); }
289 const IR::Node *postorder(IR::LOr *expression) override { return binaryBool(expression); }
290 const IR::Node *postorder(IR::Add *expression) override { return binaryArith(expression); }
291 const IR::Node *postorder(IR::Sub *expression) override { return binaryArith(expression); }
292 const IR::Node *postorder(IR::AddSat *expression) override { return binaryArith(expression); }
293 const IR::Node *postorder(IR::SubSat *expression) override { return binaryArith(expression); }
294 const IR::Node *postorder(IR::Mul *expression) override { return binaryArith(expression); }
295 const IR::Node *postorder(IR::Div *expression) override { return unsBinaryArith(expression); }
296 const IR::Node *postorder(IR::Mod *expression) override { return unsBinaryArith(expression); }
297 const IR::Node *postorder(IR::Shl *expression) override { return shift(expression); }
298 const IR::Node *postorder(IR::Shr *expression) override { return shift(expression); }
299 const IR::Node *postorder(IR::BXor *expression) override { return binaryArith(expression); }
300 const IR::Node *postorder(IR::BAnd *expression) override { return binaryArith(expression); }
301 const IR::Node *postorder(IR::BOr *expression) override { return binaryArith(expression); }
302 const IR::Node *postorder(IR::Mask *expression) override { return typeSet(expression); }
303 const IR::Node *postorder(IR::Range *expression) override { return typeSet(expression); }
304 const IR::Node *postorder(IR::LNot *expression) override;
305 const IR::Node *postorder(IR::Neg *expression) override;
306 const IR::Node *postorder(IR::UPlus *expression) override;
307 const IR::Node *postorder(IR::Cmpl *expression) override;
308 const IR::Node *postorder(IR::Cast *expression) override;
309 const IR::Node *postorder(IR::Mux *expression) override;
310 const IR::Node *postorder(IR::Slice *expression) override;
311 const IR::Node *postorder(IR::PathExpression *expression) override;
312 const IR::Node *postorder(IR::Member *expression) override;
313 const IR::Node *postorder(IR::TypeNameExpression *expression) override;
314 const IR::Node *postorder(IR::ListExpression *expression) override;
315 const IR::Node *postorder(IR::InvalidHeader *expression) override;
316 const IR::Node *postorder(IR::InvalidHeaderUnion *expression) override;
317 const IR::Node *postorder(IR::Invalid *expression) override;
318 const IR::Node *postorder(IR::P4ListExpression *expression) override;
319 const IR::Node *postorder(IR::StructExpression *expression) override;
320 const IR::Node *postorder(IR::HeaderStackExpression *expression) override;
321 const IR::Node *postorder(IR::MethodCallExpression *expression) override;
322 const IR::Node *postorder(IR::ConstructorCallExpression *expression) override;
323 const IR::Node *postorder(IR::SelectExpression *expression) override;
324 const IR::Node *postorder(IR::DefaultExpression *expression) override;
325 const IR::Node *postorder(IR::This *expression) override;
326 const IR::Node *postorder(IR::AttribLocal *local) override;
327 const IR::Node *postorder(IR::ActionList *al) override;
328
329 const IR::Node *postorder(IR::ReturnStatement *stat) override;
330 const IR::Node *postorder(IR::IfStatement *stat) override;
331 const IR::Node *postorder(IR::SwitchStatement *stat) override;
332 const IR::Node *postorder(IR::AssignmentStatement *stat) override;
333 const IR::Node *postorder(IR::ActionListElement *elem) override;
334 const IR::Node *postorder(IR::KeyElement *elem) override;
335 const IR::Node *postorder(IR::Property *elem) override;
336 const IR::Node *postorder(IR::SelectCase *elem) override;
337 const IR::Node *postorder(IR::Annotation *annotation) override;
338
339 Visitor::profile_t init_apply(const IR::Node *node) override;
340 void end_apply(const IR::Node *Node) override;
341 const IR::Node *apply_visitor(const IR::Node *, const char *name = 0) override;
342
343 TypeInference *clone() const override;
344 // Apply recursively the typechecker to the newly created node
345 // to add all component subtypes in the typemap.
346 // Return 'true' if errors were discovered in the learning process.
347 bool learn(const IR::Node *node, Visitor *caller);
348};
349
350// Copy types from the typeMap to expressions. Updates the typeMap with newly created nodes
351class ApplyTypesToExpressions : public Transform {
352 TypeMap *typeMap;
353 IR::Node *postorder(IR::Node *n) override {
354 const IR::Node *orig = getOriginal();
355 if (auto type = typeMap->getType(orig)) {
356 if (*orig != *n) typeMap->setType(n, type);
357 }
358 return n;
359 }
360 IR::Expression *postorder(IR::Expression *e) override {
361 auto orig = getOriginal<IR::Expression>();
362 if (auto type = typeMap->getType(orig)) {
363 e->type = type;
364 if (*orig != *e) {
365 typeMap->setType(e, type);
366 if (typeMap->isLeftValue(orig)) typeMap->setLeftValue(e);
367 if (typeMap->isCompileTimeConstant(orig)) typeMap->setCompileTimeConstant(e);
368 }
369 }
370 return e;
371 }
372
373 public:
374 explicit ApplyTypesToExpressions(TypeMap *typeMap) : typeMap(typeMap) {}
375};
376
377} // namespace P4
378
379#endif /* TYPECHECKING_TYPECHECKER_H_ */
Definition externInstance.h:33
Definition typeChecker.h:351
Definition typeChecker.h:37
Class used to encode maps from paths to declarations.
Definition referenceMap.h:66
Definition typeChecker.h:60
Definition typeChecker.h:83
const IR::ActionListElement * validateActionInitializer(const IR::Expression *actionCall)
Definition typeChecker.cpp:4181
TypeVariableSubstitution * unifyCast(const IR::Node *errorPosition, const IR::Type *destType, const IR::Type *srcType, cstring errorFormat=nullptr, std::initializer_list< const IR::Node * > errorArgs={})
Definition typeChecker.h:126
bool validateFields(const IR::Type *type, std::function< bool(const IR::Type *)> checker) const
Definition typeChecker.cpp:1706
const IR::ActionList * currentActionList
Action list of the current table.
Definition typeChecker.h:190
std::pair< const IR::Type *, const IR::Vector< IR::Argument > * > containerInstantiation(const IR::Node *node, const IR::Vector< IR::Argument > *args, const IR::IContainer *container)
Definition typeChecker.cpp:1170
TypeVariableSubstitution * unify(const IR::Node *errorPosition, const IR::Type *destType, const IR::Type *srcType, cstring errorFormat=nullptr, std::initializer_list< const IR::Node * > errorArgs={})
Same as above, not allowing casts.
Definition typeChecker.h:132
const IR::Type_Bits * checkUnderlyingEnumType(const IR::Type *enumType)
Definition typeChecker.cpp:1515
virtual const IR::Type * canonicalize(const IR::Type *type)
Definition typeChecker.cpp:333
static const IR::Type * specialize(const IR::IMayBeGenericType *type, const IR::Vector< IR::Type > *arguments)
Definition typeChecker.cpp:316
const IR::Expression * assignment(const IR::Node *errorPosition, const IR::Type *destType, const IR::Expression *sourceExpression)
Definition typeChecker.cpp:728
Definition typeChecker.h:220
Definition typeMap.h:42
Definition typeSubstitution.h:73
Definition cstring.h:72
Definition applyOptionsPragmas.cpp:24
bool hasVarbitsOrUnions(const TypeMap *typeMap, const IR::Type *type)
True if the type contains any varbit or header_union subtypes.
Definition typeChecker.cpp:3571