@@ -614,42 +614,63 @@ void PropertyMap::concretizeTypeWitnessInConformance(
614614
615615 MutableTerm constraintType;
616616
617- auto simplify = [&](CanType t) -> CanType {
618- return CanType (t.transformRec ([&](Type t) -> Optional<Type> {
619- if (!t->isTypeParameter ())
620- return None;
621-
622- auto term = Context.getRelativeTermForType (t->getCanonicalType (),
623- substitutions);
624- System.simplify (term);
625- return Context.getTypeForTerm (term, { });
626- }));
627- };
628-
629- if (simplify (concreteType) == simplify (typeWitness) &&
630- requirementKind == RequirementKind::SameType) {
631- // FIXME: ConcreteTypeInDomainMap should support substitutions so
632- // that we can remove this.
633-
634- if (Debug.contains (DebugFlags::ConcretizeNestedTypes)) {
635- llvm::dbgs () << " ^^ Type witness is the same as the concrete type\n " ;
636- }
617+ RewritePath path;
637618
638- // Add a rule T.[P:A] => T.
639- constraintType = MutableTerm (key);
640- } else {
641- constraintType = computeConstraintTermForTypeWitness (
642- key, concreteType, typeWitness, subjectType,
643- substitutions);
644- }
619+ constraintType = computeConstraintTermForTypeWitness (
620+ key, requirementKind, concreteType, typeWitness, subjectType,
621+ substitutions, path);
645622
646- inducedRules.emplace_back (subjectType, constraintType );
623+ inducedRules.emplace_back (constraintType, subjectType, path );
647624 if (Debug.contains (DebugFlags::ConcretizeNestedTypes)) {
648625 llvm::dbgs () << " ^^ Induced rule " << constraintType
649626 << " => " << subjectType << " \n " ;
650627 }
651628}
652629
630+ RewriteSystem::ConcreteTypeWitness::ConcreteTypeWitness (
631+ Symbol concreteConformance,
632+ Symbol assocType,
633+ Symbol concreteType)
634+ : ConcreteConformance(concreteConformance),
635+ AssocType(assocType),
636+ ConcreteType(concreteType) {
637+ assert (concreteConformance.getKind () == Symbol::Kind::ConcreteConformance);
638+ assert (assocType.getKind () == Symbol::Kind::AssociatedType);
639+ assert (concreteType.getKind () == Symbol::Kind::ConcreteType);
640+ assert (assocType.getProtocols ().size () == 1 );
641+ assert (assocType.getProtocols ()[0 ] == concreteConformance.getProtocol ());
642+ }
643+
644+ bool swift::rewriting::operator ==(
645+ const RewriteSystem::ConcreteTypeWitness &lhs,
646+ const RewriteSystem::ConcreteTypeWitness &rhs) {
647+ return (lhs.ConcreteConformance == rhs.ConcreteConformance &&
648+ lhs.AssocType == rhs.AssocType &&
649+ lhs.ConcreteType == rhs.ConcreteType );
650+ }
651+
652+ unsigned RewriteSystem::recordConcreteTypeWitness (
653+ RewriteSystem::ConcreteTypeWitness witness) {
654+ auto key = std::make_pair (witness.ConcreteConformance ,
655+ witness.AssocType );
656+ unsigned index = ConcreteTypeWitnesses.size ();
657+ auto inserted = ConcreteTypeWitnessMap.insert (std::make_pair (key, index));
658+
659+ if (!inserted.second ) {
660+ index = inserted.first ->second ;
661+ } else {
662+ ConcreteTypeWitnesses.push_back (witness);
663+ }
664+
665+ assert (ConcreteTypeWitnesses[index] == witness);
666+ return index;
667+ }
668+
669+ const RewriteSystem::ConcreteTypeWitness &
670+ RewriteSystem::getConcreteTypeWitness (unsigned index) const {
671+ return ConcreteTypeWitnesses[index];
672+ }
673+
653674// / Given the key of a property bag known to have \p concreteType,
654675// / together with a \p typeWitness from a conformance on that concrete
655676// / type, return the right hand side of a rewrite rule to relate
@@ -675,8 +696,72 @@ void PropertyMap::concretizeTypeWitnessInConformance(
675696// /
676697// / T.[P:A] => V
677698MutableTerm PropertyMap::computeConstraintTermForTypeWitness (
678- Term key, CanType concreteType, CanType typeWitness,
679- const MutableTerm &subjectType, ArrayRef<Term> substitutions) const {
699+ Term key, RequirementKind requirementKind,
700+ CanType concreteType, CanType typeWitness,
701+ const MutableTerm &subjectType,
702+ ArrayRef<Term> substitutions,
703+ RewritePath &path) const {
704+ // If the type witness is abstract, introduce a same-type requirement
705+ // between two type parameters.
706+ if (typeWitness->isTypeParameter ()) {
707+ // The type witness is a type parameter of the form τ_0_n.X.Y...Z,
708+ // where 'n' is an index into the substitution array.
709+ //
710+ // Add a rule:
711+ //
712+ // T.[concrete: C : P].[P:X] => S[n].X.Y...Z
713+ //
714+ // Where S[n] is the nth substitution term.
715+
716+ // FIXME: Record a rewrite path.
717+ return Context.getRelativeTermForType (typeWitness, substitutions);
718+ }
719+
720+ // Otherwise the type witness is concrete, but may contain type
721+ // parameters in structural position.
722+
723+ // Compute the concrete type symbol [concrete: C.X].
724+ SmallVector<Term, 3 > result;
725+ auto typeWitnessSchema =
726+ remapConcreteSubstitutionSchema (typeWitness, substitutions,
727+ Context, result);
728+ auto typeWitnessSymbol =
729+ Symbol::forConcreteType (typeWitnessSchema, result, Context);
730+ System.simplifySubstitutions (typeWitnessSymbol);
731+
732+ auto concreteConformanceSymbol = *(subjectType.end () - 2 );
733+ auto assocTypeSymbol = *(subjectType.end () - 1 );
734+
735+ RewriteSystem::ConcreteTypeWitness witness (concreteConformanceSymbol,
736+ assocTypeSymbol,
737+ typeWitnessSymbol);
738+ unsigned witnessID = System.recordConcreteTypeWitness (witness);
739+
740+ // If it is equal to the parent type, introduce a same-type requirement
741+ // between the two parameters.
742+ if (requirementKind == RequirementKind::SameType &&
743+ typeWitnessSymbol.getConcreteType () == concreteType &&
744+ typeWitnessSymbol.getSubstitutions () == substitutions) {
745+ // FIXME: ConcreteTypeInDomainMap should support substitutions so
746+ // that we can remove this.
747+
748+ if (Debug.contains (DebugFlags::ConcretizeNestedTypes)) {
749+ llvm::dbgs () << " ^^ Type witness is the same as the concrete type\n " ;
750+ }
751+
752+ // Add a rule T.[concrete: C : P].[P:X] => T.[concrete: C : P].
753+ MutableTerm result (key);
754+ result.add (concreteConformanceSymbol);
755+
756+ path.add (RewriteStep::forSameTypeWitness (
757+ witnessID, /* inverse=*/ true ));
758+
759+ return result;
760+ }
761+
762+ // If the type witness is completely concrete, try to introduce a
763+ // same-type requirement with another representative type parameter,
764+ // if we have one.
680765 if (!typeWitness->hasTypeParameter ()) {
681766 // Check if we have a shorter representative we can use.
682767 auto domain = key.getRootProtocols ();
@@ -690,38 +775,23 @@ MutableTerm PropertyMap::computeConstraintTermForTypeWitness(
690775 llvm::dbgs () << " ^^ Type witness can re-use property bag of "
691776 << found->second << " \n " ;
692777 }
778+
779+ // FIXME: Record a rewrite path.
693780 return result;
694781 }
695782 }
696783 }
697784
698- if (typeWitness->isTypeParameter ()) {
699- // The type witness is a type parameter of the form τ_0_n.X.Y...Z,
700- // where 'n' is an index into the substitution array.
701- //
702- // Add a rule:
703- //
704- // T.[concrete: C : P].[P:X] => S[n].X.Y...Z
705- //
706- // Where S[n] is the nth substitution term.
707- return Context.getRelativeTermForType (typeWitness, substitutions);
708- }
709-
710- // The type witness is a concrete type.
785+ // Otherwise, add a concrete type requirement for the type witness.
711786 //
712787 // Add a rule:
713788 //
714- // T.[concrete: C : P].[P:X].[concrete: Foo.A ] => T.[concrete: C : P].[P:A ].
789+ // T.[concrete: C : P].[P:X].[concrete: C.X ] => T.[concrete: C : P].[P:X ].
715790 MutableTerm constraintType = subjectType;
791+ constraintType.add (typeWitnessSymbol);
716792
717- SmallVector<Term, 3 > result;
718- auto typeWitnessSchema =
719- remapConcreteSubstitutionSchema (typeWitness, substitutions,
720- Context, result);
721-
722- constraintType.add (
723- Symbol::forConcreteType (
724- typeWitnessSchema, result, Context));
793+ path.add (RewriteStep::forConcreteTypeWitness (
794+ witnessID, /* inverse=*/ false ));
725795
726796 return constraintType;
727797}
0 commit comments