@@ -2466,21 +2466,215 @@ ConstraintSystem::matchPackTypes(PackType *pack1, PackType *pack2,
2466
2466
return getTypeMatchSuccess();
2467
2467
}
2468
2468
2469
+ namespace {
2470
+
2471
+ /// Collects all unique pack type variables referenced from the pattern type,
2472
+ /// skipping those captured by nested pack expansion types.
2473
+ ///
2474
+ /// FIXME: This could probably be a common utility method somewhere.
2475
+ struct PackTypeVariableCollector: TypeWalker {
2476
+ llvm::SetVector<TypeVariableType *> typeVars;
2477
+
2478
+ Action walkToTypePre(Type t) override {
2479
+ if (t->is<PackExpansionType>())
2480
+ return Action::SkipChildren;
2481
+
2482
+ if (auto *typeVar = t->getAs<TypeVariableType>()) {
2483
+ if (typeVar->getImpl().canBindToPack())
2484
+ typeVars.insert(typeVar);
2485
+ }
2486
+
2487
+ return Action::Continue;
2488
+ }
2489
+ };
2490
+
2491
+ }
2492
+
2493
+ /// Utility function used when matching a pack expansion type against a
2494
+ /// pack type.
2495
+ ///
2496
+ /// Takes a pattern type and an original pack type, and returns an instantiated
2497
+ /// pack type. The original pack type is then matched against the instantiated
2498
+ /// pack type.
2499
+ ///
2500
+ /// As a side effect, it binds each pack type variable occuring in the pattern
2501
+ /// type to a new pack with the same shape as the original pack, but where the
2502
+ /// elements are fresh type variables.
2503
+ ///
2504
+ /// The instantiated pack has the same shape as the original pack, where the
2505
+ /// ith element is the pattern type with each pack type variable replaced by the
2506
+ /// ith element of its binding.
2507
+ ///
2508
+ /// For example, given the pattern Foo<$T0> and the original pack
2509
+ /// {Foo<Int>, Foo<String>...}, we're going to bind
2510
+ ///
2511
+ /// $T0 := {$T1, $T2}
2512
+ ///
2513
+ /// And return the new pack {Foo<$T1>, Foo<$T2>...}.
2514
+ ///
2515
+ /// The caller will then match the original pack type against the instantiated
2516
+ /// pack type, which will recover the bindings:
2517
+ ///
2518
+ /// $T1 := Int
2519
+ /// $T2 := String
2520
+ ///
2521
+ static PackType *replaceTypeVariablesWithFreshPacks(ConstraintSystem &cs,
2522
+ Type pattern,
2523
+ PackType *pack,
2524
+ ConstraintLocatorBuilder locator) {
2525
+ SmallVector<Type, 2> elts;
2526
+
2527
+ llvm::MapVector<TypeVariableType *, SmallVector<Type, 2>> typeVars;
2528
+
2529
+ PackTypeVariableCollector collector;
2530
+ pattern.walk(collector);
2531
+
2532
+ auto *loc = cs.getConstraintLocator(locator);
2533
+
2534
+ // For each pack type variable occurring in the pattern type, compute a
2535
+ // binding pack type comprised of fresh type variables.
2536
+ for (auto *typeVar : collector.typeVars) {
2537
+ auto &freshTypeVars = typeVars[typeVar];
2538
+ for (unsigned i = 0, e = pack->getNumElements(); i < e; ++i) {
2539
+ // Preserve the pack expansion structure of the original pack. If the ith
2540
+ // element was a pack expansion type, create a new pack expansion type
2541
+ // wrapping a pack type variable. Otherwise, create a new scalar
2542
+ // type variable.
2543
+ //
2544
+ // FIXME: Locator for diagnostics
2545
+ // FIXME: Other TVO_* flags for type variables?
2546
+ if (pack->getElementType(i)->is<PackExpansionType>()) {
2547
+ auto *freshTypeVar = cs.createTypeVariable(loc, TVO_CanBindToPack);
2548
+ freshTypeVars.push_back(PackExpansionType::get(freshTypeVar, freshTypeVar));
2549
+ } else {
2550
+ freshTypeVars.push_back(cs.createTypeVariable(loc, /*options=*/0));
2551
+ }
2552
+ }
2553
+ }
2554
+
2555
+ // For each element of the original pack type, instantiate the pattern type by
2556
+ // replacing each pack type variable with the corresponding element of the
2557
+ // pack type variable's binding pack.
2558
+ for (unsigned i = 0, e = pack->getNumElements(); i < e; ++i) {
2559
+ auto *packExpansionElt = pack->getElementType(i)->getAs<PackExpansionType>();
2560
+
2561
+ auto instantiatedPattern = pattern.transformRec([&](Type t) -> Optional<Type> {
2562
+ if (t->is<PackExpansionType>())
2563
+ return t;
2564
+
2565
+ if (auto *typeVar = t->getAs<TypeVariableType>()) {
2566
+ if (typeVar->getImpl().canBindToPack()) {
2567
+ auto found = typeVars.find(typeVar);
2568
+ assert(found != typeVars.end());
2569
+
2570
+ // The ith element of the binding pack is either a scalar type variable
2571
+ // or a pack expansion type wrapping a pack type variable.
2572
+ auto projectedType = (found->second)[i];
2573
+ if (packExpansionElt != nullptr) {
2574
+ projectedType = projectedType->castTo<PackExpansionType>()
2575
+ ->getPatternType();
2576
+ assert(projectedType->castTo<TypeVariableType>()
2577
+ ->getImpl().canBindToPack());
2578
+ } else {
2579
+ assert(!projectedType->castTo<TypeVariableType>()
2580
+ ->getImpl().canBindToPack());
2581
+ }
2582
+
2583
+ return projectedType;
2584
+ }
2585
+ }
2586
+
2587
+ return None;
2588
+ });
2589
+
2590
+ if (packExpansionElt != nullptr) {
2591
+ elts.push_back(PackExpansionType::get(instantiatedPattern,
2592
+ packExpansionElt->getCountType()));
2593
+ } else {
2594
+ elts.push_back(instantiatedPattern);
2595
+ }
2596
+ }
2597
+
2598
+ auto &ctx = cs.getASTContext();
2599
+
2600
+ // Bind each pack type variable occurring in the pattern type to its
2601
+ // binding pack that was constructed above.
2602
+ for (const auto &pair : typeVars) {
2603
+ // FIXME: Locator for diagnostics
2604
+ cs.addConstraint(ConstraintKind::Bind,
2605
+ pair.first, PackType::get(ctx, pair.second), locator);
2606
+ }
2607
+
2608
+ // Construct the instantiated pack type.
2609
+ return PackType::get(cs.getASTContext(), elts);
2610
+ }
2611
+
2469
2612
ConstraintSystem::TypeMatchResult
2470
2613
ConstraintSystem::matchPackExpansionTypes(PackExpansionType *expansion1,
2471
2614
PackExpansionType *expansion2,
2472
2615
ConstraintKind kind, TypeMatchOptions flags,
2473
2616
ConstraintLocatorBuilder locator) {
2474
- // FIXME: Should we downgrade kind to Bind or something here?
2475
- auto result = matchTypes(expansion1->getCountType(),
2476
- expansion2->getCountType(),
2477
- kind, flags, locator);
2478
- if (result.isFailure())
2479
- return result;
2617
+ // The count types of two pack expansion types must have the same shape.
2618
+ //
2619
+ // FIXME: Locator for diagnostics.
2620
+ auto *loc = getConstraintLocator(locator);
2621
+ auto *shapeTypeVar = createTypeVariable(loc, TVO_CanBindToPack);
2622
+ addConstraint(ConstraintKind::ShapeOf,
2623
+ expansion1->getCountType(), shapeTypeVar, locator);
2624
+ addConstraint(ConstraintKind::ShapeOf,
2625
+ expansion2->getCountType(), shapeTypeVar, locator);
2626
+
2627
+ auto pattern1 = expansion1->getPatternType();
2628
+ auto pattern2 = expansion2->getPatternType();
2629
+
2630
+ // A pattern is 'expanded' if it is a pack type, pack archetype or
2631
+ // pack type variable. Otherwise, it is a concrete type which can be
2632
+ // instantiated by replacing any pack type variables that occur within.
2633
+ auto isFullyExpanded = [](Type t) -> bool {
2634
+ return (t->is<PackType>() ||
2635
+ t->is<PackArchetypeType>() ||
2636
+ (t->is<TypeVariableType>() &&
2637
+ t->castTo<TypeVariableType>()->getImpl().canBindToPack()));
2638
+ };
2639
+
2640
+ bool isExpanded1 = isFullyExpanded(pattern1);
2641
+ bool isExpanded2 = isFullyExpanded(pattern2);
2642
+
2643
+ // If both sides are expanded or neither side is, just match them
2644
+ // directly.
2645
+ if ((isExpanded1 && isExpanded2) ||
2646
+ (!isExpanded1 && !isExpanded2)) {
2647
+ return matchTypes(pattern1, pattern2, kind, flags, locator);
2648
+
2649
+ // If the right hand side is expanded, we have something like
2650
+ // Foo<$T0>... vs Pack{Foo<Int>, Foo<String>}...; We're going to
2651
+ // bind $T0 to Pack{Int, String}.
2652
+ } else if (!isExpanded1 && isExpanded2) {
2653
+ if (auto *pack2 = pattern2->getAs<PackType>()) {
2654
+ auto *pack1 = replaceTypeVariablesWithFreshPacks(
2655
+ *this, pattern1, pack2, locator);
2656
+ // FIXME: Locator for diagnostics.
2657
+ addConstraint(kind, pack1, pack2, locator);
2658
+ return getTypeMatchSuccess();
2659
+ }
2660
+
2661
+ return getTypeMatchFailure(locator);
2480
2662
2481
- return matchTypes(expansion1->getPatternType(),
2482
- expansion2->getPatternType(),
2483
- kind, flags, locator);
2663
+ // If the left hand side is expanded, we have something like
2664
+ // Pack{Foo<Int>, Foo<String>}... vs Foo<$T0>...; We're going to
2665
+ // bind $T0 to Pack{Int, String}.
2666
+ } else {
2667
+ assert(isExpanded1 && !isExpanded2);
2668
+ if (auto *pack1 = pattern1->getAs<PackType>()) {
2669
+ auto *pack2 = replaceTypeVariablesWithFreshPacks(
2670
+ *this, pattern2, pack1, locator);
2671
+ // FIXME: Locator for diagnostics.
2672
+ addConstraint(kind, pack1, pack2, locator);
2673
+ return getTypeMatchSuccess();
2674
+ }
2675
+
2676
+ return getTypeMatchFailure(locator);
2677
+ }
2484
2678
}
2485
2679
2486
2680
/// Check where a representation is a subtype of another.
@@ -12519,34 +12713,38 @@ ConstraintSystem::simplifyDynamicCallableApplicableFnConstraint(
12519
12713
return SolutionKind::Solved;
12520
12714
}
12521
12715
12522
- static Type getReducedShape(Type type) {
12716
+ /// FIXME: Move this elsewhere if it is broadly useful
12717
+ static Type getReducedShape(Type type, ASTContext &ctx) {
12523
12718
// Pack archetypes know their reduced shape
12524
12719
if (auto *packArchetype = type->getAs<PackArchetypeType>())
12525
12720
return packArchetype->getShape();
12526
12721
12527
12722
// Reduced shape of pack is computed recursively
12528
12723
if (auto *packType = type->getAs<PackType>()) {
12529
- auto &ctx = type->getASTContext();
12530
12724
SmallVector<Type, 2> elts;
12531
12725
12532
12726
for (auto elt : packType->getElementTypes()) {
12533
12727
// T... => shape(T)...
12534
12728
if (auto *packExpansionType = elt->getAs<PackExpansionType>()) {
12535
- auto shapeType = getReducedShape(packExpansionType->getCountType());
12536
- assert(shapeType && "Should not end up here if pack type's shape "
12537
- "is still potentially unknown");
12729
+ if (packExpansionType->getCountType()->is<PlaceholderType>()) {
12730
+ elts.push_back(ctx.TheEmptyTupleType);
12731
+ continue;
12732
+ }
12733
+ auto shapeType = getReducedShape(packExpansionType->getCountType(), ctx);
12538
12734
elts.push_back(PackExpansionType::get(shapeType, shapeType));
12539
12735
}
12540
12736
12541
- // Use () as a placeholder for scalar shape
12737
+ // Use () as a placeholder for scalar shape.
12542
12738
elts.push_back(ctx.TheEmptyTupleType);
12543
12739
}
12544
12740
12545
12741
return PackType::get(ctx, elts);
12546
12742
}
12547
12743
12548
- // Getting the shape of any other type is an error.
12549
- return Type();
12744
+ assert(!type->isTypeVariableOrMember());
12745
+
12746
+ // Use () as a placeholder for scalar shape.
12747
+ return ctx.TheEmptyTupleType;
12550
12748
}
12551
12749
12552
12750
ConstraintSystem::SolutionKind ConstraintSystem::simplifyShapeOfConstraint(
@@ -12579,7 +12777,7 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyShapeOfConstraint(
12579
12777
return formUnsolved();
12580
12778
}
12581
12779
12582
- if (Type shape = getReducedShape(type1)) {
12780
+ if (Type shape = getReducedShape(type1, getASTContext() )) {
12583
12781
addConstraint(ConstraintKind::Bind, shape, type2, locator);
12584
12782
return SolutionKind::Solved;
12585
12783
}
0 commit comments