Skip to content

Commit 7da802e

Browse files
authored
Merge pull request #665 from glu-lang/sema-simplify
[Sema] Feature: CS Simplify
2 parents 4a80818 + 700ca69 commit 7da802e

5 files changed

Lines changed: 120 additions & 69 deletions

File tree

include/Sema/ConstraintSystem.hpp

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -225,8 +225,22 @@ class ConstraintSystem {
225225
/// splitting of the constraint system, and before mapping types back to the
226226
/// AST.
227227
/// @param result The solution result to populate with found solutions.
228+
/// @param initialState The initial state with early unification bindings.
228229
/// @return True if a solution was found, false otherwise.
229-
bool solveLocalConstraints(SolutionResult &result);
230+
bool solveLocalConstraints(
231+
SolutionResult &result, SystemState const &initialState
232+
);
233+
234+
/// @brief Simplifies the constraint system before solving.
235+
///
236+
/// This method performs various optimizations on the constraint set:
237+
/// - Eliminates redundant constraints
238+
/// - Pre-filters impossible overload choices
239+
/// - Reorders constraints for optimal evaluation
240+
/// - Performs early unification where possible
241+
///
242+
/// @return Initial SystemState with early unification bindings applied.
243+
SystemState simplifyConstraints();
230244

231245
/// @brief Solves all constraints and applies mappings.
232246
///
@@ -428,6 +442,10 @@ class ConstraintSystem {
428442

429443
/// @brief Print all constraints in a ConstraintSystem for debugging.
430444
void print();
445+
446+
private:
447+
// Constraint simplification passes
448+
void reorderConstraintsByPriority();
431449
};
432450

433451
/// @brief Print all constraints in a ConstraintSystem for debugging.

lib/Sema/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ target_sources(Sema
2121
ConstraintSystem/ConstraintPrinter.cpp
2222
ConstraintSystem/ConstraintSystem.cpp
2323
ConstraintSystem/ConversionVisitor.cpp
24+
ConstraintSystem/CSSimplify.cpp
2425
ConstraintSystem/LocalCSWalker.cpp
2526
ConstraintSystem/OccursCheckVisitor.cpp
2627
ConstraintSystem/Solver.cpp
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
#include "ConstraintSystem.hpp"
2+
3+
#include "AST/Expr/CallExpr.hpp"
4+
#include "AST/Expr/RefExpr.hpp"
5+
#include "AST/Types/FunctionTy.hpp"
6+
#include "AST/Types/TypeVariableTy.hpp"
7+
8+
#include <algorithm>
9+
10+
namespace glu::sema {
11+
12+
SystemState ConstraintSystem::simplifyConstraints()
13+
{
14+
// Create initial state for simplification
15+
SystemState initialState(_context);
16+
17+
reorderConstraintsByPriority();
18+
19+
return initialState;
20+
}
21+
22+
enum class ConstraintPriority : unsigned {
23+
// Priority 0: Immediate - simple deterministic bindings
24+
Immediate = 0,
25+
// Priority 1: Normal constraints
26+
Normal = 1,
27+
// Priority 2: Deferred constraints (like StructInitialiser)
28+
Deferred = 2,
29+
// Priority 3: Defaultable constraints (last resort)
30+
Defaultable = 3,
31+
// Priority 4: Type property constraints (checks only)
32+
TypeProperty = 4
33+
};
34+
35+
static ConstraintPriority getPriority(Constraint *constraint)
36+
{
37+
ConstraintKind kind = constraint->getKind();
38+
39+
if (kind == ConstraintKind::Bind || kind == ConstraintKind::Equal
40+
|| kind == ConstraintKind::BindToPointerType) {
41+
return ConstraintPriority::Immediate;
42+
}
43+
44+
if (kind == ConstraintKind::StructInitialiser) {
45+
return ConstraintPriority::Deferred;
46+
}
47+
48+
if (kind == ConstraintKind::Defaultable) {
49+
return ConstraintPriority::Defaultable;
50+
}
51+
52+
if (constraint->isTypePropertyConstraint()) {
53+
return ConstraintPriority::TypeProperty;
54+
}
55+
56+
return ConstraintPriority::Normal;
57+
}
58+
59+
void ConstraintSystem::reorderConstraintsByPriority()
60+
{
61+
// Reorder constraints by priority - lower priority number = processed first
62+
// This eliminates the need for multiple passes in solveLocalConstraints
63+
std::stable_sort(
64+
_constraints.begin(), _constraints.end(),
65+
[](Constraint *a, Constraint *b) {
66+
return getPriority(a) < getPriority(b);
67+
}
68+
);
69+
}
70+
71+
} // namespace glu::sema

lib/Sema/ConstraintSystem/ConstraintSystem.cpp

Lines changed: 22 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -145,84 +145,32 @@ void ConstraintSystem::mapImplicitConversions(Solution *solution)
145145
}
146146
}
147147

