Skip to content

[4.0] Collected fixes #8970

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
Apr 24, 2017
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: 4 additions & 0 deletions include/swift/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -5308,6 +5308,10 @@ class FuncDecl final : public AbstractFunctionDecl,

/// True if the function is a defer body.
bool isDeferBody() const;

/// Perform basic checking to determine whether the @IBAction attribute can
/// be applied to this function.
bool isPotentialIBActionTarget() const;
};

/// \brief This represents a 'case' declaration in an 'enum', which may declare
Expand Down
34 changes: 28 additions & 6 deletions lib/AST/ASTVerifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -388,7 +388,7 @@ class Verifier : public ASTWalker {
// If we've checked types already, do some extra verification.
if (!SF || SF->ASTStage >= SourceFile::TypeChecked) {
verifyCheckedAlways(node);
if (!HadError)
if (!HadError && shouldVerifyChecked(node))
verifyChecked(node);
}

Expand All @@ -405,6 +405,12 @@ class Verifier : public ASTWalker {
bool shouldVerify(Pattern *S) { return true; }
bool shouldVerify(Decl *S) { return true; }

// Default cases for whether we should verify a checked subtree.
bool shouldVerifyChecked(Expr *E) { return !E->getType().isNull(); }
bool shouldVerifyChecked(Stmt *S) { return true; }
bool shouldVerifyChecked(Pattern *S) { return S->hasType(); }
bool shouldVerifyChecked(Decl *S) { return true; }

// Default cases for cleaning up as we exit a node.
void cleanup(Expr *E) { }
void cleanup(Stmt *S) { }
Expand Down Expand Up @@ -782,20 +788,32 @@ class Verifier : public ASTWalker {
verifyCheckedAlwaysBase(D);
}

bool shouldVerifyChecked(ThrowStmt *S) {
return shouldVerifyChecked(S->getSubExpr());
}

void verifyChecked(ThrowStmt *S) {
checkSameType(S->getSubExpr()->getType(),
checkExceptionTypeExists("throw expression"),
"throw operand");
verifyCheckedBase(S);
}

bool shouldVerifyChecked(CatchStmt *S) {
return shouldVerifyChecked(S->getErrorPattern());
}

void verifyChecked(CatchStmt *S) {
checkSameType(S->getErrorPattern()->getType(),
checkExceptionTypeExists("catch statement"),
"catch pattern");
verifyCheckedBase(S);
}

bool shouldVerifyChecked(ReturnStmt *S) {
return !S->hasResult() || shouldVerifyChecked(S->getResult());
}

void verifyChecked(ReturnStmt *S) {
auto func = Functions.back();
Type resultType;
Expand Down Expand Up @@ -849,15 +867,19 @@ class Verifier : public ASTWalker {
case StmtConditionElement::CK_Availability: break;
case StmtConditionElement::CK_Boolean: {
auto *E = elt.getBoolean();
checkSameType(E->getType(), BuiltinIntegerType::get(1, Ctx),
"condition type");
if (shouldVerifyChecked(E))
checkSameType(E->getType(), BuiltinIntegerType::get(1, Ctx),
"condition type");
break;
}

case StmtConditionElement::CK_PatternBinding:
checkSameType(elt.getPattern()->getType(),
elt.getInitializer()->getType(),
"conditional binding type");
if (shouldVerifyChecked(elt.getPattern()) &&
shouldVerifyChecked(elt.getInitializer())) {
checkSameType(elt.getPattern()->getType(),
elt.getInitializer()->getType(),
"conditional binding type");
}
break;
}
}
Expand Down
3 changes: 1 addition & 2 deletions lib/AST/ConformanceLookupTable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -809,8 +809,7 @@ ProtocolConformance *ConformanceLookupTable::getConformance(
ModuleDecl *module = entry->getDeclContext()->getParentModule();
auto inheritedConformance = module->lookupConformance(superclassTy,
protocol,
resolver)
.getPointer();
resolver);

// Form the inherited conformance.
conformance = ctx.getInheritedConformance(
Expand Down
6 changes: 6 additions & 0 deletions lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5111,6 +5111,12 @@ bool FuncDecl::isDeferBody() const {
return getName() == getASTContext().getIdentifier("$defer");
}

bool FuncDecl::isPotentialIBActionTarget() const {
return isInstanceMember() &&
getDeclContext()->getAsClassOrClassExtensionContext() &&
!isAccessor();
}

Type TypeBase::getSwiftNewtypeUnderlyingType() {
auto structDecl = getStructOrBoundGenericStruct();
if (!structDecl)
Expand Down
5 changes: 4 additions & 1 deletion lib/ClangImporter/ImportDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3703,9 +3703,12 @@ namespace {
}

// Handle attributes.
if (decl->hasAttr<clang::IBActionAttr>())
if (decl->hasAttr<clang::IBActionAttr>() &&
isa<FuncDecl>(result) &&
cast<FuncDecl>(result)->isPotentialIBActionTarget()) {
result->getAttrs().add(
new (Impl.SwiftContext) IBActionAttr(/*IsImplicit=*/false));
}

// Check whether there's some special method to import.
if (!forceClassMethod) {
Expand Down
21 changes: 15 additions & 6 deletions lib/Sema/TypeCheckAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,19 @@ class AttributeEarlyChecker : public AttributeVisitor<AttributeEarlyChecker> {
/// This emits a diagnostic with a fixit to remove the attribute.
template<typename ...ArgTypes>
void diagnoseAndRemoveAttr(DeclAttribute *attr, ArgTypes &&...Args) {
TC.diagnose(attr->getLocation(), std::forward<ArgTypes>(Args)...)
.fixItRemove(attr->getRangeWithAt());
assert(!D->hasClangNode() && "Clang imported propagated a bogus attribute");
if (!D->hasClangNode()) {
SourceLoc loc = attr->getLocation();
assert(loc.isValid() && "Diagnosing attribute with invalid location");
if (loc.isInvalid()) {
loc = D->getLoc();
}
if (loc.isValid()) {
TC.diagnose(loc, std::forward<ArgTypes>(Args)...)
.fixItRemove(attr->getRangeWithAt());
}
}

attr->setInvalid();
}

Expand Down Expand Up @@ -304,10 +315,8 @@ void AttributeEarlyChecker::visitDynamicAttr(DynamicAttr *attr) {
void AttributeEarlyChecker::visitIBActionAttr(IBActionAttr *attr) {
// Only instance methods returning () can be IBActions.
const FuncDecl *FD = cast<FuncDecl>(D);
if (!FD->getDeclContext()->getAsClassOrClassExtensionContext() ||
FD->isStatic() || FD->isAccessor())
if (!FD->isPotentialIBActionTarget())
return diagnoseAndRemoveAttr(attr, diag::invalid_ibaction_decl);

}

void AttributeEarlyChecker::visitIBDesignableAttr(IBDesignableAttr *attr) {
Expand Down Expand Up @@ -1627,7 +1636,7 @@ void AttributeChecker::visitSpecializeAttr(SpecializeAttr *attr) {

// Form a new generic signature based on the old one.
GenericSignatureBuilder Builder(D->getASTContext(),
LookUpConformanceInModule(DC->getParentModule()));
TypeChecker::LookUpConformance(TC, DC));

// First, add the old generic signature.
Builder.addGenericSignature(genericSig);
Expand Down
8 changes: 3 additions & 5 deletions lib/Sema/TypeCheckGeneric.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -797,8 +797,7 @@ TypeChecker::validateGenericFuncSignature(AbstractFunctionDecl *func) {
addGenericParamTypes(gp, allGenericParams);

// Create the generic signature builder.
GenericSignatureBuilder builder(Context,
LookUpConformanceInModule(func->getParentModule()));
GenericSignatureBuilder builder(Context, LookUpConformance(*this, func));

// Type check the function declaration, treating all generic type
// parameters as dependent, unresolved.
Expand Down Expand Up @@ -1028,8 +1027,7 @@ TypeChecker::validateGenericSubscriptSignature(SubscriptDecl *subscript) {
addGenericParamTypes(gp, allGenericParams);

// Create the generic signature builder.
GenericSignatureBuilder builder(Context,
LookUpConformanceInModule(subscript->getParentModule()));
GenericSignatureBuilder builder(Context, LookUpConformance(*this, subscript));

// Type check the function declaration, treating all generic type
// parameters as dependent, unresolved.
Expand Down Expand Up @@ -1148,7 +1146,7 @@ GenericEnvironment *TypeChecker::checkGenericEnvironment(

// Create the generic signature builder.
ModuleDecl *module = dc->getParentModule();
GenericSignatureBuilder builder(Context, LookUpConformanceInModule(module));
GenericSignatureBuilder builder(Context, LookUpConformance(*this, dc));

// Type check the generic parameters, treating all generic type
// parameters as dependent, unresolved.
Expand Down
27 changes: 21 additions & 6 deletions lib/Sema/TypeCheckProtocol.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -997,12 +997,13 @@ RequirementEnvironment::RequirementEnvironment(
auto selfType = cast<GenericTypeParamType>(
proto->getSelfInterfaceType()->getCanonicalType());

// Construct a generic signature builder by collecting the constraints from the
// requirement and the context of the conformance together, because both
// define the capabilities of the requirement.
// Construct a generic signature builder by collecting the constraints
// from the requirement and the context of the conformance together,
// because both define the capabilities of the requirement.
GenericSignatureBuilder builder(
ctx,
LookUpConformanceInModule(conformanceDC->getParentModule()));
TypeChecker::LookUpConformance(tc, conformanceDC));

SmallVector<GenericTypeParamType*, 4> allGenericParams;

// Add the generic signature of the context of the conformance. This includes
Expand Down Expand Up @@ -4776,8 +4777,7 @@ void ConformanceChecker::ensureRequirementsAreSatisfied() {
// FIXME: maybe this should be the conformance's type
proto->getDeclaredInterfaceType(), reqSig,
QuerySubstitutionMap{substitutions},
LookUpConformanceInModule(
Conformance->getDeclContext()->getParentModule()),
TypeChecker::LookUpConformance(TC, Conformance->getDeclContext()),
nullptr,
ConformanceCheckFlags::Used, &listener);

Expand Down Expand Up @@ -5268,6 +5268,21 @@ TypeChecker::conformsToProtocol(Type T, ProtocolDecl *Proto, DeclContext *DC,
: ConformsToProtocolResult::failure();
}

Optional<ProtocolConformanceRef>
TypeChecker::LookUpConformance::operator()(
CanType dependentType,
Type conformingReplacementType,
ProtocolType *conformedProtocol) const {
if (conformingReplacementType->isTypeParameter())
return ProtocolConformanceRef(conformedProtocol->getDecl());

return tc.conformsToProtocol(conformingReplacementType,
conformedProtocol->getDecl(),
dc,
(ConformanceCheckFlags::Used|
ConformanceCheckFlags::InExpression));
}

/// Mark any _ObjectiveCBridgeable conformances in the given type as "used".
///
/// These conformances might not appear in any substitution lists produced
Expand Down
4 changes: 2 additions & 2 deletions lib/Sema/TypeCheckType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -743,7 +743,7 @@ Type TypeChecker::applyUnboundGenericArguments(
auto result =
checkGenericArguments(dc, loc, noteLoc, unboundType, genericSig,
QueryTypeSubstitutionMap{subs},
LookUpConformanceInModule{dc->getParentModule()},
LookUpConformance(*this, dc),
unsatisfiedDependency);

switch (result) {
Expand All @@ -758,7 +758,7 @@ Type TypeChecker::applyUnboundGenericArguments(

// Apply the substitution map to the interface type of the declaration.
resultType = resultType.subst(QueryTypeSubstitutionMap{subs},
LookUpConformanceInModule(dc->getParentModule()),
LookUpConformance(*this, dc),
SubstFlags::UseErrorType);

if (isa<NominalTypeDecl>(decl)) {
Expand Down
17 changes: 17 additions & 0 deletions lib/Sema/TypeChecker.h
Original file line number Diff line number Diff line change
Expand Up @@ -1814,6 +1814,23 @@ class TypeChecker final : public LazyResolver {
ConformanceCheckOptions options, SourceLoc ComplainLoc,
UnsatisfiedDependency *unsatisfiedDependency);

/// Functor class suitable for use as a \c LookupConformanceFn to look up a
/// conformance through a particular declaration context using the given
/// type checker.
class LookUpConformance {
TypeChecker &tc;
DeclContext *dc;

public:
explicit LookUpConformance(TypeChecker &tc, DeclContext *dc)
: tc(tc), dc(dc) { }

Optional<ProtocolConformanceRef>
operator()(CanType dependentType,
Type conformingReplacementType,
ProtocolType *conformedProtocol) const;
};

/// Completely check the given conformance.
void checkConformance(NormalProtocolConformance *conformance);

Expand Down
9 changes: 9 additions & 0 deletions test/ClangImporter/Inputs/ibaction.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
@import ObjectiveC;

@protocol IBActionInProtocol
-(void) __attribute__((ibaction)) actionMethod:(_Nullable id)param;
@end

@interface ConformsToIBActionInProtocol : NSObject <IBActionInProtocol>
@end

6 changes: 6 additions & 0 deletions test/ClangImporter/objc_ibaction.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// RUN: %target-swift-frontend -emit-sil %s -import-objc-header %S/Inputs/ibaction.h -verify
// REQUIRES: objc_interop

func foo(object: ConformsToIBActionInProtocol) {
object.actionMethod(object)
}
12 changes: 12 additions & 0 deletions test/multifile/Inputs/for_each_conformance_crashB.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
protocol _P { }
protocol P : _P { }

protocol Q {
associatedtype A: P

func getArray() -> [RequiresP<A>]
}

struct RequiresP<T: P> { }

struct MyStruct: P { }
7 changes: 7 additions & 0 deletions test/multifile/for_each_conformance_crash.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// RUN: %target-swift-frontend -emit-ir %S/Inputs/for_each_conformance_crashB.swift -primary-file %s -o -

extension Q where A == MyStruct {
func foo() {
for _ in getArray() { }
}
}