Skip to content
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
2 changes: 1 addition & 1 deletion docs/SIL.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5461,7 +5461,7 @@ unconditional_checked_cast_addr
sil-type 'in' sil-operand 'to'
sil-type 'in' sil-operand

unconditional_checked_cast_addr $A in %0 : $*@thick A to $B in $*@thick B
unconditional_checked_cast_addr $A in %0 : $*@thick A to $B in %1 : $*@thick B
// $A and $B must be both addresses
// %1 will be of type $*B
// $A is destroyed during the conversion. There is no implicit copy.
Expand Down
7 changes: 7 additions & 0 deletions lib/SILGen/ManagedValue.h
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,13 @@ class ManagedValue {
return ManagedValue::forOwnedObjectRValue(value, cleanup);
}

static ManagedValue
forExclusivelyBorrowedOwnedObjectRValue(SILValue value,
CleanupHandle cleanup) {
assert(value->getType().isObject());
return ManagedValue::forOwnedObjectRValue(value, cleanup);
}

/// Create a managed value for a +0 borrowed non-trivial rvalue object.
static ManagedValue
forBorrowedObjectRValue(SILValue value) {
Expand Down
2 changes: 1 addition & 1 deletion lib/SILGen/SILGenApply.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1243,7 +1243,7 @@ class SILGenApply : public Lowering::ExprVisitor<SILGenApply> {
if (superMV.getValue() != SGF.InitDelegationSelf.getValue()) {
SILValue underlyingSelf = SGF.InitDelegationSelf.getValue();
SGF.InitDelegationSelf = ManagedValue::forUnmanaged(underlyingSelf);
CleanupHandle newWriteback = SGF.enterDelegateInitSelfWritebackCleanup(
CleanupHandle newWriteback = SGF.enterOwnedValueWritebackCleanup(
SGF.InitDelegationLoc.getValue(), SGF.InitDelegationSelfBox,
superMV.forward(SGF));
SGF.SuperInitDelegationSelf =
Expand Down
30 changes: 14 additions & 16 deletions lib/SILGen/SILGenExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -717,20 +717,20 @@ SILValue SILGenFunction::emitEmptyTuple(SILLocation loc) {

namespace {

/// This is a simple cleanup class that is only meant to help with delegating
/// initializers. Specifically, if the delegating initializer fails to consume
/// the loaded self, we want to write back self into the slot to ensure that
/// ownership is preserved.
struct DelegateInitSelfWritebackCleanup : Cleanup {
/// This is a simple cleanup class that at the end of a lexical scope consumes
/// an owned value by writing it back to memory. The user can forward this
/// cleanup to take ownership of the value and thus prevent it form being
/// written back.
struct OwnedValueWritebackCleanup final : Cleanup {

/// We store our own loc so that we can ensure that DI ignores our writeback.
SILLocation loc;

SILValue lvalueAddress;
SILValue value;

DelegateInitSelfWritebackCleanup(SILLocation loc, SILValue lvalueAddress,
SILValue value)
OwnedValueWritebackCleanup(SILLocation loc, SILValue lvalueAddress,
SILValue value)
: loc(loc), lvalueAddress(lvalueAddress), value(value) {}

void emit(SILGenFunction &SGF, CleanupLocation l, ForUnwind_t forUnwind) override {
Expand All @@ -749,14 +749,13 @@ struct DelegateInitSelfWritebackCleanup : Cleanup {
lvalueObjTy);
}

auto &lowering = SGF.B.getTypeLowering(lvalueAddress->getType());
lowering.emitStore(SGF.B, loc, valueToStore, lvalueAddress,
StoreOwnershipQualifier::Init);
SGF.B.emitStoreValueOperation(loc, valueToStore, lvalueAddress,
StoreOwnershipQualifier::Init);
}

void dump(SILGenFunction &) const override {
#ifndef NDEBUG
llvm::errs() << "SimpleWritebackCleanup "
llvm::errs() << "OwnedValueWritebackCleanup "
<< "State:" << getState() << "\n"
<< "lvalueAddress:" << lvalueAddress << "value:" << value
<< "\n";
Expand All @@ -766,10 +765,9 @@ struct DelegateInitSelfWritebackCleanup : Cleanup {

} // end anonymous namespace

CleanupHandle SILGenFunction::enterDelegateInitSelfWritebackCleanup(
CleanupHandle SILGenFunction::enterOwnedValueWritebackCleanup(
SILLocation loc, SILValue address, SILValue newValue) {
Cleanups.pushCleanup<DelegateInitSelfWritebackCleanup>(loc, address,
newValue);
Cleanups.pushCleanup<OwnedValueWritebackCleanup>(loc, address, newValue);
return Cleanups.getTopCleanup();
}

Expand Down Expand Up @@ -815,8 +813,8 @@ RValue SILGenFunction::emitRValueForSelfInDelegationInit(SILLocation loc,
// Forward our initial value for init delegation self and create a new
// cleanup that performs a writeback at the end of lexical scope if our
// value is not consumed.
InitDelegationSelf = ManagedValue(
self, enterDelegateInitSelfWritebackCleanup(*InitDelegationLoc, addr, self));
InitDelegationSelf = ManagedValue::forExclusivelyBorrowedOwnedObjectRValue(
self, enterOwnedValueWritebackCleanup(*InitDelegationLoc, addr, self));
InitDelegationSelfBox = addr;
return RValue(*this, loc, refType, InitDelegationSelf);
}
Expand Down
6 changes: 3 additions & 3 deletions lib/SILGen/SILGenFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -1188,9 +1188,9 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
CleanupHandle enterDeallocateUninitializedArrayCleanup(SILValue array);
void emitUninitializedArrayDeallocation(SILLocation loc, SILValue array);

CleanupHandle enterDelegateInitSelfWritebackCleanup(SILLocation loc,
SILValue address,
SILValue newValue);
CleanupHandle enterOwnedValueWritebackCleanup(SILLocation loc,
SILValue address,
SILValue newValue);

SILValue emitConversionToSemanticRValue(SILLocation loc, SILValue value,
const TypeLowering &valueTL);
Expand Down
53 changes: 25 additions & 28 deletions lib/Sema/CSSimplify.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7683,10 +7683,30 @@ ConstraintSystem::simplifyKeyPathConstraint(
return true;
};

// We have a hole, the solver can't infer the key path type. So let's
// just assume this is solved.
if (shouldAttemptFixes() && keyPathTy->isHole()) {
return SolutionKind::Solved;
// If we have a hole somewhere in the key path, the solver won't be able to
// infer the key path type. So let's just assume this is solved.
if (shouldAttemptFixes()) {
if (keyPathTy->isHole())
return SolutionKind::Solved;

// If the root type has been bound to a hole, we cannot infer it.
if (getFixedTypeRecursive(rootTy, /*wantRValue*/ true)->isHole())
return SolutionKind::Solved;

// If we have e.g a missing member somewhere, a component type variable
// will have been marked as a potential hole.
// FIXME: This relies on the fact that we only mark an overload type
// variable as a potential hole once we've added a corresponding fix. We
// can't use 'isHole' instead, as that doesn't handle cases where the
// overload type variable gets bound to another type from the context rather
// than a hole. We need to come up with a better way of handling the
// relationship between key paths and overloads.
if (llvm::any_of(componentTypeVars, [&](TypeVariableType *tv) {
return tv->getImpl().getLocator()->isForKeyPathComponent() &&
tv->getImpl().canBindToHole();
})) {
return SolutionKind::Solved;
}
}

// If we're fixed to a bound generic type, trying harvesting context from it.
Expand Down Expand Up @@ -7737,34 +7757,11 @@ ConstraintSystem::simplifyKeyPathConstraint(
// to determine whether the result will be a function type vs BGT KeyPath
// type, so continue through components to create new constraint at the
// end.
if (!overload || anyComponentsUnresolved) {
if (!overload) {
if (flags.contains(TMF_GenerateConstraints)) {
anyComponentsUnresolved = true;
continue;
}

if (shouldAttemptFixes()) {
auto typeVar =
llvm::find_if(componentTypeVars, [&](TypeVariableType *typeVar) {
auto *locator = typeVar->getImpl().getLocator();
auto elt = locator->findLast<LocatorPathElt::KeyPathComponent>();
return elt && elt->getIndex() == i;
});

// If one of the components haven't been resolved, let's check
// whether it has been determined to be a "hole" and if so,
// let's allow component validation to contiunue.
//
// This helps to, for example, diagnose problems with missing
// members used as part of a key path.
if (typeVar != componentTypeVars.end() &&
(*typeVar)->getImpl().canBindToHole()) {
anyComponentsUnresolved = true;
capability = ReadOnly;
continue;
}
}

return SolutionKind::Unsolved;
}

Expand Down
12 changes: 6 additions & 6 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -120,26 +120,26 @@ set(LIT "${LLVM_MAIN_SRC_DIR}/utils/lit/lit.py")
# instead of by the path, which is good for CI. In this mode lit also updates
# the mtime on the failed tests, which makes them run first on the
# consecutive execution, which makes local builds fail faster.
set(SWIFT_TEST_EXTRA_ARGS "--incremental")
set(SWIFT_LIT_ARGS "--incremental" CACHE STRING "Arguments to pass to lit")

if(NOT SWIFT_INCLUDE_TOOLS)
list(APPEND SWIFT_TEST_EXTRA_ARGS
list(APPEND SWIFT_LIT_ARGS
"--path=${SWIFT_NATIVE_LLVM_TOOLS_PATH}"
"--path=${SWIFT_NATIVE_CLANG_TOOLS_PATH}"
"--path=${SWIFT_NATIVE_SWIFT_TOOLS_PATH}")
if(SWIFT_BUILD_STDLIB)
list(APPEND SWIFT_TEST_EXTRA_ARGS
list(APPEND SWIFT_LIT_ARGS
"--param" "test_resource_dir=${SWIFTLIB_DIR}")
endif()
endif()

option(SWIFT_TEST_USE_LEAKS "Run Swift stdlib tests under leaks" FALSE)
if (SWIFT_TEST_USE_LEAKS)
list(APPEND SWIFT_TEST_EXTRA_ARGS "--param" "leaks-all")
list(APPEND SWIFT_LIT_ARGS "--param" "leaks-all")
endif()

if(NOT CMAKE_CFG_INTDIR STREQUAL ".")
list(APPEND SWIFT_TEST_EXTRA_ARGS
list(APPEND SWIFT_LIT_ARGS
"--param" "build_mode=${CMAKE_CFG_INTDIR}")
endif()

Expand Down Expand Up @@ -332,7 +332,7 @@ _Block_release(void) { }\n")
COMMENT "Uploading stdlib")

foreach(test_mode ${TEST_MODES})
set(LIT_ARGS "${SWIFT_TEST_EXTRA_ARGS} ${LLVM_LIT_ARGS}")
set(LIT_ARGS "${SWIFT_LIT_ARGS} ${LLVM_LIT_ARGS}")
separate_arguments(LIT_ARGS)

if(NOT SWIFT_BUILD_STDLIB AND NOT SWIFT_PATH_TO_EXTERNAL_STDLIB_BUILD)
Expand Down
31 changes: 31 additions & 0 deletions test/Constraints/rdar62201037.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// RUN: %target-swift-frontend %s -verify -emit-sil -o /dev/null

struct R<T> {
var str: String?
}

func map<A, B>(e: (A) -> B) -> () -> R<B> {
fatalError()
}
func map<A, B>(_ : (A) -> B) -> (A?) -> B? {
fatalError()
}

infix operator |>
func |> <A, B> (g: A, h: (A) -> B) -> B { h(g) }

infix operator ^^^
func ^^^ <A, B, C>(j: ((B) -> C) -> A, k: String) {}

extension WritableKeyPath {
static func ^^^ (l: WritableKeyPath, m: Value) -> (Root) -> Root {
fatalError()
}
}

func foo<T>(_ s: String, _ rt: R<T>?) -> String? {
return rt.flatMap { _ in
rt |> map(\.str ^^^ s)
}
.flatMap(\.str)
}
29 changes: 29 additions & 0 deletions test/expr/unary/keypath/keypath.swift
Original file line number Diff line number Diff line change
Expand Up @@ -895,11 +895,40 @@ struct SR_12290 {

func testKeyPathHole() {
_ = \.x // expected-error {{cannot infer key path type from context; consider explicitly specifying a root type}} {{8-8=<#Root#>}}
_ = \.x.y // expected-error {{cannot infer key path type from context; consider explicitly specifying a root type}} {{8-8=<#Root#>}}

let _ : AnyKeyPath = \.x
// expected-error@-1 {{'AnyKeyPath' does not provide enough context for root type to be inferred; consider explicitly specifying a root type}} {{25-25=<#Root#>}}
let _ : AnyKeyPath = \.x.y
// expected-error@-1 {{'AnyKeyPath' does not provide enough context for root type to be inferred; consider explicitly specifying a root type}} {{25-25=<#Root#>}}

func f(_ i: Int) {}
f(\.x) // expected-error {{cannot infer key path type from context; consider explicitly specifying a root type}} {{6-6=<#Root#>}}
f(\.x.y) // expected-error {{cannot infer key path type from context; consider explicitly specifying a root type}} {{6-6=<#Root#>}}

// FIXME(SR-12827): Instead of "generic parameter 'T' could not be inferred",
// we should offer the same diagnostic as above.
func provideValueButNotRoot<T>(_ fn: (T) -> String) {} // expected-note 2{{in call to function 'provideValueButNotRoot'}}
provideValueButNotRoot(\.x) // expected-error {{generic parameter 'T' could not be inferred}}
provideValueButNotRoot(\.x.y) // expected-error {{generic parameter 'T' could not be inferred}}
provideValueButNotRoot(\String.foo) // expected-error {{value of type 'String' has no member 'foo'}}

func provideKPValueButNotRoot<T>(_ kp: KeyPath<T, String>) {} // expected-note 3{{in call to function 'provideKPValueButNotRoot'}}
provideKPValueButNotRoot(\.x) // expected-error {{generic parameter 'T' could not be inferred}}
provideKPValueButNotRoot(\.x.y) // expected-error {{generic parameter 'T' could not be inferred}}
provideKPValueButNotRoot(\String.foo)
// expected-error@-1 {{value of type 'String' has no member 'foo'}}
// expected-error@-2 {{generic parameter 'T' could not be inferred}}
}

func testMissingMember() {
let _: KeyPath<String, String> = \.foo // expected-error {{value of type 'String' has no member 'foo'}}
let _: KeyPath<String, String> = \.foo.bar // expected-error {{value of type 'String' has no member 'foo'}}

let _: PartialKeyPath<String> = \.foo // expected-error {{value of type 'String' has no member 'foo'}}
let _: PartialKeyPath<String> = \.foo.bar // expected-error {{value of type 'String' has no member 'foo'}}

_ = \String.x.y // expected-error {{value of type 'String' has no member 'x'}}
}

func testSyntaxErrors() { // expected-note{{}}
Expand Down
5 changes: 3 additions & 2 deletions validation-test/Sanitizers/fuzzer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,10 @@ import MSVCRT
#endif

@_cdecl("LLVMFuzzerTestOneInput")
public func test(_ start: UnsafeRawPointer, _ count: Int) -> CInt {
public func testHexDigits(_ start: UnsafeRawPointer, _ count: Int) -> CInt {
let bytes = UnsafeRawBufferPointer(start: start, count: count)
if bytes.starts(with: "ABC".utf8) {
let string = String(decoding: bytes, as: Unicode.UTF8.self)
if let number = Int(string, radix: 16), (0x10...0xFF).contains(number) {
print("Crash!")
fflush(stdout)
exit(EXIT_FAILURE)
Expand Down