|
28 | 28 | #include "MoveOnlyBorrowToDestructureUtils.h" |
29 | 29 | #include "MoveOnlyDiagnostics.h" |
30 | 30 | #include "MoveOnlyObjectCheckerUtils.h" |
| 31 | +#include "MoveOnlyTypeUtils.h" |
31 | 32 |
|
32 | 33 | #include "swift/Basic/BlotSetVector.h" |
33 | 34 | #include "swift/Basic/Defer.h" |
@@ -544,236 +545,6 @@ void Implementation::checkDestructureUsesOnBoundary() const { |
544 | 545 | } |
545 | 546 | } |
546 | 547 |
|
547 | | -static StructDecl *getFullyReferenceableStruct(SILType ktypeTy) { |
548 | | - auto structDecl = ktypeTy.getStructOrBoundGenericStruct(); |
549 | | - if (!structDecl || structDecl->hasUnreferenceableStorage()) |
550 | | - return nullptr; |
551 | | - return structDecl; |
552 | | -} |
553 | | - |
554 | | -namespace { |
555 | | - |
556 | | -struct TypeOffsetSizePair { |
557 | | - SubElementOffset startOffset = 0; |
558 | | - TypeSubElementCount size = 0; |
559 | | - |
560 | | - TypeOffsetSizePair() : startOffset(0), size(0) {} |
561 | | - TypeOffsetSizePair(SILType baseType, SILFunction *fn) |
562 | | - : startOffset(0), size(baseType, fn) {} |
563 | | - TypeOffsetSizePair(SubElementOffset offset, TypeSubElementCount size) |
564 | | - : startOffset(offset), size(size) {} |
565 | | - TypeOffsetSizePair(SILValue projection, SILValue base) |
566 | | - : startOffset(*SubElementOffset::compute(projection, base)), |
567 | | - size(TypeSubElementCount(projection)) {} |
568 | | - |
569 | | - IntRange<unsigned> getRange() const { |
570 | | - return range(startOffset, getEndOffset()); |
571 | | - } |
572 | | - |
573 | | - SubElementOffset getEndOffset() const { |
574 | | - return SubElementOffset(startOffset + size); |
575 | | - } |
576 | | - |
577 | | - bool operator==(const TypeOffsetSizePair &other) const { |
578 | | - return startOffset == other.startOffset && size == other.size; |
579 | | - } |
580 | | - |
581 | | - bool operator!=(const TypeOffsetSizePair &other) const { |
582 | | - return !(*this == other); |
583 | | - } |
584 | | - |
585 | | - /// Given an ancestor offset \p ancestorOffset and a type called \p |
586 | | - /// ancestorType, walk one level towards this current type which is assumed to |
587 | | - /// be a child type of \p ancestorType. |
588 | | - Optional<std::pair<TypeOffsetSizePair, SILType>> |
589 | | - walkOneLevelTowardsChild(TypeOffsetSizePair ancestorOffsetSize, |
590 | | - SILType ancestorType, SILFunction *fn) const { |
591 | | - assert(ancestorOffsetSize.size >= size && |
592 | | - "Too large to be a child of ancestorType"); |
593 | | - assert((ancestorOffsetSize.startOffset <= startOffset && |
594 | | - startOffset < |
595 | | - (ancestorOffsetSize.startOffset + ancestorOffsetSize.size)) && |
596 | | - "Not within the offset range of ancestor"); |
597 | | - |
598 | | - if (auto tupleType = ancestorType.getAs<TupleType>()) { |
599 | | - // Before we do anything, see if we have a single element tuple. If we do, |
600 | | - // just return that. |
601 | | - if (tupleType->getNumElements() == 1) { |
602 | | - return {{ancestorOffsetSize, ancestorType.getTupleElementType(0)}}; |
603 | | - } |
604 | | - |
605 | | - assert(ancestorOffsetSize.size > size && |
606 | | - "Too large to be a child of ancestorType"); |
607 | | - |
608 | | - unsigned childOffset = ancestorOffsetSize.startOffset; |
609 | | - |
610 | | - for (auto index : indices(tupleType->getElementTypes())) { |
611 | | - SILType newType = ancestorType.getTupleElementType(index); |
612 | | - unsigned newSize = TypeSubElementCount(newType, fn); |
613 | | - |
614 | | - // childOffset + size(tupleChild) is the offset of the next tuple |
615 | | - // element. If our target offset is less than that, then we know that |
616 | | - // the target type must be a descendent of this tuple element type. |
617 | | - if (childOffset + newSize > startOffset) { |
618 | | - return {{{childOffset, newSize}, newType}}; |
619 | | - } |
620 | | - |
621 | | - // Otherwise, add the new size of this field to iterOffset so we visit |
622 | | - // our sibling type next. |
623 | | - childOffset += newSize; |
624 | | - } |
625 | | - |
626 | | - // At this point, we know that our type is not a subtype of this |
627 | | - // type. Some sort of logic error occurred. |
628 | | - llvm_unreachable("Not a child of this type?!"); |
629 | | - } |
630 | | - |
631 | | - if (auto *structDecl = getFullyReferenceableStruct(ancestorType)) { |
632 | | - // Before we do anything, see if we have a single element struct. If we |
633 | | - // do, just return that. |
634 | | - auto storedProperties = structDecl->getStoredProperties(); |
635 | | - if (storedProperties.size() == 1) { |
636 | | - return {{ancestorOffsetSize, |
637 | | - ancestorType.getFieldType(storedProperties[0], fn)}}; |
638 | | - } |
639 | | - |
640 | | - assert(ancestorOffsetSize.size > size && |
641 | | - "Too large to be a child of ancestorType"); |
642 | | - |
643 | | - unsigned childOffset = ancestorOffsetSize.startOffset; |
644 | | - for (auto *fieldDecl : storedProperties) { |
645 | | - SILType newType = ancestorType.getFieldType(fieldDecl, fn); |
646 | | - unsigned newSize = TypeSubElementCount(newType, fn); |
647 | | - |
648 | | - // iterOffset + size(tupleChild) is the offset of the next tuple |
649 | | - // element. If our target offset is less than that, then we know that |
650 | | - // the target type must be a child of this tuple element type. |
651 | | - if (childOffset + newSize > startOffset) { |
652 | | - return {{{childOffset, newSize}, newType}}; |
653 | | - } |
654 | | - |
655 | | - // Otherwise, add the new size of this field to iterOffset so we visit |
656 | | - // our sibling type next. |
657 | | - childOffset += newSize; |
658 | | - } |
659 | | - |
660 | | - // At this point, we know that our type is not a subtype of this |
661 | | - // type. Some sort of logic error occurred. |
662 | | - llvm_unreachable("Not a child of this type?!"); |
663 | | - } |
664 | | - |
665 | | - if (auto *enumDecl = ancestorType.getEnumOrBoundGenericEnum()) { |
666 | | - llvm_unreachable("Cannot find child type of enum!\n"); |
667 | | - } |
668 | | - |
669 | | - llvm_unreachable("Hit a leaf type?! Should have handled it earlier"); |
670 | | - } |
671 | | - |
672 | | - /// Given an ancestor offset \p ancestorOffset and a type called \p |
673 | | - /// ancestorType, walk one level towards this current type inserting on value, |
674 | | - /// the relevant projection. |
675 | | - Optional<std::pair<TypeOffsetSizePair, SILValue>> |
676 | | - walkOneLevelTowardsChild(SILBuilderWithScope &builder, SILLocation loc, |
677 | | - TypeOffsetSizePair ancestorOffsetSize, |
678 | | - SILValue ancestorValue) const { |
679 | | - auto *fn = ancestorValue->getFunction(); |
680 | | - SILType ancestorType = ancestorValue->getType(); |
681 | | - |
682 | | - assert(ancestorOffsetSize.size >= size && |
683 | | - "Too large to be a child of ancestorType"); |
684 | | - assert((ancestorOffsetSize.startOffset <= startOffset && |
685 | | - startOffset < |
686 | | - (ancestorOffsetSize.startOffset + ancestorOffsetSize.size)) && |
687 | | - "Not within the offset range of ancestor"); |
688 | | - if (auto tupleType = ancestorType.getAs<TupleType>()) { |
689 | | - // Before we do anything, see if we have a single element tuple. If we do, |
690 | | - // just return that. |
691 | | - if (tupleType->getNumElements() == 1) { |
692 | | - auto *newValue = builder.createTupleExtract(loc, ancestorValue, 0); |
693 | | - return {{ancestorOffsetSize, newValue}}; |
694 | | - } |
695 | | - |
696 | | - assert(ancestorOffsetSize.size > size && |
697 | | - "Too large to be a child of ancestorType"); |
698 | | - |
699 | | - unsigned childOffset = ancestorOffsetSize.startOffset; |
700 | | - |
701 | | - for (auto index : indices(tupleType->getElementTypes())) { |
702 | | - SILType newType = ancestorType.getTupleElementType(index); |
703 | | - unsigned newSize = TypeSubElementCount(newType, fn); |
704 | | - |
705 | | - // childOffset + size(tupleChild) is the offset of the next tuple |
706 | | - // element. If our target offset is less than that, then we know that |
707 | | - // the target type must be a descendent of this tuple element type. |
708 | | - if (childOffset + newSize > startOffset) { |
709 | | - auto *newValue = |
710 | | - builder.createTupleExtract(loc, ancestorValue, index); |
711 | | - return {{{childOffset, newSize}, newValue}}; |
712 | | - } |
713 | | - |
714 | | - // Otherwise, add the new size of this field to iterOffset so we visit |
715 | | - // our sibling type next. |
716 | | - childOffset += newSize; |
717 | | - } |
718 | | - |
719 | | - // At this point, we know that our type is not a subtype of this |
720 | | - // type. Some sort of logic error occurred. |
721 | | - llvm_unreachable("Not a child of this type?!"); |
722 | | - } |
723 | | - |
724 | | - if (auto *structDecl = getFullyReferenceableStruct(ancestorType)) { |
725 | | - // Before we do anything, see if we have a single element struct. If we |
726 | | - // do, just return that. |
727 | | - auto storedProperties = structDecl->getStoredProperties(); |
728 | | - if (storedProperties.size() == 1) { |
729 | | - auto *newValue = builder.createStructExtract(loc, ancestorValue, |
730 | | - storedProperties[0]); |
731 | | - return {{ancestorOffsetSize, newValue}}; |
732 | | - } |
733 | | - |
734 | | - assert(ancestorOffsetSize.size > size && |
735 | | - "Too large to be a child of ancestorType"); |
736 | | - |
737 | | - unsigned childOffset = ancestorOffsetSize.startOffset; |
738 | | - for (auto *fieldDecl : structDecl->getStoredProperties()) { |
739 | | - SILType newType = ancestorType.getFieldType(fieldDecl, fn); |
740 | | - unsigned newSize = TypeSubElementCount(newType, fn); |
741 | | - |
742 | | - // iterOffset + size(tupleChild) is the offset of the next tuple |
743 | | - // element. If our target offset is less than that, then we know that |
744 | | - // the target type must be a child of this tuple element type. |
745 | | - if (childOffset + newSize > startOffset) { |
746 | | - auto *newValue = |
747 | | - builder.createStructExtract(loc, ancestorValue, fieldDecl); |
748 | | - return {{{childOffset, newSize}, newValue}}; |
749 | | - } |
750 | | - |
751 | | - // Otherwise, add the new size of this field to iterOffset so we visit |
752 | | - // our sibling type next. |
753 | | - childOffset += newSize; |
754 | | - } |
755 | | - |
756 | | - // At this point, we know that our type is not a subtype of this |
757 | | - // type. Some sort of logic error occurred. |
758 | | - llvm_unreachable("Not a child of this type?!"); |
759 | | - } |
760 | | - |
761 | | - if (auto *enumDecl = ancestorType.getEnumOrBoundGenericEnum()) { |
762 | | - llvm_unreachable("Cannot find child type of enum!\n"); |
763 | | - } |
764 | | - |
765 | | - llvm_unreachable("Hit a leaf type?! Should have handled it earlier"); |
766 | | - } |
767 | | -}; |
768 | | - |
769 | | -llvm::raw_ostream &operator<<(llvm::raw_ostream &os, |
770 | | - const TypeOffsetSizePair &other) { |
771 | | - return os << "(startOffset: " << other.startOffset << ", size: " << other.size |
772 | | - << ")"; |
773 | | -} |
774 | | - |
775 | | -} // anonymous namespace |
776 | | - |
777 | 548 | #ifndef NDEBUG |
778 | 549 | static void dumpSmallestTypeAvailable( |
779 | 550 | SmallVectorImpl<Optional<std::pair<TypeOffsetSizePair, SILType>>> |
|
0 commit comments