Skip to content

[CSFix] Fix a null pointer dereference in getStructuralTypeContext #79592

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 1 commit into from
Feb 25, 2025
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
28 changes: 21 additions & 7 deletions include/swift/Sema/ConstraintSystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -1797,19 +1797,33 @@ class Solution {
/// "resolved" concrete type.
Type getResolvedType(ASTNode node) const;

Type getContextualType(ASTNode anchor) const {
std::optional<ContextualTypeInfo>
getContextualTypeInfo(ASTNode anchor) const {
for (const auto &entry : contextualTypes) {
if (entry.first == anchor) {
// The contextual information record could contain the purpose
// without a type i.e. when the context is an optional-some or
// an invalid pattern binding.
if (auto contextualTy = entry.second.getType())
if (entry.first == anchor)
return entry.second;
}
return std::nullopt;
}

Type getContextualType(ASTNode anchor) const {
if (auto info = getContextualTypeInfo(anchor)) {
// The contextual information record could contain the purpose
// without a type i.e. when the context is an optional-some or
// an invalid pattern binding.
if (auto contextualTy = info->getType())
return simplifyType(contextualTy);
}
}
return Type();
}

ContextualTypePurpose getContextualTypePurpose(ASTNode anchor) const {
if (auto info = getContextualTypeInfo(anchor)) {
return info->purpose;
}
return CTP_Unused;
}

/// Retrieve the generic environment for the opened element of a given pack
/// expansion, or \c nullptr if no environment was recorded.
GenericEnvironment *
Expand Down
17 changes: 10 additions & 7 deletions lib/Sema/CSFix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -592,12 +592,16 @@ getStructuralTypeContext(const Solution &solution, ConstraintLocator *locator) {
assert(locator->isLastElement<LocatorPathElt::ContextualType>() ||
locator->isLastElement<LocatorPathElt::FunctionArgument>());

auto &cs = solution.getConstraintSystem();
auto anchor = locator->getAnchor();
auto contextualType = cs.getContextualType(anchor, /*forConstraint=*/false);
auto exprType = cs.getType(anchor);
return std::make_tuple(contextualTypeElt->getPurpose(), exprType,
contextualType);
auto contextualInfo = solution.getContextualTypeInfo(anchor);
// For some patterns the type could be empty and the entry is
// there to indicate the purpose only.
if (!contextualInfo || !contextualInfo->getType())
return std::nullopt;

auto exprType = solution.getType(anchor);
return std::make_tuple(contextualInfo->purpose, exprType,
contextualInfo->getType());
} else if (auto argApplyInfo = solution.getFunctionArgApplyInfo(locator)) {
Type fromType = argApplyInfo->getArgType();
Type toType = argApplyInfo->getParamType();
Expand All @@ -607,9 +611,8 @@ getStructuralTypeContext(const Solution &solution, ConstraintLocator *locator) {
auto fromFnType = fromType->getAs<FunctionType>();
auto toFnType = toType->getAs<FunctionType>();
if (fromFnType && toFnType) {
auto &cs = solution.getConstraintSystem();
return std::make_tuple(
cs.getContextualTypePurpose(locator->getAnchor()),
solution.getContextualTypePurpose(locator->getAnchor()),
fromFnType->getResult(), toFnType->getResult());
}
}
Expand Down
15 changes: 15 additions & 0 deletions test/Constraints/patterns.swift
Original file line number Diff line number Diff line change
Expand Up @@ -805,3 +805,18 @@ func testMatchingNonErrorConformingTypeInClosure(_ x: any Error) {
}
}
}

// rdar://131819800 - crash in `transformWithPosition` while trying to emit diagnostics for `AllowFunctionTypeMismatch` fix
do {
enum E {
case test(kind: Int, defaultsToEmpty: Bool = false)
}

func test(e: E) {
if case .test(kind: _, // expected-error {{tuple pattern has the wrong length for tuple type '(Int, Bool)'}}
name: let name?,
defaultsToEmpty: _,
deprecateName: let deprecatedName?) = e {
}
}
}