Skip to content

Collected fixes from the 4.1 branch #14612

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Feb 14, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions include/swift/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -2219,9 +2219,7 @@ class ValueDecl : public Decl {
/// Set the interface type for the given value.
void setInterfaceType(Type type);

bool hasValidSignature() const {
return hasInterfaceType() && !isBeingValidated();
}
bool hasValidSignature() const;

/// isSettable - Determine whether references to this decl may appear
/// on the left-hand side of an assignment or as the operand of a
Expand Down
4 changes: 4 additions & 0 deletions lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1964,6 +1964,10 @@ void ValueDecl::setInterfaceType(Type type) {
TypeAndAccess.setPointer(type);
}

bool ValueDecl::hasValidSignature() const {
return hasInterfaceType() && !isBeingValidated();
}

Optional<ObjCSelector> ValueDecl::getObjCRuntimeName() const {
if (auto func = dyn_cast<AbstractFunctionDecl>(this))
return func->getObjCSelector();
Expand Down
62 changes: 48 additions & 14 deletions lib/AST/GenericSignature.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -958,20 +958,32 @@ static bool hasNonCanonicalSelfProtocolRequirement(

/// Retrieve the best requirement source from the list
static const RequirementSource *
getBestCanonicalRequirementSource(
ArrayRef<GSBConstraint<ProtocolDecl *>> constraints) {
getBestRequirementSource(ArrayRef<GSBConstraint<ProtocolDecl *>> constraints) {
const RequirementSource *bestSource = nullptr;
bool bestIsNonCanonical = false;

auto isBetter = [&](const RequirementSource *source, bool isNonCanonical) {
if (!bestSource) return true;

if (bestIsNonCanonical != isNonCanonical)
return bestIsNonCanonical;

return bestSource->compare(source) > 0;
};

for (const auto &constraint : constraints) {
auto source = constraint.source;

// If there is a non-canonical protocol requirement next to the root,
// skip this requirement source.
if (hasNonCanonicalSelfProtocolRequirement(source, constraint.value))
continue;
bool isNonCanonical =
hasNonCanonicalSelfProtocolRequirement(source, constraint.value);

// Check whether this is better than our best source.
if (!bestSource || source->compare(bestSource) < 0)
if (isBetter(source, isNonCanonical)) {
bestSource = source;
bestIsNonCanonical = isNonCanonical;
continue;
}
}

return bestSource;
Expand Down Expand Up @@ -1007,13 +1019,32 @@ ConformanceAccessPath GenericSignature::getConformanceAccessPath(
ProtocolDecl *requirementSignatureProto) {
// Each protocol requirement is a step along the path.
if (source->isProtocolRequirement()) {
// If we're expanding for a protocol that has no requirement signature
// (yet) and have hit the penultimate step, this is the last step
// If we're expanding for a protocol that had no requirement signature
// and have hit the penultimate step, this is the last step
// that would occur in the requirement signature.
Optional<GenericSignatureBuilder> replacementBuilder;
if (!source->parent->parent && requirementSignatureProto) {
Type subjectType = source->getStoredType()->getCanonicalType();
path.path.push_back({subjectType, conformingProto});
return;
// If we have a requirement signature now, we're done.
if (source->usesRequirementSignature) {
Type subjectType = source->getStoredType()->getCanonicalType();
path.path.push_back({subjectType, conformingProto});
return;
}

// The generic signature builder we're using for this protocol
// wasn't built from its own requirement signature, so we can't
// trust it. Make sure we have a requirement signature, then build
// a new generic signature builder.
// FIXME: It would be better if we could replace the canonical generic
// signature builder with the rebuilt one.
if (!requirementSignatureProto->isRequirementSignatureComputed())
requirementSignatureProto->computeRequirementSignature();
assert(requirementSignatureProto->isRequirementSignatureComputed());

replacementBuilder.emplace(getASTContext());
replacementBuilder->addGenericSignature(
requirementSignatureProto->getGenericSignature());
replacementBuilder->processDelayedRequirements();
}

// Follow the rest of the path to derive the conformance into which
Expand Down Expand Up @@ -1046,9 +1077,12 @@ ConformanceAccessPath GenericSignature::getConformanceAccessPath(
return;
}

// Get the generic signature builder for the protocol.
// Get a generic signature for the protocol's signature.
auto inProtoSig = inProtocol->getGenericSignature();
auto &inProtoSigBuilder = *inProtoSig->getGenericSignatureBuilder();
auto &inProtoSigBuilder =
replacementBuilder ? *replacementBuilder
: *inProtoSig->getGenericSignatureBuilder();

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

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

// Canonicalize the root type.
auto source = getBestCanonicalRequirementSource(conforms->second);
auto source = getBestRequirementSource(conforms->second);
Type rootType = source->getRootType()->getCanonicalType(this);

// Build the path.
Expand Down
2 changes: 1 addition & 1 deletion lib/Sema/ConstraintSystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1074,7 +1074,7 @@ void ConstraintSystem::openGeneric(

// Create the type variables for the generic parameters.
for (auto gp : sig->getGenericParams()) {
auto contextTy = genericEnv->mapTypeIntoContext(gp);
auto contextTy = GenericEnvironment::mapTypeIntoContext(genericEnv, gp);
if (auto *archetype = contextTy->getAs<ArchetypeType>())
locatorPtr = getConstraintLocator(
locator.withPathElement(LocatorPathElt(archetype)));
Expand Down
13 changes: 12 additions & 1 deletion lib/Sema/TypeCheckProtocol.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -941,9 +941,15 @@ bool WitnessChecker::findBestWitness(
continue;
}

if (!witness->hasInterfaceType())
if (!witness->hasValidSignature()) {
TC.validateDecl(witness);

if (!witness->hasValidSignature()) {
doNotDiagnoseMatches = true;
continue;
}
}

auto match = matchWitness(TC, Proto, conformance, DC,
requirement, witness);
if (match.isViable()) {
Expand Down Expand Up @@ -4015,6 +4021,11 @@ static bool shouldWarnAboutPotentialWitness(
isUnlabeledInitializerOrSubscript(witness))
return false;

// For non-@objc requirements, only warn if the witness comes from an
// extension.
if (!req->isObjC() && !isa<ExtensionDecl>(witness->getDeclContext()))
return false;

// If the score is relatively high, don't warn: this is probably
// unrelated. Allow about one typo for every four properly-typed
// characters, which prevents completely-wacky suggestions in many
Expand Down
3 changes: 2 additions & 1 deletion lib/Serialization/Deserialization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -738,7 +738,8 @@ GenericParamList *ModuleFile::maybeReadGenericParams(DeclContext *DC,
// precede SIL linkage, we should be ok.
assert((genericParam->getDeclContext()->isModuleScopeContext() ||
DC->isModuleScopeContext() ||
genericParam->getDeclContext() == DC) &&
genericParam->getDeclContext() == DC ||
genericParam->getDeclContext()->isChildContextOf(DC)) &&
"Mismatched decl context for generic types.");
params.push_back(genericParam);
break;
Expand Down
4 changes: 4 additions & 0 deletions test/SIL/Serialization/Inputs/def_generic.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,8 @@ public class A<T> {
@_versioned
@_inlineable
init() {}

@_inlineable public subscript<U>(value: T) -> U? {
return nil
}
}
7 changes: 2 additions & 5 deletions test/decl/ext/protocol.swift
Original file line number Diff line number Diff line change
Expand Up @@ -526,7 +526,7 @@ struct SConforms7a : PConforms7 { }
protocol PConforms8 {
associatedtype Assoc

func method() -> Assoc // expected-note{{requirement 'method()' declared here}}
func method() -> Assoc
var property: Assoc { get }
subscript (i: Assoc) -> Assoc { get }
}
Expand All @@ -551,10 +551,7 @@ func testSConforms8b() {
}

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

func testSConforms8c() {
Expand Down