Skip to content

Commit 6507563

Browse files
committed
Remove LinkedExprAnalyzer completely. Short-circuit generic overload disjunctions by testing last opened typevar.
1 parent 217be63 commit 6507563

File tree

4 files changed

+87
-378
lines changed

4 files changed

+87
-378
lines changed

lib/Sema/CSGen.cpp

Lines changed: 0 additions & 371 deletions
Original file line numberDiff line numberDiff line change
@@ -92,366 +92,6 @@ static bool mergeRepresentativeEquivalenceClasses(ConstraintSystem &CS,
9292
}
9393

9494
namespace {
95-
96-
/// Internal struct for tracking information about types within a series
97-
/// of "linked" expressions. (Such as a chain of binary operator invocations.)
98-
struct LinkedTypeInfo {
99-
unsigned haveIntLiteral : 1;
100-
unsigned haveFloatLiteral : 1;
101-
unsigned haveStringLiteral : 1;
102-
103-
llvm::SmallSet<TypeBase*, 16> collectedTypes;
104-
105-
llvm::SmallVector<TypeVariableType *, 16> intLiteralTyvars;
106-
llvm::SmallVector<TypeVariableType *, 16> floatLiteralTyvars;
107-
llvm::SmallVector<TypeVariableType *, 16> stringLiteralTyvars;
108-
109-
llvm::SmallVector<BinaryExpr *, 4> binaryExprs;
110-
111-
// TODO: manage as a set of lists, to speed up addition of binding
112-
// constraints.
113-
llvm::SmallVector<DeclRefExpr *, 16> anonClosureParams;
114-
115-
LinkedTypeInfo() {
116-
haveIntLiteral = false;
117-
haveFloatLiteral = false;
118-
haveStringLiteral = false;
119-
}
120-
121-
bool hasLiteral() {
122-
return haveIntLiteral || haveFloatLiteral || haveStringLiteral;
123-
}
124-
};
125-
126-
/// Walks an expression sub-tree, and collects information about expressions
127-
/// whose types are mutually dependent upon one another.
128-
class LinkedExprCollector : public ASTWalker {
129-
130-
llvm::SmallVectorImpl<Expr*> &LinkedExprs;
131-
ConstraintSystem &CS;
132-
133-
public:
134-
LinkedExprCollector(llvm::SmallVectorImpl<Expr *> &linkedExprs,
135-
ConstraintSystem &cs)
136-
: LinkedExprs(linkedExprs), CS(cs) {}
137-
138-
std::pair<bool, Expr *> walkToExprPre(Expr *expr) override {
139-
140-
if (CS.shouldReusePrecheckedType() &&
141-
!CS.getType(expr)->hasTypeVariable()) {
142-
return { false, expr };
143-
}
144-
145-
// Store top-level binary exprs for further analysis.
146-
if (isa<BinaryExpr>(expr) ||
147-
148-
// Literal exprs are contextually typed, so store them off as well.
149-
isa<LiteralExpr>(expr) ||
150-
151-
// We'd like to take a look at implicit closure params, so store
152-
// them.
153-
isa<ClosureExpr>(expr) ||
154-
155-
// We'd like to look at the elements of arrays and dictionaries.
156-
isa<ArrayExpr>(expr) ||
157-
isa<DictionaryExpr>(expr) ||
158-
159-
// assignment expression can involve anonymous closure parameters
160-
// as source and destination, so it's beneficial for diagnostics if
161-
// we look at the assignment.
162-
isa<AssignExpr>(expr)) {
163-
LinkedExprs.push_back(expr);
164-
return {false, expr};
165-
}
166-
167-
return { true, expr };
168-
}
169-
170-
Expr *walkToExprPost(Expr *expr) override {
171-
return expr;
172-
}
173-
174-
/// Ignore statements.
175-
std::pair<bool, Stmt *> walkToStmtPre(Stmt *stmt) override {
176-
return { false, stmt };
177-
}
178-
179-
/// Ignore declarations.
180-
bool walkToDeclPre(Decl *decl) override { return false; }
181-
182-
/// Ignore patterns.
183-
std::pair<bool, Pattern*> walkToPatternPre(Pattern *pat) override {
184-
return { false, pat };
185-
}
186-
187-
/// Ignore types.
188-
bool walkToTypeLocPre(TypeLoc &TL) override { return false; }
189-
};
190-
191-
/// Given a collection of "linked" expressions, analyzes them for
192-
/// commonalities regarding their types. This will help us compute a
193-
/// "best common type" from the expression types.
194-
class LinkedExprAnalyzer : public ASTWalker {
195-
196-
LinkedTypeInfo &LTI;
197-
ConstraintSystem &CS;
198-
199-
public:
200-
201-
LinkedExprAnalyzer(LinkedTypeInfo &lti, ConstraintSystem &cs) :
202-
LTI(lti), CS(cs) {}
203-
204-
std::pair<bool, Expr *> walkToExprPre(Expr *expr) override {
205-
206-
if (CS.shouldReusePrecheckedType() &&
207-
!CS.getType(expr)->hasTypeVariable()) {
208-
return { false, expr };
209-
}
210-
211-
if (isa<IntegerLiteralExpr>(expr)) {
212-
LTI.haveIntLiteral = true;
213-
auto tyvar = CS.getType(expr)->getAs<TypeVariableType>();
214-
215-
if (tyvar) {
216-
LTI.intLiteralTyvars.push_back(tyvar);
217-
}
218-
219-
return { false, expr };
220-
}
221-
222-
if (isa<FloatLiteralExpr>(expr)) {
223-
LTI.haveFloatLiteral = true;
224-
auto tyvar = CS.getType(expr)->getAs<TypeVariableType>();
225-
226-
if (tyvar) {
227-
LTI.floatLiteralTyvars.push_back(tyvar);
228-
}
229-
230-
return { false, expr };
231-
}
232-
233-
if (isa<StringLiteralExpr>(expr)) {
234-
LTI.haveStringLiteral = true;
235-
236-
auto tyvar = CS.getType(expr)->getAs<TypeVariableType>();
237-
238-
if (tyvar) {
239-
LTI.stringLiteralTyvars.push_back(tyvar);
240-
}
241-
242-
return { false, expr };
243-
}
244-
245-
if (isa<CollectionExpr>(expr)) {
246-
return { true, expr };
247-
}
248-
249-
if (auto UDE = dyn_cast<UnresolvedDotExpr>(expr)) {
250-
251-
if (CS.hasType(UDE))
252-
LTI.collectedTypes.insert(CS.getType(UDE).getPointer());
253-
254-
// Don't recurse into the base expression.
255-
return { false, expr };
256-
}
257-
258-
259-
if (isa<ClosureExpr>(expr)) {
260-
return { true, expr };
261-
}
262-
263-
if (auto FVE = dyn_cast<ForceValueExpr>(expr)) {
264-
LTI.collectedTypes.insert(CS.getType(FVE).getPointer());
265-
return { false, expr };
266-
}
267-
268-
if (auto DRE = dyn_cast<DeclRefExpr>(expr)) {
269-
if (auto varDecl = dyn_cast<VarDecl>(DRE->getDecl())) {
270-
if (isa<ParamDecl>(varDecl) &&
271-
cast<ParamDecl>(varDecl)->isAnonClosureParam()) {
272-
LTI.anonClosureParams.push_back(DRE);
273-
} else if (CS.hasType(DRE)) {
274-
LTI.collectedTypes.insert(CS.getType(DRE).getPointer());
275-
}
276-
return { false, expr };
277-
}
278-
}
279-
280-
// In the case of a function application, we would have already captured
281-
// the return type during constraint generation, so there's no use in
282-
// looking any further.
283-
if (isa<ApplyExpr>(expr) &&
284-
!(isa<BinaryExpr>(expr) || isa<PrefixUnaryExpr>(expr) ||
285-
isa<PostfixUnaryExpr>(expr))) {
286-
return { false, expr };
287-
}
288-
289-
if (isa<BinaryExpr>(expr)) {
290-
LTI.binaryExprs.push_back(dyn_cast<BinaryExpr>(expr));
291-
}
292-
293-
if (auto favoredType = CS.getFavoredType(expr)) {
294-
LTI.collectedTypes.insert(favoredType);
295-
296-
return { false, expr };
297-
}
298-
299-
// Optimize branches of a conditional expression separately.
300-
if (auto IE = dyn_cast<IfExpr>(expr)) {
301-
CS.optimizeConstraints(IE->getCondExpr());
302-
CS.optimizeConstraints(IE->getThenExpr());
303-
CS.optimizeConstraints(IE->getElseExpr());
304-
return { false, expr };
305-
}
306-
307-
// For exprs of a structural type that are not modeling argument lists,
308-
// avoid merging the type variables. (We need to allow for cases like
309-
// (Int, Int32).)
310-
if (isa<TupleExpr>(expr) && !isa<ApplyExpr>(Parent.getAsExpr())) {
311-
return { false, expr };
312-
}
313-
314-
// Coercion exprs have a rigid type, so there's no use in gathering info
315-
// about them.
316-
if (auto *coercion = dyn_cast<CoerceExpr>(expr)) {
317-
// Let's not collect information about types initialized by
318-
// coercions just like we don't for regular initializer calls,
319-
// because that might lead to overly eager type variable merging.
320-
if (!coercion->isLiteralInit())
321-
LTI.collectedTypes.insert(CS.getType(expr).getPointer());
322-
return { false, expr };
323-
}
324-
325-
// Don't walk into subscript expressions - to do so would risk factoring
326-
// the index expression into edge contraction. (We don't want to do this
327-
// if the index expression is a literal type that differs from the return
328-
// type of the subscript operation.)
329-
if (isa<SubscriptExpr>(expr) || isa<DynamicLookupExpr>(expr)) {
330-
return { false, expr };
331-
}
332-
333-
// Don't walk into unresolved member expressions - we avoid merging type
334-
// variables inside UnresolvedMemberExpr and those outside, since they
335-
// should be allowed to behave independently in CS.
336-
if (isa<UnresolvedMemberExpr>(expr)) {
337-
return {false, expr };
338-
}
339-
340-
return { true, expr };
341-
}
342-
343-
/// Ignore statements.
344-
std::pair<bool, Stmt *> walkToStmtPre(Stmt *stmt) override {
345-
return { false, stmt };
346-
}
347-
348-
/// Ignore declarations.
349-
bool walkToDeclPre(Decl *decl) override { return false; }
350-
351-
/// Ignore patterns.
352-
std::pair<bool, Pattern*> walkToPatternPre(Pattern *pat) override {
353-
return { false, pat };
354-
}
355-
356-
/// Ignore types.
357-
bool walkToTypeLocPre(TypeLoc &TL) override { return false; }
358-
};
359-
360-
/// For a given expression, given information that is global to the
361-
/// expression, attempt to derive a favored type for it.
362-
bool computeFavoredTypeForExpr(Expr *expr, ConstraintSystem &CS) {
363-
LinkedTypeInfo lti;
364-
365-
expr->walk(LinkedExprAnalyzer(lti, CS));
366-
367-
// Link anonymous closure params of the same index.
368-
// TODO: As stated above, we should bucket these whilst collecting the
369-
// exprs to avoid quadratic behavior.
370-
for (auto acp1 : lti.anonClosureParams) {
371-
for (auto acp2 : lti.anonClosureParams) {
372-
if (acp1 == acp2)
373-
continue;
374-
375-
if (acp1->getDecl()->getBaseName() == acp2->getDecl()->getBaseName()) {
376-
377-
auto tyvar1 = CS.getType(acp1)->getAs<TypeVariableType>();
378-
auto tyvar2 = CS.getType(acp2)->getAs<TypeVariableType>();
379-
380-
mergeRepresentativeEquivalenceClasses(CS, tyvar1, tyvar2);
381-
}
382-
}
383-
}
384-
385-
auto mergeTypeVariables = [&](ArrayRef<TypeVariableType *> typeVars) {
386-
if (typeVars.size() < 2)
387-
return;
388-
389-
auto rep1 = CS.getRepresentative(typeVars.front());
390-
for (unsigned i = 1, n = typeVars.size(); i != n; ++i) {
391-
auto rep2 = CS.getRepresentative(typeVars[i]);
392-
if (rep1 != rep2)
393-
CS.mergeEquivalenceClasses(rep1, rep2, /*updateWorkList*/ false);
394-
}
395-
};
396-
397-
mergeTypeVariables(lti.intLiteralTyvars);
398-
mergeTypeVariables(lti.floatLiteralTyvars);
399-
mergeTypeVariables(lti.stringLiteralTyvars);
400-
401-
if (lti.collectedTypes.size() == 1) {
402-
// TODO: Compute the BCT.
403-
404-
// It's only useful to favor the type instead of
405-
// binding it directly to arguments/result types,
406-
// which means in case it has been miscalculated
407-
// solver can still make progress.
408-
auto favoredTy = (*lti.collectedTypes.begin())->getWithoutSpecifierType();
409-
CS.setFavoredType(expr, favoredTy.getPointer());
410-
return true;
411-
}
412-
413-
if (lti.haveFloatLiteral) {
414-
if (auto floatProto =
415-
CS.TC.Context.getProtocol(
416-
KnownProtocolKind::ExpressibleByFloatLiteral)) {
417-
if (auto defaultType = CS.TC.getDefaultType(floatProto, CS.DC)) {
418-
if (!CS.getFavoredType(expr)) {
419-
CS.setFavoredType(expr, defaultType.getPointer());
420-
}
421-
return true;
422-
}
423-
}
424-
}
425-
426-
if (lti.haveIntLiteral) {
427-
if (auto intProto =
428-
CS.TC.Context.getProtocol(
429-
KnownProtocolKind::ExpressibleByIntegerLiteral)) {
430-
if (auto defaultType = CS.TC.getDefaultType(intProto, CS.DC)) {
431-
if (!CS.getFavoredType(expr)) {
432-
CS.setFavoredType(expr, defaultType.getPointer());
433-
}
434-
return true;
435-
}
436-
}
437-
}
438-
439-
if (lti.haveStringLiteral) {
440-
if (auto stringProto =
441-
CS.TC.Context.getProtocol(
442-
KnownProtocolKind::ExpressibleByStringLiteral)) {
443-
if (auto defaultType = CS.TC.getDefaultType(stringProto, CS.DC)) {
444-
if (!CS.getFavoredType(expr)) {
445-
CS.setFavoredType(expr, defaultType.getPointer());
446-
}
447-
return true;
448-
}
449-
}
450-
}
451-
452-
return false;
453-
}
454-
45595
/// Determine whether the given parameter type and argument should be
45696
/// "favored" because they match exactly.
45797
bool isFavoredParamAndArg(ConstraintSystem &CS,
@@ -3658,17 +3298,6 @@ void ConstraintSystem::optimizeConstraints(Expr *e) {
36583298
if (TC.getLangOpts().DisableConstraintSolverPerformanceHacks)
36593299
return;
36603300

3661-
SmallVector<Expr *, 16> linkedExprs;
3662-
3663-
// Collect any linked expressions.
3664-
LinkedExprCollector collector(linkedExprs, *this);
3665-
e->walk(collector);
3666-
3667-
// Favor types, as appropriate.
3668-
for (auto linkedExpr : linkedExprs) {
3669-
computeFavoredTypeForExpr(linkedExpr, *this);
3670-
}
3671-
36723301
// Optimize the constraints.
36733302
ConstraintOptimizer optimizer(*this);
36743303
e->walk(optimizer);

0 commit comments

Comments
 (0)