@@ -1342,6 +1342,13 @@ bool ConstraintSystem::Candidate::solve() {
1342
1342
// Allocate new constraint system for sub-expression.
1343
1343
ConstraintSystem cs (TC, DC, None);
1344
1344
1345
+ // Set contextual type if present. This is done before constraint generation
1346
+ // to give a "hint" to that operation about possible optimizations.
1347
+ auto CT = IsPrimary ? CS.getContextualType () : CS.getContextualType (E);
1348
+ if (!CT.isNull ())
1349
+ cs.setContextualType (E, CS.getContextualTypeLoc (),
1350
+ CS.getContextualTypePurpose ());
1351
+
1345
1352
// Generate constraints for the new system.
1346
1353
if (auto generatedExpr = cs.generateConstraints (E)) {
1347
1354
E = generatedExpr;
@@ -1355,7 +1362,7 @@ bool ConstraintSystem::Candidate::solve() {
1355
1362
// constraint to the system.
1356
1363
if (!CT.isNull ()) {
1357
1364
auto constraintKind = ConstraintKind::Conversion;
1358
- if (CTP == CTP_CallArgument)
1365
+ if (CS. getContextualTypePurpose () == CTP_CallArgument)
1359
1366
constraintKind = ConstraintKind::ArgumentConversion;
1360
1367
1361
1368
cs.addConstraint (constraintKind, E->getType (), CT,
@@ -1469,21 +1476,52 @@ void ConstraintSystem::shrink(Expr *expr) {
1469
1476
std::pair<bool , Expr *> walkToExprPre (Expr *expr) override {
1470
1477
// A dictionary expression is just a set of tuples; try to solve ones
1471
1478
// that have overload sets.
1472
- if (auto collectionExpr = dyn_cast<CollectionExpr>(expr)) {
1473
- visitCollectionExpr (collectionExpr);
1479
+ if (auto dictionaryExpr = dyn_cast<DictionaryExpr>(expr)) {
1480
+ bool isPrimaryExpr = expr == PrimaryExpr;
1481
+ for (auto element : dictionaryExpr->getElements ()) {
1482
+ unsigned numOverloads = 0 ;
1483
+ element->walk (OverloadSetCounter (numOverloads));
1484
+
1485
+ // There are no overload sets in the element; skip it.
1486
+ if (numOverloads == 0 )
1487
+ continue ;
1488
+
1489
+ // FIXME: Could we avoid creating a separate dictionary expression
1490
+ // here by introducing a contextual type on the element?
1491
+ auto dict = DictionaryExpr::create (CS.getASTContext (),
1492
+ dictionaryExpr->getLBracketLoc (),
1493
+ { element },
1494
+ dictionaryExpr->getRBracketLoc (),
1495
+ dictionaryExpr->getType ());
1496
+
1497
+ // Make each of the dictionary elements an independent dictionary,
1498
+ // such makes it easy to type-check everything separately.
1499
+ Candidates.push_back (Candidate (CS, dict, isPrimaryExpr));
1500
+ }
1501
+
1474
1502
// Don't try to walk into the dictionary.
1503
+ return { false , expr };
1504
+ }
1505
+
1506
+ // Consider all of the collections to be candidates,
1507
+ // FIXME: try to split collections into parts for simplified solving.
1508
+ if (isa<CollectionExpr>(expr)) {
1509
+ Candidates.push_back (Candidate (CS, expr, false ));
1475
1510
return {false , expr};
1476
1511
}
1477
1512
1478
1513
// Let's not attempt to type-check closures, which has already been
1479
1514
// type checked anyway.
1480
1515
if (isa<ClosureExpr>(expr)) {
1481
- return {false , expr};
1516
+ return { false , expr };
1482
1517
}
1483
1518
1519
+ // Coerce to type expressions are only viable if they have
1520
+ // a single child expression.
1484
1521
if (auto coerceExpr = dyn_cast<CoerceExpr>(expr)) {
1485
- visitCoerceExpr (coerceExpr);
1486
- return {false , expr};
1522
+ if (!coerceExpr->getSubExpr ()) {
1523
+ return { false , expr };
1524
+ }
1487
1525
}
1488
1526
1489
1527
if (auto OSR = dyn_cast<OverloadSetRefExpr>(expr)) {
@@ -1501,24 +1539,12 @@ void ConstraintSystem::shrink(Expr *expr) {
1501
1539
}
1502
1540
1503
1541
Expr *walkToExprPost (Expr *expr) override {
1504
- if (expr == PrimaryExpr) {
1505
- // If this is primary expression and there are no candidates
1506
- // to be solved, let's not record it, because it's going to be
1507
- // solved irregardless.
1508
- if (Candidates.empty ())
1509
- return expr;
1510
-
1511
- auto contextualType = CS.getContextualType ();
1512
- // If there is a contextual type set for this expression.
1513
- if (!contextualType.isNull ()) {
1514
- Candidates.push_back (Candidate (CS, expr, contextualType,
1515
- CS.getContextualTypePurpose ()));
1516
- return expr;
1517
- }
1518
-
1519
- // Or it's a function application with other candidates present.
1520
- if (isa<ApplyExpr>(expr)) {
1521
- Candidates.push_back (Candidate (CS, expr));
1542
+ // If there are sub-expressions to consider and
1543
+ // contextual type is involved, let's add top-most expression
1544
+ // to the queue just to make sure that we didn't miss any solutions.
1545
+ if (expr == PrimaryExpr && !Candidates.empty ()) {
1546
+ if (!CS.getContextualType ().isNull ()) {
1547
+ Candidates.push_back (Candidate (CS, expr, true ));
1522
1548
return expr;
1523
1549
}
1524
1550
}
@@ -1548,157 +1574,10 @@ void ConstraintSystem::shrink(Expr *expr) {
1548
1574
// there is no point of solving this expression,
1549
1575
// because we won't be able to reduce its domain.
1550
1576
if (numOverloadSets > 1 )
1551
- Candidates.push_back (Candidate (CS, expr));
1577
+ Candidates.push_back (Candidate (CS, expr, expr == PrimaryExpr ));
1552
1578
1553
1579
return expr;
1554
1580
}
1555
-
1556
- private:
1557
- // / \brief Extract type of the element from given collection type.
1558
- // /
1559
- // / \param collection The type of the collection container.
1560
- // /
1561
- // / \returns ErrorType on failure, properly constructed type otherwise.
1562
- Type extractElementType (Type collection) {
1563
- auto &ctx = CS.getASTContext ();
1564
- if (collection.isNull () || collection->is <ErrorType>())
1565
- return ErrorType::get (ctx);
1566
-
1567
- auto base = collection.getPointer ();
1568
- auto isInvalidType = [](Type type) -> bool {
1569
- return type.isNull () || type->hasUnresolvedType () ||
1570
- type->is <ErrorType>();
1571
- };
1572
-
1573
- // Array type.
1574
- if (auto array = dyn_cast<ArraySliceType>(base)) {
1575
- auto elementType = array->getBaseType ();
1576
- // If base type is invalid let's return error type.
1577
- return isInvalidType (elementType) ? ErrorType::get (ctx) : elementType;
1578
- }
1579
-
1580
- // Map or Set or any other associated collection type.
1581
- if (auto boundGeneric = dyn_cast<BoundGenericType>(base)) {
1582
- if (boundGeneric->hasUnresolvedType ())
1583
- return ErrorType::get (ctx);
1584
-
1585
- llvm::SmallVector<TupleTypeElt, 2 > params;
1586
- for (auto &type : boundGeneric->getGenericArgs ()) {
1587
- // One of the generic arguments in invalid or unresolved.
1588
- if (isInvalidType (type))
1589
- return ErrorType::get (ctx);
1590
-
1591
- params.push_back (type);
1592
- }
1593
-
1594
- // If there is just one parameter, let's return it directly.
1595
- if (params.size () == 1 )
1596
- return params[0 ].getType ();
1597
-
1598
- return TupleType::get (params, ctx);
1599
- }
1600
-
1601
- return ErrorType::get (ctx);
1602
- }
1603
-
1604
- bool isSuitableCollection (TypeRepr *collectionTypeRepr) {
1605
- // Only generic identifier, array or dictionary.
1606
- switch (collectionTypeRepr->getKind ()) {
1607
- case TypeReprKind::GenericIdent:
1608
- case TypeReprKind::Array:
1609
- case TypeReprKind::Dictionary:
1610
- return true ;
1611
-
1612
- default :
1613
- return false ;
1614
- }
1615
- }
1616
-
1617
- void visitCoerceExpr (CoerceExpr *coerceExpr) {
1618
- auto subExpr = coerceExpr->getSubExpr ();
1619
- // Coerce expression is valid only if it has sub-expression.
1620
- if (!subExpr) return ;
1621
-
1622
- unsigned numOverloadSets = 0 ;
1623
- subExpr->forEachChildExpr ([&](Expr *childExpr) -> Expr * {
1624
- if (isa<OverloadSetRefExpr>(childExpr)) {
1625
- ++numOverloadSets;
1626
- return childExpr;
1627
- }
1628
-
1629
- if (auto nestedCoerceExpr = dyn_cast<CoerceExpr>(childExpr)) {
1630
- visitCoerceExpr (nestedCoerceExpr);
1631
- // Don't walk inside of nested coercion expression directly,
1632
- // that is be done by recursive call to visitCoerceExpr.
1633
- return nullptr ;
1634
- }
1635
-
1636
- // If sub-expression we are trying to coerce to type is a collection,
1637
- // let's allow collector discover it with assigned contextual type
1638
- // of coercion, which allows collections to be solved in parts.
1639
- if (auto collectionExpr = dyn_cast<CollectionExpr>(childExpr)) {
1640
- auto castTypeLoc = coerceExpr->getCastTypeLoc ();
1641
- auto typeRepr = castTypeLoc.getTypeRepr ();
1642
-
1643
- if (typeRepr && isSuitableCollection (typeRepr)) {
1644
- // Clone representative to avoid modifying in-place,
1645
- // FIXME: We should try and silently resolve the type here,
1646
- // instead of cloning representative.
1647
- auto coercionRepr = typeRepr->clone (CS.getASTContext ());
1648
- // Let's try to resolve coercion type from cloned representative.
1649
- auto coercionType = CS.TC .resolveType (coercionRepr, CS.DC ,
1650
- TypeResolutionOptions ());
1651
-
1652
- // Looks like coercion type is invalid, let's skip this sub-tree.
1653
- if (coercionType->is <ErrorType>())
1654
- return nullptr ;
1655
-
1656
- // Visit collection expression inline.
1657
- visitCollectionExpr (collectionExpr, coercionType,
1658
- CTP_CoerceOperand);
1659
- }
1660
- }
1661
-
1662
- return childExpr;
1663
- });
1664
-
1665
- // It's going to be inefficient to try and solve
1666
- // coercion in parts, so let's just make it a candidate directly,
1667
- // if it contains at least a single overload set.
1668
-
1669
- if (numOverloadSets > 0 )
1670
- Candidates.push_back (Candidate (CS, coerceExpr));
1671
- }
1672
-
1673
- void visitCollectionExpr (CollectionExpr *collectionExpr,
1674
- Type contextualType = Type(),
1675
- ContextualTypePurpose CTP = CTP_Unused) {
1676
- // If there is a contextual type set for this collection,
1677
- // let's propagate it to the candidate.
1678
- if (!contextualType.isNull ()) {
1679
- auto elementType = extractElementType (contextualType);
1680
- // If we couldn't deduce element type for the collection, let's
1681
- // not attempt to solve it.
1682
- if (elementType->is <ErrorType>())
1683
- return ;
1684
-
1685
- contextualType = elementType;
1686
- }
1687
-
1688
- for (auto element : collectionExpr->getElements ()) {
1689
- unsigned numOverloads = 0 ;
1690
- element->walk (OverloadSetCounter (numOverloads));
1691
-
1692
- // There are no overload sets in the element; skip it.
1693
- if (numOverloads == 0 )
1694
- continue ;
1695
-
1696
- // Record each of the collection elements, which passed
1697
- // number of overload sets rule, as a candidate for solving
1698
- // with contextual type of the collection.
1699
- Candidates.push_back (Candidate (CS, element, contextualType, CTP));
1700
- }
1701
- }
1702
1581
};
1703
1582
1704
1583
ExprCollector collector (expr, *this , domains);
0 commit comments