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 boost::format fmt(format);
87 return reportErrorImpl(subst,
88 " ---- Actual error:\n" +
89 ::P4::error_helper(fmt, std::forward<Args>(args)...).toString());
90 }
91 // Default error message; returns 'false'
92 virtual bool reportError(const TypeVariableSubstitution *subst) const = 0;
93
94 DECLARE_TYPEINFO(TypeConstraint);
95};
96
98class BinaryConstraint : public TypeConstraint {
99 public:
100 const IR::Type *left;
101 const IR::Type *right;
102
103 protected:
104 BinaryConstraint(const IR::Type *left, const IR::Type *right, const TypeConstraint *derivedFrom)
105 : TypeConstraint(derivedFrom), left(left), right(right) {
106 validate();
107 }
108 BinaryConstraint(const IR::Type *left, const IR::Type *right, const IR::Node *origin)
109 : TypeConstraint(origin), left(left), right(right) {
110 validate();
111 }
112 void validate() const {
113 CHECK_NULL(left);
114 CHECK_NULL(right);
115 if (left->is<IR::Type_Name>() || right->is<IR::Type_Name>())
116 BUG("type names should not appear in unification: %1% and %2%", left, right);
117 }
118
119 public:
120 virtual BinaryConstraint *create(const IR::Type *left, const IR::Type *right) const = 0;
121
122 DECLARE_TYPEINFO(BinaryConstraint, TypeConstraint);
123};
124
126class EqualityConstraint : public BinaryConstraint {
127 public:
128 EqualityConstraint(const IR::Type *left, const IR::Type *right,
130 : BinaryConstraint(left, right, derivedFrom) {}
131 EqualityConstraint(const IR::Type *left, const IR::Type *right, const IR::Node *origin)
132 : BinaryConstraint(left, right, origin) {}
133 void dbprint(std::ostream &out) const override {
134 out << "Constraint:" << dbp(left) << " == " << dbp(right);
135 }
137 bool reportError(const TypeVariableSubstitution *subst) const override {
138 return reportError(subst, "Cannot unify type '%1%' with type '%2%'", right, left);
139 }
140 BinaryConstraint *create(const IR::Type *left, const IR::Type *right) const override {
141 return new EqualityConstraint(left, right, this);
142 }
143
144 DECLARE_TYPEINFO(EqualityConstraint, BinaryConstraint);
145};
146
148class CanBeImplicitlyCastConstraint : public BinaryConstraint {
149 public:
150 CanBeImplicitlyCastConstraint(const IR::Type *left, const IR::Type *right,
152 : BinaryConstraint(left, right, derivedFrom) {}
153 CanBeImplicitlyCastConstraint(const IR::Type *left, const IR::Type *right,
154 const IR::Node *origin)
155 : BinaryConstraint(left, right, origin) {}
156 void dbprint(std::ostream &out) const override {
157 out << "Constraint:" << dbp(left) << " := " << dbp(right);
158 }
160 bool reportError(const TypeVariableSubstitution *subst) const override {
161 return reportError(subst, "Cannot cast implicitly type '%1%' to type '%2%'", right, left);
162 }
163 BinaryConstraint *create(const IR::Type *left, const IR::Type *right) const override {
164 return new CanBeImplicitlyCastConstraint(left, right, this);
165 }
166
167 DECLARE_TYPEINFO(CanBeImplicitlyCastConstraint, BinaryConstraint);
168};
169
170// A list of equality constraints on types.
171class TypeConstraints final : public IHasDbPrint {
172 private:
173 /*
174 * Not all type variables that appear in unification can be bound:
175 * only the ones in this set can be.
176 *
177 * Consider this example:
178 *
179 * extern void f(in bit x);
180 * control p<T>(T data) { f(data); }
181 *
182 * This example should not typecheck: because T cannot be constrained in the invocation of f.
183 * While typechecking the f(data) call, T is not a type variable that can be unified.
184 */
185 absl::flat_hash_set<const IR::ITypeVar *, Util::Hash> unifiableTypeVariables;
186 std::vector<const TypeConstraint *> constraints;
187 TypeUnification *unification;
188 const TypeVariableSubstitution *definedVariables;
190 TypeVariableSubstitution *currentSubstitution;
191
192 public:
193 TypeVariableSubstitutionVisitor replaceVariables;
194
195 TypeConstraints(const TypeVariableSubstitution *definedVariables, const P4::TypeMap *typeMap)
196 : unification(new TypeUnification(this, typeMap)),
197 definedVariables(definedVariables),
198 currentSubstitution(new TypeVariableSubstitution()),
199 replaceVariables(definedVariables) {}
200 // Mark this variable as being free.
201 void addUnifiableTypeVariable(const IR::ITypeVar *typeVariable) {
202 LOG3("Adding unifiable type variable " << typeVariable);
203 unifiableTypeVariables.insert(typeVariable);
204 }
205
209 bool isUnifiableTypeVariable(const IR::Type *type);
210 void add(const TypeConstraint *constraint) {
211 LOG3("Adding constraint " << constraint);
212 constraints.push_back(constraint);
213 }
214 void addEqualityConstraint(const IR::Node *source, const IR::Type *left, const IR::Type *right);
215 void addImplicitCastConstraint(const IR::Node *source, const IR::Type *left,
216 const IR::Type *right);
217 /*
218 * Solve the specified constraint.
219 * @param subst Variable substitution which is updated with new constraints.
220 * @param constraint Constraint to solve.
221 * @return True on success. Does not report error on failure.
222 */
223 bool solve(const BinaryConstraint *constraint);
225 void dbprint(std::ostream &out) const;
226 const TypeVariableSubstitution *getCurrentSubstitution() const { return currentSubstitution; }
227};
228} // namespace P4
229
230#endif /* FRONTENDS_P4_TYPECHECKING_TYPECONSTRAINTS_H_ */
Base class for EqualityConstraint and CanBeImplicitlyCastConstraint.
Definition typeConstraints.h:98
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