Skip to content

Fix easy crashers #10151

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 8 commits into from
Jun 7, 2017
6 changes: 4 additions & 2 deletions lib/AST/ASTDumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -642,8 +642,10 @@ namespace {
void printAbstractTypeParamCommon(AbstractTypeParamDecl *decl,
const char *name) {
printCommon(decl, name);
if (auto superclassTy = decl->getSuperclass()) {
OS << " superclass='" << superclassTy->getString() << "'";
if (decl->getDeclContext()->getGenericEnvironmentOfContext()) {
if (auto superclassTy = decl->getSuperclass()) {
OS << " superclass='" << superclassTy->getString() << "'";
}
}
}

Expand Down
6 changes: 6 additions & 0 deletions lib/AST/DeclContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -445,6 +445,12 @@ DeclContext *DeclContext::getParentForLookup() const {
// outer types.
return getModuleScopeContext();
}
if (isa<NominalTypeDecl>(this)) {
// If we are inside a nominal type that is inside a protocol,
// skip the protocol.
if (isa<ProtocolDecl>(getParent()))
return getModuleScopeContext();
}
return getParent();
}

Expand Down
14 changes: 8 additions & 6 deletions lib/AST/Type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3906,24 +3906,25 @@ case TypeKind::Id:

case TypeKind::ProtocolComposition: {
auto pc = cast<ProtocolCompositionType>(base);
SmallVector<Type, 4> members;
SmallVector<Type, 4> substMembers;
auto members = pc->getMembers();
bool anyChanged = false;
unsigned index = 0;
for (auto member : pc->getMembers()) {
for (auto member : members) {
auto substMember = member.transformRec(fn);
if (!substMember)
return Type();

if (anyChanged) {
members.push_back(substMember);
substMembers.push_back(substMember);
++index;
continue;
}

if (substMember.getPointer() != member.getPointer()) {
anyChanged = true;
members.append(members.begin(), members.begin() + index);
members.push_back(substMember);
substMembers.append(members.begin(), members.begin() + index);
substMembers.push_back(substMember);
}

++index;
Expand All @@ -3932,7 +3933,8 @@ case TypeKind::Id:
if (!anyChanged)
return *this;

return ProtocolCompositionType::get(Ptr->getASTContext(), members,
return ProtocolCompositionType::get(Ptr->getASTContext(),
substMembers,
pc->hasExplicitAnyObject());
}
}
Expand Down
2 changes: 0 additions & 2 deletions lib/Sema/ITCDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -342,8 +342,6 @@ void IterativeTypeChecker::processResolveTypeDecl(
if (auto typeAliasDecl = dyn_cast<TypeAliasDecl>(typeDecl)) {
if (typeAliasDecl->getDeclContext()->isModuleScopeContext() &&
typeAliasDecl->getGenericParams() == nullptr) {
typeAliasDecl->setValidationStarted();

TypeResolutionOptions options = TR_TypeAliasUnderlyingType;
if (typeAliasDecl->getFormalAccess() <= Accessibility::FilePrivate)
options |= TR_KnownNonCascadingDependency;
Expand Down
15 changes: 15 additions & 0 deletions lib/Sema/TypeCheckNameLookup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,14 @@ LookupTypeResult TypeChecker::lookupMemberType(DeclContext *dc,
continue;
}
}

// Nominal type members of protocols cannot be accessed with an
// archetype base, because we have no way to recover the correct
// substitutions.
if (type->is<ArchetypeType>() &&
isa<NominalTypeDecl>(typeDecl)) {
continue;
}
}

// Substitute the base into the member's type.
Expand Down Expand Up @@ -451,6 +459,13 @@ LookupTypeResult TypeChecker::lookupMemberType(DeclContext *dc,
// Use the type witness.
auto concrete = conformance->getConcrete();
Type memberType = concrete->getTypeWitness(assocType, this);

// This is the only case where NormalProtocolConformance::
// getTypeWitnessAndDecl() returns a null type.
if (concrete->getState() ==
ProtocolConformanceState::CheckingTypeWitnesses)
continue;

assert(memberType && "Missing type witness?");

// If we haven't seen this type result yet, add it to the result set.
Expand Down
23 changes: 17 additions & 6 deletions lib/Sema/TypeCheckProtocol.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3286,15 +3286,21 @@ ResolveWitnessResult ConformanceChecker::resolveWitnessViaDefault(
///
/// \returns an empty result on success, or a description of the error.
static CheckTypeWitnessResult checkTypeWitness(TypeChecker &tc, DeclContext *dc,
ProtocolDecl *proto,
AssociatedTypeDecl *assocType,
Type type) {
if (auto superclass = assocType->getSuperclass()) {
auto *moduleDecl = dc->getParentModule();
auto *reqtSig = assocType->getProtocol()->getRequirementSignature();
auto *depTy = DependentMemberType::get(proto->getSelfInterfaceType(),
assocType);

if (auto superclass = reqtSig->getSuperclassBound(depTy, *moduleDecl)) {
if (!superclass->isExactSuperclassOf(type))
return superclass->getAnyNominal();
}

// Check protocol conformances.
for (auto reqProto : assocType->getConformingProtocols()) {
for (auto reqProto : reqtSig->getConformsTo(depTy, *moduleDecl)) {
if (!tc.conformsToProtocol(type, reqProto, dc, None))
return reqProto;

Expand Down Expand Up @@ -3323,6 +3329,11 @@ static CheckTypeWitnessResult checkTypeWitness(TypeChecker &tc, DeclContext *dc,
/// Attempt to resolve a type witness via member name lookup.
ResolveWitnessResult ConformanceChecker::resolveTypeWitnessViaLookup(
AssociatedTypeDecl *assocType) {
if (!Proto->isRequirementSignatureComputed()) {
Conformance->setInvalid();
return ResolveWitnessResult::Missing;
}

// Look for a member type with the same name as the associated type.
auto candidates = TC.lookupMemberType(DC, Adoptee, assocType->getName(),
NameLookupFlags::ProtocolMembers);
Expand All @@ -3342,7 +3353,7 @@ ResolveWitnessResult ConformanceChecker::resolveTypeWitnessViaLookup(
continue;

// Check this type against the protocol requirements.
if (auto checkResult = checkTypeWitness(TC, DC, assocType,
if (auto checkResult = checkTypeWitness(TC, DC, Proto, assocType,
candidate.second)) {
auto reqProto = checkResult.getProtocolOrClass();
nonViable.push_back({candidate.first, reqProto});
Expand Down Expand Up @@ -3603,7 +3614,7 @@ ConformanceChecker::inferTypeWitnessesViaValueWitnesses(
if (!canInferFromOtherAssociatedType) {
// Check that the type witness meets the
// requirements on the associated type.
if (auto failed = checkTypeWitness(TC, DC, result.first,
if (auto failed = checkTypeWitness(TC, DC, Proto, result.first,
result.second)) {
witnessResult.NonViable.push_back(
std::make_tuple(result.first,result.second,failed));
Expand Down Expand Up @@ -4196,7 +4207,7 @@ void ConformanceChecker::resolveTypeWitnesses() {
if (!defaultType)
return Type();

if (auto failed = checkTypeWitness(TC, DC, assocType, defaultType)) {
if (auto failed = checkTypeWitness(TC, DC, Proto, assocType, defaultType)) {
// Record the failure, if we haven't seen one already.
if (!failedDefaultedAssocType) {
failedDefaultedAssocType = assocType;
Expand Down Expand Up @@ -4231,7 +4242,7 @@ void ConformanceChecker::resolveTypeWitnesses() {
return Type();

// Make sure that the derived type is sane.
if (checkTypeWitness(TC, DC, assocType, derivedType)) {
if (checkTypeWitness(TC, DC, Proto, assocType, derivedType)) {
diagnoseOrDefer(assocType, true,
[derivedType](NormalProtocolConformance *conformance) {
// FIXME: give more detail here?
Expand Down
2 changes: 2 additions & 0 deletions test/decl/nested/protocol.swift
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,11 @@ protocol Racoon {
associatedtype Stripes
class Claw<T> { // expected-error{{type 'Claw' cannot be nested in protocol 'Racoon'}}
func mangle(_ s: Stripes) {}
// expected-error@-1 {{use of undeclared type 'Stripes'}}
}
struct Fang<T> { // expected-error{{type 'Fang' cannot be nested in protocol 'Racoon'}}
func gnaw(_ s: Stripes) {}
// expected-error@-1 {{use of undeclared type 'Stripes'}}
}
enum Fur { // expected-error{{type 'Fur' cannot be nested in protocol 'Racoon'}}
case Stripes
Expand Down
2 changes: 2 additions & 0 deletions test/decl/typealias/protocol.swift
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,8 @@ struct S7 : P7 {

func inExpressionContext() {
_ = Y.self
_ = T5.T1.self
_ = T5.T2.self
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors

// REQUIRES: asserts
// RUN: not --crash %target-swift-frontend %s -emit-ir
// RUN: not %target-swift-frontend %s -emit-ir
typealias e:a
struct A:a{}typealias a=A
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors

// REQUIRES: asserts
// RUN: not --crash %target-swift-frontend %s -emit-ir
// RUN: not %target-swift-frontend %s -emit-ir
protocol P{class a:Self.a
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors

// REQUIRES: asserts
// RUN: not --crash %target-swift-frontend %s -emit-ir
// RUN: not %target-swift-frontend %s -emit-ir
protocol A:a{{}typealias e:a}{}class a:A{typealias e:b
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors

// REQUIRES: asserts
// RUN: not --crash %target-swift-frontend %s -emit-ir
// RUN: not %target-swift-frontend %s -emit-ir
{class a:P{{}typealias a:Self.a}protocol P{typealias a
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors

// REQUIRES: asserts
// RUN: not --crash %target-swift-frontend %s -emit-ir
// RUN: not %target-swift-frontend %s -emit-ir
protocol A:A{{}class a{let ca{a{
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors

// REQUIRES: asserts
// RUN: not --crash %target-swift-frontend %s -emit-ir
// RUN: not %target-swift-frontend %s -emit-ir
protocol P{{}class a:A{}protocol A:P.a{typealias a{}func a:a
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors

// REQUIRES: asserts
// RUN: not --crash %target-swift-frontend %s -emit-ir
// RUN: not %target-swift-frontend %s -emit-ir
Indexable
& ManagedBuffer
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors

// RUN: not --crash %target-swift-frontend %s -emit-ir
// RUN: not %target-swift-frontend %s -emit-ir
@objc protocol P{{}typealias a{}class a{let c=a{