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