148-
bool ConstraintSystem::solveLocalConstraints(SolutionResult &result)
148+
bool ConstraintSystem::solveLocalConstraints(
149+
SolutionResult &result, SystemState const &initialState
150+
)
149151
{
150-
/// The initial system state used to begin constraint solving.
151-
std::vector<SystemState> worklist;
152-
worklist.emplace_back(_context); // Start from an empty state
152+
/// The initial system state with early unification bindings applied
153+
std::vector<std::pair<SystemState, size_t>> worklist;
154+
worklist.push_back({ initialState, 0 }); // Start from the simplified state
153155

154156
while (!worklist.empty()) {
155-
SystemState current = std::move(worklist.back());
157+
SystemState current = std::move(worklist.back().first);
158+
size_t index = worklist.back().second;
156159
worklist.pop_back();
157160

158-
/// Apply non-defaultable constraints first
159-
for (Constraint *constraint : _constraints) {
160-
// Skip disabled constraints
161-
if (constraint->isDisabled())
162-
continue;
163-
164-
// Skip defaultable constraints in first pass
165-
if (constraint->getKind() == ConstraintKind::Defaultable
166-
|| constraint->isTypePropertyConstraint()
167-
|| constraint->getKind() == ConstraintKind::StructInitialiser) {
168-
continue;
169-
}
170-
171-
/// Apply the constraint and check the result.
172-
ConstraintResult result = apply(constraint, current, worklist);
173-
markConstraint(result, constraint);
174-
if (result == ConstraintResult::Failed) {
175-
goto failed;
176-
}
177-
// Continue if Satisfied or Applied
178-
}
179-
180-
for (Constraint *constraint : _constraints) {
181-
if (constraint->isDisabled())
182-
continue;
183-
if (constraint->getKind() != ConstraintKind::StructInitialiser)
184-
continue;
185-
/// Apply the constraint and check the result.
186-
ConstraintResult result = apply(constraint, current, worklist);
187-
markConstraint(result, constraint);
188-
if (result == ConstraintResult::Failed) {
189-
goto failed;
190-
}
191-
}
161+
while (index < _constraints.size()) {
162+
Constraint *constraint = _constraints[index++];
192163

193-
/// Apply defaultable constraints only if non-defaultable
194-
/// constraints succeed
195-
for (Constraint *constraint : _constraints) {
196164
// Skip disabled constraints
197165
if (constraint->isDisabled())
198166
continue;
199167

200-
// Only process defaultable constraints in second pass
201-
if (constraint->getKind() != ConstraintKind::Defaultable)
202-
continue;
203-
204168
/// Apply the constraint and check the result.
205-
ConstraintResult result = apply(constraint, current, worklist);
206-
markConstraint(result, constraint);
207-
if (result == ConstraintResult::Failed) {
208-
goto failed;
169+
std::vector<SystemState> newStates;
170+
ConstraintResult result = apply(constraint, current, newStates);
171+
for (auto &newState : newStates) {
172+
worklist.push_back({ std::move(newState), index });
209173
}
210-
// Continue if Satisfied or Applied
211-
}
212-
213-
/// Apply ExpressibleByLiterals constraints only if other
214-
/// constraints succeed
215-
for (Constraint *constraint : _constraints) {
216-
// Skip disabled constraints
217-
if (constraint->isDisabled())
218-
continue;
219-
220-
// Only process ExpressibleByLiterals constraints in third pass
221-
if (!constraint->isTypePropertyConstraint())
222-
continue;
223-
224-
/// Apply the constraint and check the result.
225-
ConstraintResult result = apply(constraint, current, worklist);
226174
markConstraint(result, constraint);
227175
if (result == ConstraintResult::Failed) {
228176
goto failed;
@@ -253,6 +201,10 @@ bool ConstraintSystem::solveLocalConstraints(SolutionResult &result)
253201

254202
bool ConstraintSystem::solveConstraints()
255203
{
204+
// Simplify constraints before solving and get initial state with early
205+
// bindings
206+
SystemState initialState = simplifyConstraints();
207+
256208
// color the constraints based on which type variables they contain
257209
// map of color => set of used type variables
258210
std::vector<llvm::DenseSet<glu::types::TypeVariableTy *>> colors;
@@ -294,14 +246,16 @@ bool ConstraintSystem::solveConstraints()
294246
}
295247
} while (changed);
296248
// solve each color separately
297-
SystemState finalSolution(_context);
249+
// Start with the initial state from simplification
250+
SystemState finalSolution = initialState;
251+
298252
for (std::size_t i = 0; i < colors.size(); ++i) {
299253
// Disable all constraints not in this color
300254
for (auto *constraint : _constraints) {
301255
constraint->setEnabled(colorConstraints[i].count(constraint));
302256
}
303257
SolutionResult result;
304-
if (!solveLocalConstraints(result)) {
258+
if (!solveLocalConstraints(result, initialState)) {
305259
return false;
306260
}
307261
result.getBestSolution()->mergeInto(finalSolution);

lib/Sema/ConstraintSystem/TypeVariableCollector.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,13 @@ void collectTypeVariables(
6868
&& constraint->getKind() != ConstraintKind::BindOverload
6969
&& constraint->getKind() != ConstraintKind::StructInitialiser)
7070
collector.visit(constraint->getSecondType());
71+
if (constraint->getKind() == ConstraintKind::StructInitialiser) {
72+
for (auto &field :
73+
llvm::cast<ast::StructInitializerExpr>(constraint->getLocator())
74+
->getFields()) {
75+
collector.visit(field->getType());
76+
}
77+
}
7178
}
7279

7380
} // namespace glu::sema

0 commit comments

Comments
 (0)