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