Skip to content

Commit 312abd7

Browse files
authored
Merge pull request #14612 from DougGregor/collected-fixes
Collected fixes from the 4.1 branch
2 parents 572b353 + 6bff42c commit 312abd7

File tree

8 files changed

+74
-25
lines changed

8 files changed

+74
-25
lines changed

include/swift/AST/Decl.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2219,9 +2219,7 @@ class ValueDecl : public Decl {
22192219
/// Set the interface type for the given value.
22202220
void setInterfaceType(Type type);
22212221

2222-
bool hasValidSignature() const {
2223-
return hasInterfaceType() && !isBeingValidated();
2224-
}
2222+
bool hasValidSignature() const;
22252223

22262224
/// isSettable - Determine whether references to this decl may appear
22272225
/// on the left-hand side of an assignment or as the operand of a

lib/AST/Decl.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1964,6 +1964,10 @@ void ValueDecl::setInterfaceType(Type type) {
19641964
TypeAndAccess.setPointer(type);
19651965
}
19661966

1967+
bool ValueDecl::hasValidSignature() const {
1968+
return hasInterfaceType() && !isBeingValidated();
1969+
}
1970+
19671971
Optional<ObjCSelector> ValueDecl::getObjCRuntimeName() const {
19681972
if (auto func = dyn_cast<AbstractFunctionDecl>(this))
19691973
return func->getObjCSelector();

lib/AST/GenericSignature.cpp

Lines changed: 48 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -958,20 +958,32 @@ static bool hasNonCanonicalSelfProtocolRequirement(
958958

959959
/// Retrieve the best requirement source from the list
960960
static const RequirementSource *
961-
getBestCanonicalRequirementSource(
962-
ArrayRef<GSBConstraint<ProtocolDecl *>> constraints) {
961+
getBestRequirementSource(ArrayRef<GSBConstraint<ProtocolDecl *>> constraints) {
963962
const RequirementSource *bestSource = nullptr;
963+
bool bestIsNonCanonical = false;
964+
965+
auto isBetter = [&](const RequirementSource *source, bool isNonCanonical) {
966+
if (!bestSource) return true;
967+
968+
if (bestIsNonCanonical != isNonCanonical)
969+
return bestIsNonCanonical;
970+
971+
return bestSource->compare(source) > 0;
972+
};
973+
964974
for (const auto &constraint : constraints) {
965975
auto source = constraint.source;
966976

967977
// If there is a non-canonical protocol requirement next to the root,
968978
// skip this requirement source.
969-
if (hasNonCanonicalSelfProtocolRequirement(source, constraint.value))
970-
continue;
979+
bool isNonCanonical =
980+
hasNonCanonicalSelfProtocolRequirement(source, constraint.value);
971981

972-
// Check whether this is better than our best source.
973-
if (!bestSource || source->compare(bestSource) < 0)
982+
if (isBetter(source, isNonCanonical)) {
974983
bestSource = source;
984+
bestIsNonCanonical = isNonCanonical;
985+
continue;
986+
}
975987
}
976988

977989
return bestSource;
@@ -1007,13 +1019,32 @@ ConformanceAccessPath GenericSignature::getConformanceAccessPath(
10071019
ProtocolDecl *requirementSignatureProto) {
10081020
// Each protocol requirement is a step along the path.
10091021
if (source->isProtocolRequirement()) {
1010-
// If we're expanding for a protocol that has no requirement signature
1011-
// (yet) and have hit the penultimate step, this is the last step
1022+
// If we're expanding for a protocol that had no requirement signature
1023+
// and have hit the penultimate step, this is the last step
10121024
// that would occur in the requirement signature.
1025+
Optional<GenericSignatureBuilder> replacementBuilder;
10131026
if (!source->parent->parent && requirementSignatureProto) {
1014-
Type subjectType = source->getStoredType()->getCanonicalType();
1015-
path.path.push_back({subjectType, conformingProto});
1016-
return;
1027+
// If we have a requirement signature now, we're done.
1028+
if (source->usesRequirementSignature) {
1029+
Type subjectType = source->getStoredType()->getCanonicalType();
1030+
path.path.push_back({subjectType, conformingProto});
1031+
return;
1032+
}
1033+
1034+
// The generic signature builder we're using for this protocol
1035+
// wasn't built from its own requirement signature, so we can't
1036+
// trust it. Make sure we have a requirement signature, then build
1037+
// a new generic signature builder.
1038+
// FIXME: It would be better if we could replace the canonical generic
1039+
// signature builder with the rebuilt one.
1040+
if (!requirementSignatureProto->isRequirementSignatureComputed())
1041+
requirementSignatureProto->computeRequirementSignature();
1042+
assert(requirementSignatureProto->isRequirementSignatureComputed());
1043+
1044+
replacementBuilder.emplace(getASTContext());
1045+
replacementBuilder->addGenericSignature(
1046+
requirementSignatureProto->getGenericSignature());
1047+
replacementBuilder->processDelayedRequirements();
10171048
}
10181049

10191050
// Follow the rest of the path to derive the conformance into which
@@ -1046,9 +1077,12 @@ ConformanceAccessPath GenericSignature::getConformanceAccessPath(
10461077
return;
10471078
}
10481079

1080+
// Get the generic signature builder for the protocol.
10491081
// Get a generic signature for the protocol's signature.
10501082
auto inProtoSig = inProtocol->getGenericSignature();
1051-
auto &inProtoSigBuilder = *inProtoSig->getGenericSignatureBuilder();
1083+
auto &inProtoSigBuilder =
1084+
replacementBuilder ? *replacementBuilder
1085+
: *inProtoSig->getGenericSignatureBuilder();
10521086

10531087
// Retrieve the stored type, but erase all of the specific associated
10541088
// type declarations; we don't want any details of the enclosing context
@@ -1067,7 +1101,7 @@ ConformanceAccessPath GenericSignature::getConformanceAccessPath(
10671101
assert(conforms != equivClass->conformsTo.end());
10681102

10691103
// Compute the root type, canonicalizing it w.r.t. the protocol context.
1070-
auto conformsSource = getBestCanonicalRequirementSource(conforms->second);
1104+
auto conformsSource = getBestRequirementSource(conforms->second);
10711105
assert(conformsSource != source || !requirementSignatureProto);
10721106
Type localRootType = conformsSource->getRootType();
10731107
localRootType = inProtoSig->getCanonicalTypeInContext(localRootType);
@@ -1115,7 +1149,7 @@ ConformanceAccessPath GenericSignature::getConformanceAccessPath(
11151149
};
11161150

11171151
// Canonicalize the root type.
1118-
auto source = getBestCanonicalRequirementSource(conforms->second);
1152+
auto source = getBestRequirementSource(conforms->second);
11191153
Type rootType = source->getRootType()->getCanonicalType(this);
11201154

11211155
// Build the path.

lib/Sema/ConstraintSystem.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1074,7 +1074,7 @@ void ConstraintSystem::openGeneric(
10741074

10751075
// Create the type variables for the generic parameters.
10761076
for (auto gp : sig->getGenericParams()) {
1077-
auto contextTy = genericEnv->mapTypeIntoContext(gp);
1077+
auto contextTy = GenericEnvironment::mapTypeIntoContext(genericEnv, gp);
10781078
if (auto *archetype = contextTy->getAs<ArchetypeType>())
10791079
locatorPtr = getConstraintLocator(
10801080
locator.withPathElement(LocatorPathElt(archetype)));

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -941,9 +941,15 @@ bool WitnessChecker::findBestWitness(
941941
continue;
942942
}
943943

944-
if (!witness->hasInterfaceType())
944+
if (!witness->hasValidSignature()) {
945945
TC.validateDecl(witness);
946946

947+
if (!witness->hasValidSignature()) {
948+
doNotDiagnoseMatches = true;
949+
continue;
950+
}
951+
}
952+
947953
auto match = matchWitness(TC, Proto, conformance, DC,
948954
requirement, witness);
949955
if (match.isViable()) {
@@ -4015,6 +4021,11 @@ static bool shouldWarnAboutPotentialWitness(
40154021
isUnlabeledInitializerOrSubscript(witness))
40164022
return false;
40174023

4024+
// For non-@objc requirements, only warn if the witness comes from an
4025+
// extension.
4026+
if (!req->isObjC() && !isa<ExtensionDecl>(witness->getDeclContext()))
4027+
return false;
4028+
40184029
// If the score is relatively high, don't warn: this is probably
40194030
// unrelated. Allow about one typo for every four properly-typed
40204031
// characters, which prevents completely-wacky suggestions in many

lib/Serialization/Deserialization.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -738,7 +738,8 @@ GenericParamList *ModuleFile::maybeReadGenericParams(DeclContext *DC,
738738
// precede SIL linkage, we should be ok.
739739
assert((genericParam->getDeclContext()->isModuleScopeContext() ||
740740
DC->isModuleScopeContext() ||
741-
genericParam->getDeclContext() == DC) &&
741+
genericParam->getDeclContext() == DC ||
742+
genericParam->getDeclContext()->isChildContextOf(DC)) &&
742743
"Mismatched decl context for generic types.");
743744
params.push_back(genericParam);
744745
break;

test/SIL/Serialization/Inputs/def_generic.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,8 @@ public class A<T> {
99
@_versioned
1010
@_inlineable
1111
init() {}
12+
13+
@_inlineable public subscript<U>(value: T) -> U? {
14+
return nil
15+
}
1216
}

test/decl/ext/protocol.swift

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -526,7 +526,7 @@ struct SConforms7a : PConforms7 { }
526526
protocol PConforms8 {
527527
associatedtype Assoc
528528

529-
func method() -> Assoc // expected-note{{requirement 'method()' declared here}}
529+
func method() -> Assoc
530530
var property: Assoc { get }
531531
subscript (i: Assoc) -> Assoc { get }
532532
}
@@ -551,10 +551,7 @@ func testSConforms8b() {
551551
}
552552

553553
struct SConforms8c : PConforms8 {
554-
func method() -> String { return "" } // expected-warning{{instance method 'method()' nearly matches defaulted requirement 'method()' of protocol 'PConforms8'}}
555-
// expected-note@-1{{candidate has non-matching type '() -> String' [with Assoc = Int]}}
556-
// expected-note@-2{{move 'method()' to an extension to silence this warning}}
557-
// expected-note@-3{{make 'method()' private to silence this warning}}
554+
func method() -> String { return "" } // no warning in type definition
558555
}
559556

560557
func testSConforms8c() {

0 commit comments

Comments
 (0)