mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Sema: Teach TypeReprCycleCheckWalker to avoid more cycles
More declaration order issues uncovered by lazy type checking. Fixes rdar://119499800.
This commit is contained in:
@@ -165,27 +165,25 @@ namespace {
|
||||
/// Try to avoid situations where resolving the type of a witness calls back
|
||||
/// into associated type inference.
|
||||
struct TypeReprCycleCheckWalker : ASTWalker {
|
||||
ASTContext &ctx;
|
||||
llvm::SmallDenseSet<Identifier, 2> circularNames;
|
||||
ValueDecl *witness;
|
||||
bool found;
|
||||
|
||||
TypeReprCycleCheckWalker(
|
||||
ASTContext &ctx,
|
||||
const llvm::SetVector<AssociatedTypeDecl *> &allUnresolved)
|
||||
: witness(nullptr), found(false) {
|
||||
: ctx(ctx), witness(nullptr), found(false) {
|
||||
for (auto *assocType : allUnresolved) {
|
||||
circularNames.insert(assocType->getName());
|
||||
}
|
||||
}
|
||||
|
||||
PreWalkAction walkToTypeReprPre(TypeRepr *T) override {
|
||||
// FIXME: We should still visit any generic arguments of this member type.
|
||||
// However, we want to skip 'Foo.Element' because the 'Element' reference is
|
||||
// not unqualified.
|
||||
if (auto *memberTyR = dyn_cast<MemberTypeRepr>(T)) {
|
||||
return Action::SkipChildren();
|
||||
}
|
||||
// FIXME: Visit generic arguments.
|
||||
|
||||
if (auto *identTyR = dyn_cast<SimpleIdentTypeRepr>(T)) {
|
||||
// If we're inferring `Foo`, don't look at a witness mentioning `Foo`.
|
||||
if (circularNames.count(identTyR->getNameRef().getBaseIdentifier()) > 0) {
|
||||
// If unqualified lookup can find a type with this name without looking
|
||||
// into protocol members, don't skip the witness, since this type might
|
||||
@@ -194,7 +192,6 @@ struct TypeReprCycleCheckWalker : ASTWalker {
|
||||
identTyR->getNameRef(), witness->getDeclContext(),
|
||||
identTyR->getLoc(), UnqualifiedLookupOptions());
|
||||
|
||||
auto &ctx = witness->getASTContext();
|
||||
auto results =
|
||||
evaluateOrDefault(ctx.evaluator, UnqualifiedLookupRequest{desc}, {});
|
||||
|
||||
@@ -207,6 +204,34 @@ struct TypeReprCycleCheckWalker : ASTWalker {
|
||||
}
|
||||
}
|
||||
|
||||
if (auto *memberTyR = dyn_cast<MemberTypeRepr>(T)) {
|
||||
// If we're looking at a member type`Foo.Bar`, check `Foo` recursively.
|
||||
auto *baseTyR = memberTyR->getBaseComponent();
|
||||
baseTyR->walk(*this);
|
||||
|
||||
// If we're inferring `Foo`, don't look at a witness mentioning `Self.Foo`.
|
||||
if (auto *identTyR = dyn_cast<SimpleIdentTypeRepr>(baseTyR)) {
|
||||
if (identTyR->getNameRef().getBaseIdentifier() == ctx.Id_Self) {
|
||||
// But if qualified lookup can find a type with this name without
|
||||
// looking into protocol members, don't skip the witness, since this
|
||||
// type might be a candidate witness.
|
||||
SmallVector<ValueDecl *, 2> results;
|
||||
witness->getInnermostDeclContext()->lookupQualified(
|
||||
witness->getDeclContext()->getSelfTypeInContext(),
|
||||
identTyR->getNameRef(), SourceLoc(), NLOptions(), results);
|
||||
|
||||
// Ok, resolving this member type would trigger associated type
|
||||
// inference recursively. We're going to skip this witness.
|
||||
if (results.empty()) {
|
||||
found = true;
|
||||
return Action::Stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Action::SkipChildren();
|
||||
}
|
||||
|
||||
return Action::Continue();
|
||||
}
|
||||
|
||||
@@ -296,7 +321,7 @@ AssociatedTypeInference::inferTypeWitnessesViaValueWitnesses(
|
||||
abort();
|
||||
}
|
||||
|
||||
TypeReprCycleCheckWalker cycleCheck(allUnresolved);
|
||||
TypeReprCycleCheckWalker cycleCheck(dc->getASTContext(), allUnresolved);
|
||||
|
||||
InferredAssociatedTypesByWitnesses result;
|
||||
|
||||
|
||||
@@ -95,3 +95,39 @@ public enum CaseWitness: CaseProtocol {
|
||||
case b(_: A)
|
||||
case c(_: A)
|
||||
}
|
||||
|
||||
// rdar://119499800 #1
|
||||
public typealias A8 = Batch.Iterator
|
||||
|
||||
public struct Batch: Collection {
|
||||
public typealias Element = Int
|
||||
public typealias Index = Array<Element>.Index
|
||||
|
||||
var elements: [Element]
|
||||
|
||||
init(_ elements: some Collection<Element>) {
|
||||
self.elements = Array(elements)
|
||||
}
|
||||
|
||||
public var startIndex: Index { return elements.startIndex }
|
||||
public var endIndex: Index { return elements.endIndex }
|
||||
|
||||
public subscript(index: Index) -> Iterator.Element {
|
||||
return elements[index]
|
||||
}
|
||||
|
||||
public func index(after i: Index) -> Index {
|
||||
return elements.index(after: i)
|
||||
}
|
||||
}
|
||||
|
||||
// rdar://119499800 #2
|
||||
public typealias A9 = LogTypes.RawValue
|
||||
|
||||
public struct LogTypes: OptionSet {
|
||||
public init(rawValue: Self.RawValue) {
|
||||
self.rawValue = rawValue
|
||||
}
|
||||
|
||||
public let rawValue: Int
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user