From 48b491df5043fcfb0d5623271dcbffa5fb0fe4f0 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Sat, 26 Mar 2022 19:03:14 -0400 Subject: [PATCH 1/2] AST: Avoid invoking TypeAliasDecl::getUnderlyingType() from isInterestingTypealias() Diagnostics are emitted from weird places sometimes, and as a result the emission is fragile for two reasons: - Kicking off requests can trigger cycles - Doing anything that can re-entrantly diagnose something else might crash In this case, the problem is getUnderlyingType(), which might kick off type resolution on the typealias. Since we already have a Type, just check that instead of getting a new one. --- lib/AST/DiagnosticEngine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/AST/DiagnosticEngine.cpp b/lib/AST/DiagnosticEngine.cpp index 491ad8a612f33..8eb534888a140 100644 --- a/lib/AST/DiagnosticEngine.cpp +++ b/lib/AST/DiagnosticEngine.cpp @@ -480,7 +480,7 @@ static bool isInterestingTypealias(Type type) { else return false; - if (aliasDecl->getUnderlyingType()->isVoid()) + if (type->isVoid()) return false; // The 'Swift.AnyObject' typealias is not 'interesting'. From b859ac14447fe6548d73923ec3cd25b735216826 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Sat, 26 Mar 2022 19:04:44 -0400 Subject: [PATCH 2/2] RequirementMachine: Unwrap outer TypeAliasType on protocol typealiases A protocol typealias 'typealias T = X' introduces a same-type requirement 'Self.T == Self.X'. However the right hand side of the requirement was wrapped in a sugared TypeAliasType. This meant if the requirement surfaced in a redundancy diagnostic, it would print as 'Self.T == Self.T'. It could also trigger a request cycle via isInterestingTypealias() in DiagnosticEngine.cpp. --- lib/AST/RequirementMachine/RequirementLowering.cpp | 6 ++++++ test/Generics/protocol_typealias_cycle_5.swift | 7 +++++++ 2 files changed, 13 insertions(+) create mode 100644 test/Generics/protocol_typealias_cycle_5.swift diff --git a/lib/AST/RequirementMachine/RequirementLowering.cpp b/lib/AST/RequirementMachine/RequirementLowering.cpp index 74a81aecd35a2..52b1c215d301d 100644 --- a/lib/AST/RequirementMachine/RequirementLowering.cpp +++ b/lib/AST/RequirementMachine/RequirementLowering.cpp @@ -712,7 +712,13 @@ StructuralRequirementsRequest::evaluate(Evaluator &evaluator, if (assocTypes.contains(typeAliasDecl->getName())) continue; + // The structural type of a typealias will always be a TypeAliasType, + // so unwrap it to avoid a requirement that prints as 'Self.T == Self.T' + // in diagnostics. auto underlyingType = typeAliasDecl->getStructuralType(); + if (auto *aliasType = dyn_cast(underlyingType.getPointer())) + underlyingType = aliasType->getSinglyDesugaredType(); + if (underlyingType->is()) continue; diff --git a/test/Generics/protocol_typealias_cycle_5.swift b/test/Generics/protocol_typealias_cycle_5.swift new file mode 100644 index 0000000000000..b706cbfa774dc --- /dev/null +++ b/test/Generics/protocol_typealias_cycle_5.swift @@ -0,0 +1,7 @@ +// RUN: %target-typecheck-verify-swift -requirement-machine-protocol-signatures=on + +protocol P : Sequence { + typealias Element = Iterator.Element + // expected-warning@-1 {{typealias overriding associated type 'Element' from protocol 'Sequence' is better expressed as same-type constraint on the protocol}} + // expected-warning@-2 {{redundant same-type constraint 'Self.Element' == 'Self.Iterator.Element'}} +}