P4C
The P4 Compiler
Loading...
Searching...
No Matches
typeConstraints.h
1/*
2 * SPDX-FileCopyrightText: 2013 Barefoot Networks, Inc.
3 * Copyright 2013-present Barefoot Networks, Inc.
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8#ifndef FRONTENDS_P4_TYPECHECKING_TYPECONSTRAINTS_H_
9#define FRONTENDS_P4_TYPECHECKING_TYPECONSTRAINTS_H_
10
11#include "ir/ir.h"
12#include "lib/castable.h"
13#include "lib/error_helper.h"
14#include "typeSubstitution.h"
15#include "typeSubstitutionVisitor.h"
16#include "typeUnification.h"
17
18namespace P4 {
19
21class Explain : public Inspector {
22 absl::flat_hash_set<const IR::Type_Var *, Util::Hash> explained;
23 const TypeVariableSubstitution *subst;
24
25 public:
26 std::string explanation;
27 explicit Explain(const TypeVariableSubstitution *subst) : subst(subst) { CHECK_NULL(subst); }
28 profile_t init_apply(const IR::Node *node) override {
29 explanation = "";
30 return Inspector::init_apply(node);
31 }
32 void postorder(const IR::Type_Var *tv) override {
33 auto [_, inserted] = explained.emplace(tv);
34 if (!inserted)
35 // Do not repeat explanations.
36 return;
37 auto val = subst->lookup(tv);
38 if (!val) return;
39 explanation += "Where '" + tv->toString() + "' is bound to '" + val->toString() + "'\n";
40 Explain erec(subst); // recursive explain variables in this substitution
41 erec.setCalledBy(this);
42 val->apply(erec);
43 explanation += erec.explanation;
44 }
45};
46
47class TypeConstraint : public IHasDbPrint, public ICastable {
48 int id; // for debugging
49 static int crtid;
51 cstring errFormat;
52 std::vector<const IR::Node *> errArguments;
53
54 private:
55 bool reportErrorImpl(const TypeVariableSubstitution *subst, std::string message) const;
56
57 protected:
59 const TypeConstraint *derivedFrom = nullptr;
61 const IR::Node *origin = nullptr;
62
63 explicit TypeConstraint(const TypeConstraint *derivedFrom)
64 : id(crtid++), derivedFrom(derivedFrom) {}
65 explicit TypeConstraint(const IR::Node *origin) : id(crtid++), origin(origin) {}
66 std::string explain(size_t index, Explain *explainer) const {
67 const auto *node = errArguments.at(index);
68 node->apply(*explainer);
69 return explainer->explanation;
70 }
71 std::string localError(Explain *explainer) const;
72
73 public:
74 void setError(std::string_view format, std::initializer_list<const IR::Node *> nodes) {
75 errFormat = cstring(format);
76 errArguments = nodes;
77 }
78 template <typename... Args>
79 // Always return false.
80 bool reportError(const TypeVariableSubstitution *subst, const char *format,
81 Args &&...args) const {
86 return reportErrorImpl(
87 subst, " ---- Actual error:\n" +
88 ::P4::error_helper(format, std::forward<Args>(args)...).toString());
89 }
90 // Default error message; returns 'false'
91 virtual bool reportError(const TypeVariableSubstitution *subst) const = 0;
92
93 DECLARE_TYPEINFO(TypeConstraint);
94};
95
97class BinaryConstraint : public TypeConstraint {
98 public:
99 const IR::Type *left;
100 const IR::Type *right;
101
102 protected:
103 BinaryConstraint(const IR::Type *left, const IR::Type *right, const TypeConstraint *derivedFrom)
104 : TypeConstraint(derivedFrom), left(left), right(right) {
105 validate();
106 }
107 BinaryConstraint(const IR::Type *left, const IR::Type *right, const IR::Node *origin)
108 : TypeConstraint(origin), left(left), right(right) {
109 validate();
110 }
111 void validate() const {
112 CHECK_NULL(left);
113 CHECK_NULL(right);
114 if (left->is<IR::Type_Name>() || right->is<IR::Type_Name>())
115 BUG("type names should not appear in unification: %1% and %2%", left, right);
116 }
117
118 public:
119 virtual BinaryConstraint *create(const IR::Type *left, const IR::Type *right) const = 0;
120
121 DECLARE_TYPEINFO(BinaryConstraint, TypeConstraint);
122};
123
125class EqualityConstraint : public BinaryConstraint {
126 public:
127 EqualityConstraint(const IR::Type *left, const IR::Type *right,
129 : BinaryConstraint(left, right, derivedFrom) {}
130 EqualityConstraint(const IR::Type *left, const IR::Type *right, const IR::Node *origin)
131 : BinaryConstraint(left, right, origin) {}
132 void dbprint(std::ostream &out) const override {
133 out << "Constraint:" << dbp(left) << " == " << dbp(right);
134 }
136 bool reportError(const TypeVariableSubstitution *subst) const override {
137 return reportError(subst, "Cannot unify type '%1%' with type '%2%'", right, left);
138 }
139 BinaryConstraint *create(const IR::Type *left, const IR::Type *right) const override {
140 return new EqualityConstraint(left, right, this);
141 }
142
143 DECLARE_TYPEINFO(EqualityConstraint, BinaryConstraint);
144};
145
147class CanBeImplicitlyCastConstraint : public BinaryConstraint {
148 public:
149 CanBeImplicitlyCastConstraint(const IR::Type *left, const IR::Type *right,
151 : BinaryConstraint(left, right, derivedFrom) {}
152 CanBeImplicitlyCastConstraint(const IR::Type *left, const IR::Type *right,
153 const IR::Node *origin)
154 : BinaryConstraint(left, right, origin) {}
155 void dbprint(std::ostream &out) const override {
156 out << "Constraint:" << dbp(left) << " := " << dbp(right);
157 }
159 bool reportError(const TypeVariableSubstitution *subst) const override {
160 return reportError(subst, "Cannot cast implicitly type '%1%' to type '%2%'", right, left);
161 }
162 BinaryConstraint *create(const IR::Type *left, const IR::Type *right) const override {
163 return new CanBeImplicitlyCastConstraint(left, right, this);
164 }
165
166 DECLARE_TYPEINFO(CanBeImplicitlyCastConstraint, BinaryConstraint);
167};
168
169// A list of equality constraints on types.
170class TypeConstraints final : public IHasDbPrint {
171 private:
172 /*
173 * Not all type variables that appear in unification can be bound:
174 * only the ones in this set can be.
175 *
176 * Consider this example:
177 *
178 * extern void f(in bit x);
179 * control p<T>(T data) { f(data); }
180 *
181 * This example should not typecheck: because T cannot be constrained in the invocation of f.
182 * While typechecking the f(data) call, T is not a type variable that can be unified.
183 */
184 absl::flat_hash_set<const IR::ITypeVar *, Util::Hash> unifiableTypeVariables;
185 std::vector<const TypeConstraint *> constraints;
186 TypeUnification *unification;
187 const TypeVariableSubstitution *definedVariables;
189 TypeVariableSubstitution *currentSubstitution;
190
191 public:
192 TypeVariableSubstitutionVisitor replaceVariables;
193
194 TypeConstraints(const TypeVariableSubstitution *definedVariables, const P4::TypeMap *typeMap)
195 : unification(new TypeUnification(this, typeMap)),
196 definedVariables(definedVariables),
197 currentSubstitution(new TypeVariableSubstitution()),
198 replaceVariables(definedVariables) {}
199 // Mark this variable as being free.
200 void addUnifiableTypeVariable(const IR::ITypeVar *typeVariable) {
201 LOG3("Adding unifiable type variable " << typeVariable);
202 unifiableTypeVariables.insert(typeVariable);
203 }
204
208 bool isUnifiableTypeVariable(const IR::Type *type);
209 void add(const TypeConstraint *constraint) {
210 LOG3("Adding constraint " << constraint);
211 constraints.push_back(constraint);
212 }
213 void addEqualityConstraint(const IR::Node *source, const IR::Type *left, const IR::Type *right);
214 void addImplicitCastConstraint(const IR::Node *source, const IR::Type *left,
215 const IR::Type *right);
216 /*
217 * Solve the specified constraint.
218 * @param subst Variable substitution which is updated with new constraints.
219 * @param constraint Constraint to solve.
220 * @return True on success. Does not report error on failure.
221 */
222 bool solve(const BinaryConstraint *constraint);
224 void dbprint(std::ostream &out) const;
225 const TypeVariableSubstitution *getCurrentSubstitution() const { return currentSubstitution; }
226};
227} // namespace P4
228
229#endif /* FRONTENDS_P4_TYPECHECKING_TYPECONSTRAINTS_H_ */
Base class for EqualityConstraint and CanBeImplicitlyCastConstraint.
Definition typeConstraints.h:97
Definition castable.h:27
Definition stringify.h:24
Definition node.h:44
Definition visitor.h:409
Definition typeConstraints.h:47
bool reportError(const TypeVariableSubstitution *subst, const char *format, Args &&...args) const
Definition typeConstraints.h:80
const IR::Node * origin
Place in source code which originated the contraint. May be nullptr.
Definition typeConstraints.h:61
const TypeConstraint * derivedFrom
Constraint which produced this one. May be nullptr.
Definition typeConstraints.h:59
bool isUnifiableTypeVariable(const IR::Type *type)
Definition typeConstraints.cpp:42
Definition typeMap.h:32
Definition typeUnification.h:30
Definition typeSubstitution.h:64
Definition typeSubstitutionVisitor.h:36
Definition visitor.h:69
Definition cstring.h:76
TODO: this is not really specific to BMV2, it should reside somewhere else.
Definition applyOptionsPragmas.cpp:13