mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
"Sober up" the type checker by improving type inference over dictionary
literals that lack a contextual type. This fixes SR-305
This commit is contained in:
@@ -69,6 +69,22 @@ static bool isArithmeticOperatorDecl(ValueDecl *vd) {
|
|||||||
vd->getName().str() == "%");
|
vd->getName().str() == "%");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool mergeRepresentativeEquivalenceClasses(ConstraintSystem &CS,
|
||||||
|
TypeVariableType* tyvar1,
|
||||||
|
TypeVariableType* tyvar2) {
|
||||||
|
if (tyvar1 && tyvar2) {
|
||||||
|
auto rep1 = CS.getRepresentative(tyvar1);
|
||||||
|
auto rep2 = CS.getRepresentative(tyvar2);
|
||||||
|
|
||||||
|
if (rep1 != rep2) {
|
||||||
|
CS.mergeEquivalenceClasses(rep1, rep2, /*updateWorkList*/ false);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
/// Internal struct for tracking information about types within a series
|
/// Internal struct for tracking information about types within a series
|
||||||
@@ -327,14 +343,7 @@ namespace {
|
|||||||
auto tyvar1 = acp1->getType()->getAs<TypeVariableType>();
|
auto tyvar1 = acp1->getType()->getAs<TypeVariableType>();
|
||||||
auto tyvar2 = acp2->getType()->getAs<TypeVariableType>();
|
auto tyvar2 = acp2->getType()->getAs<TypeVariableType>();
|
||||||
|
|
||||||
if (tyvar1 && tyvar2) {
|
mergeRepresentativeEquivalenceClasses(CS, tyvar1, tyvar2);
|
||||||
auto rep1 = CS.getRepresentative(tyvar1);
|
|
||||||
auto rep2 = CS.getRepresentative(tyvar2);
|
|
||||||
|
|
||||||
if (rep1 != rep2) {
|
|
||||||
CS.mergeEquivalenceClasses(rep1, rep2, /*updateWorkList*/ false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1859,6 +1868,12 @@ namespace {
|
|||||||
return arrayTy;
|
return arrayTy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool isMergeableValueKind(Expr *expr) {
|
||||||
|
return isa<CollectionExpr>(expr) ||
|
||||||
|
isa<StringLiteralExpr>(expr) || isa<IntegerLiteralExpr>(expr) ||
|
||||||
|
isa<FloatLiteralExpr>(expr);
|
||||||
|
}
|
||||||
|
|
||||||
Type visitDictionaryExpr(DictionaryExpr *expr) {
|
Type visitDictionaryExpr(DictionaryExpr *expr) {
|
||||||
ASTContext &C = CS.getASTContext();
|
ASTContext &C = CS.getASTContext();
|
||||||
// A dictionary expression can be of a type T that conforms to the
|
// A dictionary expression can be of a type T that conforms to the
|
||||||
@@ -1908,16 +1923,67 @@ namespace {
|
|||||||
TupleTypeElt(dictionaryValueTy) };
|
TupleTypeElt(dictionaryValueTy) };
|
||||||
Type elementTy = TupleType::get(tupleElts, C);
|
Type elementTy = TupleType::get(tupleElts, C);
|
||||||
|
|
||||||
|
// Keep track of which elements have been "merged". This way, we won't create
|
||||||
|
// needless conversion constraints for elements whose equivalence classes have
|
||||||
|
// been merged.
|
||||||
|
llvm::DenseSet<Expr *> mergedElements;
|
||||||
|
|
||||||
|
// If no contextual type is present, Merge equivalence classes of key
|
||||||
|
// and value types as necessary.
|
||||||
|
if (!CS.getContextualType(expr)) {
|
||||||
|
for (auto element1 : expr->getElements()) {
|
||||||
|
for (auto element2 : expr->getElements()) {
|
||||||
|
if (element1 == element2)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
auto tty1 = element1->getType()->getAs<TupleType>();
|
||||||
|
auto tty2 = element2->getType()->getAs<TupleType>();
|
||||||
|
|
||||||
|
if (tty1 && tty2) {
|
||||||
|
auto mergedKey = false;
|
||||||
|
auto mergedValue = false;
|
||||||
|
|
||||||
|
auto keyTyvar1 = tty1->getElementTypes()[0]->
|
||||||
|
getAs<TypeVariableType>();
|
||||||
|
auto keyTyvar2 = tty2->getElementTypes()[0]->
|
||||||
|
getAs<TypeVariableType>();
|
||||||
|
|
||||||
|
mergedKey = mergeRepresentativeEquivalenceClasses(CS,
|
||||||
|
keyTyvar1, keyTyvar2);
|
||||||
|
|
||||||
|
auto valueTyvar1 = tty1->getElementTypes()[1]->
|
||||||
|
getAs<TypeVariableType>();
|
||||||
|
auto valueTyvar2 = tty2->getElementTypes()[1]->
|
||||||
|
getAs<TypeVariableType>();
|
||||||
|
|
||||||
|
auto elemExpr1 = dyn_cast<TupleExpr>(element1)->getElements()[1];
|
||||||
|
auto elemExpr2 = dyn_cast<TupleExpr>(element2)->getElements()[1];
|
||||||
|
|
||||||
|
if (elemExpr1->getKind() == elemExpr2->getKind() &&
|
||||||
|
isMergeableValueKind(elemExpr1)) {
|
||||||
|
mergedValue = mergeRepresentativeEquivalenceClasses(CS,
|
||||||
|
valueTyvar1, valueTyvar2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mergedKey && mergedValue)
|
||||||
|
mergedElements.insert(element2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Introduce conversions from each element to the element type of the
|
// Introduce conversions from each element to the element type of the
|
||||||
// dictionary.
|
// dictionary. (If the equivalence class of an element has already been
|
||||||
|
// merged with a previous one, skip it.)
|
||||||
unsigned index = 0;
|
unsigned index = 0;
|
||||||
for (auto element : expr->getElements()) {
|
for (auto element : expr->getElements()) {
|
||||||
CS.addConstraint(ConstraintKind::Conversion,
|
if (!mergedElements.count(element))
|
||||||
element->getType(),
|
CS.addConstraint(ConstraintKind::Conversion,
|
||||||
elementTy,
|
element->getType(),
|
||||||
CS.getConstraintLocator(
|
elementTy,
|
||||||
expr,
|
CS.getConstraintLocator(
|
||||||
LocatorPathElt::getTupleElement(index++)));
|
expr,
|
||||||
|
LocatorPathElt::getTupleElement(index++)));
|
||||||
}
|
}
|
||||||
|
|
||||||
return dictionaryTy;
|
return dictionaryTy;
|
||||||
|
|||||||
26
test/expr/edge-contraction/dictionary-literal.swift
Normal file
26
test/expr/edge-contraction/dictionary-literal.swift
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
// RUN: %target-parse-verify-swift
|
||||||
|
|
||||||
|
let dict = [
|
||||||
|
"keys": [
|
||||||
|
"key 1": ["key": "value"],
|
||||||
|
"key 2": ["key": "value"],
|
||||||
|
"key 3": ["key": "value"],
|
||||||
|
"key 4": ["key": "value"],
|
||||||
|
"key 5": ["key": "value"],
|
||||||
|
"key 6": ["key": "value"],
|
||||||
|
"key 7": ["key": "value"],
|
||||||
|
"key 8": ["key": "value"],
|
||||||
|
"key 9": ["key": "value"],
|
||||||
|
"key 10": ["key": "value"],
|
||||||
|
"key 11": ["key": "value"],
|
||||||
|
"key 12": ["key": "value"],
|
||||||
|
"key 13": ["key": "value"],
|
||||||
|
"key 14": ["key": "value"],
|
||||||
|
"key 15": ["key": "value"],
|
||||||
|
"key 16": ["key": "value"],
|
||||||
|
"key 17": ["key": "value"],
|
||||||
|
"key 18": ["key": "value"],
|
||||||
|
"key 19": ["key": "value"],
|
||||||
|
"key 20": ["key": "value"],
|
||||||
|
]
|
||||||
|
]
|
||||||
Reference in New Issue
Block a user