Skip to content

Commit caa91db

Browse files
authored
Merge pull request #39442 from hamishknight/iuo-a-bug-fix
2 parents 48c5c83 + d74f515 commit caa91db

File tree

3 files changed

+73
-54
lines changed

3 files changed

+73
-54
lines changed

include/swift/Sema/ConstraintSystem.h

Lines changed: 2 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -4527,60 +4527,8 @@ class ConstraintSystem {
45274527
// Build a disjunction that attempts both T? and T for a particular
45284528
// type binding. The choice of T? is preferred, and we will not
45294529
// attempt T if we can type check with T?
4530-
void
4531-
buildDisjunctionForOptionalVsUnderlying(Type boundTy, Type type,
4532-
ConstraintLocator *locator) {
4533-
// NOTE: If we use other locator kinds for these disjunctions, we
4534-
// need to account for it in solution scores for forced-unwraps.
4535-
assert(locator->getPath().back().getKind() ==
4536-
ConstraintLocator::ImplicitlyUnwrappedDisjunctionChoice ||
4537-
locator->getPath().back().getKind() ==
4538-
ConstraintLocator::DynamicLookupResult);
4539-
4540-
// Create the constraint to bind to the optional type and make it
4541-
// the favored choice.
4542-
auto *bindToOptional =
4543-
Constraint::create(*this, ConstraintKind::Bind, boundTy, type, locator);
4544-
bindToOptional->setFavored();
4545-
4546-
Type underlyingType;
4547-
if (auto *fnTy = type->getAs<AnyFunctionType>())
4548-
underlyingType = replaceFinalResultTypeWithUnderlying(fnTy);
4549-
else if (auto *typeVar =
4550-
type->getWithoutSpecifierType()->getAs<TypeVariableType>()) {
4551-
auto *locator = typeVar->getImpl().getLocator();
4552-
4553-
// If `type` hasn't been resolved yet, we need to allocate a type
4554-
// variable to represent an object type of a future optional, and
4555-
// add a constraint beetween `type` and `underlyingType` to model it.
4556-
underlyingType = createTypeVariable(
4557-
getConstraintLocator(locator, LocatorPathElt::GenericArgument(0)),
4558-
TVO_PrefersSubtypeBinding | TVO_CanBindToLValue |
4559-
TVO_CanBindToNoEscape);
4560-
4561-
// Using a `typeVar` here because l-value is going to be applied
4562-
// to the underlying type below.
4563-
addConstraint(ConstraintKind::OptionalObject, typeVar, underlyingType,
4564-
locator);
4565-
} else {
4566-
underlyingType = type->getWithoutSpecifierType()->getOptionalObjectType();
4567-
}
4568-
4569-
assert(underlyingType);
4570-
4571-
if (type->is<LValueType>())
4572-
underlyingType = LValueType::get(underlyingType);
4573-
assert(!type->is<InOutType>());
4574-
4575-
auto *bindToUnderlying = Constraint::create(
4576-
*this, ConstraintKind::Bind, boundTy, underlyingType, locator);
4577-
4578-
llvm::SmallVector<Constraint *, 2> choices = {bindToOptional,
4579-
bindToUnderlying};
4580-
4581-
// Create the disjunction
4582-
addDisjunctionConstraint(choices, locator, RememberChoice);
4583-
}
4530+
void buildDisjunctionForOptionalVsUnderlying(Type boundTy, Type ty,
4531+
ConstraintLocator *locator);
45844532

45854533
// Build a disjunction for types declared IUO.
45864534
void

lib/Sema/ConstraintSystem.cpp

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2597,6 +2597,68 @@ bool ConstraintSystem::isAsynchronousContext(DeclContext *dc) {
25972597
return false;
25982598
}
25992599

2600+
void ConstraintSystem::buildDisjunctionForOptionalVsUnderlying(
2601+
Type boundTy, Type ty, ConstraintLocator *locator) {
2602+
// NOTE: If we use other locator kinds for these disjunctions, we
2603+
// need to account for it in solution scores for forced-unwraps.
2604+
assert(locator->getPath().back().getKind() ==
2605+
ConstraintLocator::ImplicitlyUnwrappedDisjunctionChoice ||
2606+
locator->getPath().back().getKind() ==
2607+
ConstraintLocator::DynamicLookupResult);
2608+
assert(!ty->is<InOutType>());
2609+
auto rvalueTy = ty->getWithoutSpecifierType();
2610+
2611+
// If the type to bind is a placeholder, we can propagate it, as we don't know
2612+
// whether it can be optional or non-optional, and we would have already
2613+
// recorded a fix for it.
2614+
if (rvalueTy->isPlaceholder()) {
2615+
addConstraint(ConstraintKind::Bind, boundTy, ty, locator);
2616+
return;
2617+
}
2618+
2619+
// Create the constraint to bind to the optional type and make it the favored
2620+
// choice.
2621+
auto *bindToOptional =
2622+
Constraint::create(*this, ConstraintKind::Bind, boundTy, ty, locator);
2623+
bindToOptional->setFavored();
2624+
2625+
Type underlyingType;
2626+
if (auto *fnTy = ty->getAs<AnyFunctionType>())
2627+
underlyingType = replaceFinalResultTypeWithUnderlying(fnTy);
2628+
else if (auto *typeVar = rvalueTy->getAs<TypeVariableType>()) {
2629+
auto *locator = typeVar->getImpl().getLocator();
2630+
2631+
// If `ty` hasn't been resolved yet, we need to allocate a type variable to
2632+
// represent an object type of a future optional, and add a constraint
2633+
// between `ty` and `underlyingType` to model it.
2634+
underlyingType = createTypeVariable(
2635+
getConstraintLocator(locator, LocatorPathElt::GenericArgument(0)),
2636+
TVO_PrefersSubtypeBinding | TVO_CanBindToLValue |
2637+
TVO_CanBindToNoEscape);
2638+
2639+
// Using a `typeVar` here because l-value is going to be applied
2640+
// to the underlying type below.
2641+
addConstraint(ConstraintKind::OptionalObject, typeVar, underlyingType,
2642+
locator);
2643+
} else {
2644+
underlyingType = rvalueTy->getOptionalObjectType();
2645+
}
2646+
2647+
assert(underlyingType);
2648+
2649+
if (ty->is<LValueType>())
2650+
underlyingType = LValueType::get(underlyingType);
2651+
2652+
auto *bindToUnderlying = Constraint::create(*this, ConstraintKind::Bind,
2653+
boundTy, underlyingType, locator);
2654+
2655+
llvm::SmallVector<Constraint *, 2> choices = {bindToOptional,
2656+
bindToUnderlying};
2657+
2658+
// Create the disjunction
2659+
addDisjunctionConstraint(choices, locator, RememberChoice);
2660+
}
2661+
26002662
void ConstraintSystem::bindOverloadType(
26012663
const SelectedOverload &overload, Type boundType,
26022664
ConstraintLocator *locator, DeclContext *useDC,

test/Constraints/iuo.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,3 +238,12 @@ struct CurriedIUO {
238238
let _: Int = CurriedIUO.silly(self)()
239239
}
240240
}
241+
242+
// SR-15219 (rdar://83352038): Make sure we don't crash if an IUO param becomes
243+
// a placeholder.
244+
func rdar83352038() {
245+
func foo(_: UnsafeRawPointer) -> Undefined {} // expected-error {{cannot find type 'Undefined' in scope}}
246+
let _ = { (cnode: AlsoUndefined!) -> UnsafeMutableRawPointer in // expected-error {{cannot find type 'AlsoUndefined' in scope}}
247+
return foo(cnode)
248+
}
249+
}

0 commit comments

Comments
 (0)