Skip to content

Commit b39302a

Browse files
authored
Merge pull request #60203 from xedin/rdar-96997534
[CSGen] Allow `_` pattern to be a hole
2 parents d91d5ae + f5456bd commit b39302a

13 files changed

+161
-37
lines changed

include/swift/Sema/CSFix.h

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -298,9 +298,9 @@ enum class FixKind : uint8_t {
298298
/// Ignore `ErrorExpr` or `ErrorType` during pre-check.
299299
IgnoreInvalidASTNode,
300300

301-
/// Ignore a named pattern whose type we couldn't infer. This issue should
302-
/// already have been diagnosed elsewhere.
303-
IgnoreInvalidNamedPattern,
301+
/// Ignore a named or `_` pattern whose type we couldn't infer.
302+
/// This issue should already have been diagnosed elsewhere.
303+
IgnoreUnresolvedPatternVar,
304304

305305
/// Resolve type of `nil` by providing a contextual type.
306306
SpecifyContextualTypeForNil,
@@ -2287,6 +2287,10 @@ class UseRawValue final : public ConstraintFix {
22872287

22882288
bool diagnose(const Solution &solution, bool asNote = false) const override;
22892289

2290+
bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override {
2291+
return diagnose(*commonFixes.front().first);
2292+
}
2293+
22902294
static UseRawValue *create(ConstraintSystem &cs, Type rawReprType,
22912295
Type expectedType, ConstraintLocator *locator);
22922296

@@ -2746,10 +2750,10 @@ class IgnoreInvalidASTNode final : public ConstraintFix {
27462750
}
27472751
};
27482752

2749-
class IgnoreInvalidNamedPattern final : public ConstraintFix {
2750-
IgnoreInvalidNamedPattern(ConstraintSystem &cs, NamedPattern *pattern,
2751-
ConstraintLocator *locator)
2752-
: ConstraintFix(cs, FixKind::IgnoreInvalidNamedPattern, locator) {}
2753+
class IgnoreUnresolvedPatternVar final : public ConstraintFix {
2754+
IgnoreUnresolvedPatternVar(ConstraintSystem &cs, Pattern *pattern,
2755+
ConstraintLocator *locator)
2756+
: ConstraintFix(cs, FixKind::IgnoreUnresolvedPatternVar, locator) {}
27532757

27542758
public:
27552759
std::string getName() const override {
@@ -2762,12 +2766,11 @@ class IgnoreInvalidNamedPattern final : public ConstraintFix {
27622766
return diagnose(*commonFixes.front().first);
27632767
}
27642768

2765-
static IgnoreInvalidNamedPattern *create(ConstraintSystem &cs,
2766-
NamedPattern *pattern,
2767-
ConstraintLocator *locator);
2769+
static IgnoreUnresolvedPatternVar *
2770+
create(ConstraintSystem &cs, Pattern *pattern, ConstraintLocator *locator);
27682771

27692772
static bool classof(ConstraintFix *fix) {
2770-
return fix->getKind() == FixKind::IgnoreInvalidNamedPattern;
2773+
return fix->getKind() == FixKind::IgnoreUnresolvedPatternVar;
27712774
}
27722775
};
27732776

include/swift/Sema/ConstraintLocator.h

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1076,6 +1076,39 @@ class LocatorPathElt::PatternBindingElement final
10761076
}
10771077
};
10781078

1079+
class LocatorPathElt::PatternDecl : public StoredIntegerElement<1> {
1080+
public:
1081+
PatternDecl(ConstraintLocator::PathElementKind kind)
1082+
: StoredIntegerElement(kind, /*placeholder=*/0) {
1083+
assert(classof(this) && "classof needs updating");
1084+
}
1085+
1086+
static bool classof(const LocatorPathElt *elt) {
1087+
return elt->getKind() == ConstraintLocator::NamedPatternDecl ||
1088+
elt->getKind() == ConstraintLocator::AnyPatternDecl;
1089+
}
1090+
};
1091+
1092+
class LocatorPathElt::NamedPatternDecl final
1093+
: public LocatorPathElt::PatternDecl {
1094+
public:
1095+
NamedPatternDecl() : PatternDecl(ConstraintLocator::NamedPatternDecl) {}
1096+
1097+
static bool classof(const LocatorPathElt *elt) {
1098+
return elt->getKind() == ConstraintLocator::NamedPatternDecl;
1099+
}
1100+
};
1101+
1102+
class LocatorPathElt::AnyPatternDecl final
1103+
: public LocatorPathElt::PatternDecl {
1104+
public:
1105+
AnyPatternDecl() : PatternDecl(ConstraintLocator::AnyPatternDecl) {}
1106+
1107+
static bool classof(const LocatorPathElt *elt) {
1108+
return elt->getKind() == ConstraintLocator::AnyPatternDecl;
1109+
}
1110+
};
1111+
10791112
namespace details {
10801113
template <typename CustomPathElement>
10811114
class PathElement {

include/swift/Sema/ConstraintLocatorPathElts.def

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -239,8 +239,12 @@ CUSTOM_LOCATOR_PATH_ELT(SyntacticElement)
239239
/// The element of the pattern binding declaration.
240240
CUSTOM_LOCATOR_PATH_ELT(PatternBindingElement)
241241

242-
/// The variable declared by a named pattern.
243-
SIMPLE_LOCATOR_PATH_ELT(NamedPatternDecl)
242+
/// A declaration introduced by a pattern: name (i.e. `x`) or `_`
243+
ABSTRACT_LOCATOR_PATH_ELT(PatternDecl)
244+
/// The variable declared by a named pattern.
245+
CUSTOM_LOCATOR_PATH_ELT(NamedPatternDecl)
246+
/// The anonymous variable declared by a `_` pattern.
247+
CUSTOM_LOCATOR_PATH_ELT(AnyPatternDecl)
244248

245249
#undef LOCATOR_PATH_ELT
246250
#undef CUSTOM_LOCATOR_PATH_ELT

lib/Sema/BuilderTransform.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -758,7 +758,7 @@ class BuilderClosureVisitor
758758
// If needed, generate constraints for everything in the case statement.
759759
if (cs) {
760760
auto locator = cs->getConstraintLocator(
761-
subjectExpr, LocatorPathElt::ContextualType(CTP_Initialization));
761+
subjectExpr, LocatorPathElt::ContextualType(CTP_CaseStmt));
762762
Type subjectType = cs->getType(subjectExpr);
763763

764764
if (cs->generateConstraints(caseStmt, dc, subjectType, locator)) {

lib/Sema/CSBindings.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ bool BindingSet::isDelayed() const {
115115
// allows us to produce more specific errors because the type variable in
116116
// the expression that introduced the placeholder might be diagnosable using
117117
// fixForHole.
118-
if (locator->isLastElement<LocatorPathElt::NamedPatternDecl>()) {
118+
if (locator->isLastElement<LocatorPathElt::PatternDecl>()) {
119119
return true;
120120
}
121121

@@ -2061,16 +2061,16 @@ TypeVariableBinding::fixForHole(ConstraintSystem &cs) const {
20612061
return std::make_pair(fix, /*impact=*/(unsigned)10);
20622062
}
20632063

2064-
if (auto pattern = getAsPattern<NamedPattern>(dstLocator->getAnchor())) {
2064+
if (auto pattern = getAsPattern(dstLocator->getAnchor())) {
20652065
if (dstLocator->getPath().size() == 1 &&
2066-
dstLocator->isLastElement<LocatorPathElt::NamedPatternDecl>()) {
2066+
dstLocator->isLastElement<LocatorPathElt::PatternDecl>()) {
20672067
// Not being able to infer the type of a variable in a pattern binding
20682068
// decl is more dramatic than anything that could happen inside the
20692069
// expression because we want to preferrably point the diagnostic to a
20702070
// part of the expression that caused us to be unable to infer the
20712071
// variable's type.
20722072
ConstraintFix *fix =
2073-
IgnoreInvalidNamedPattern::create(cs, pattern, dstLocator);
2073+
IgnoreUnresolvedPatternVar::create(cs, pattern, dstLocator);
20742074
return std::make_pair(fix, /*impact=*/(unsigned)100);
20752075
}
20762076
}

lib/Sema/CSFix.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2004,18 +2004,18 @@ IgnoreResultBuilderWithReturnStmts::create(ConstraintSystem &cs, Type builderTy,
20042004
IgnoreResultBuilderWithReturnStmts(cs, builderTy, locator);
20052005
}
20062006

2007-
bool IgnoreInvalidNamedPattern::diagnose(const Solution &solution,
2008-
bool asNote) const {
2007+
bool IgnoreUnresolvedPatternVar::diagnose(const Solution &solution,
2008+
bool asNote) const {
20092009
// Not being able to infer the type of a pattern should already have been
20102010
// diagnosed on the pattern's initializer or as a structural issue of the AST.
20112011
return true;
20122012
}
20132013

2014-
IgnoreInvalidNamedPattern *
2015-
IgnoreInvalidNamedPattern::create(ConstraintSystem &cs, NamedPattern *pattern,
2016-
ConstraintLocator *locator) {
2014+
IgnoreUnresolvedPatternVar *
2015+
IgnoreUnresolvedPatternVar::create(ConstraintSystem &cs, Pattern *pattern,
2016+
ConstraintLocator *locator) {
20172017
return new (cs.getAllocator())
2018-
IgnoreInvalidNamedPattern(cs, pattern, locator);
2018+
IgnoreUnresolvedPatternVar(cs, pattern, locator);
20192019
}
20202020

20212021
bool SpecifyBaseTypeForOptionalUnresolvedMember::diagnose(

lib/Sema/CSGen.cpp

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2265,9 +2265,11 @@ namespace {
22652265
->getUnderlyingType();
22662266
}
22672267

2268-
auto underlyingType =
2269-
getTypeForPattern(paren->getSubPattern(), locator,
2270-
externalPatternType, bindPatternVarsOneWay);
2268+
auto *subPattern = paren->getSubPattern();
2269+
auto underlyingType = getTypeForPattern(
2270+
subPattern,
2271+
locator.withPathElement(LocatorPathElt::PatternMatch(subPattern)),
2272+
externalPatternType, bindPatternVarsOneWay);
22712273

22722274
if (!underlyingType)
22732275
return Type();
@@ -2286,11 +2288,34 @@ namespace {
22862288
return setType(type);
22872289
}
22882290
case PatternKind::Any: {
2289-
return setType(
2290-
externalPatternType
2291-
? externalPatternType
2292-
: CS.createTypeVariable(CS.getConstraintLocator(locator),
2293-
TVO_CanBindToNoEscape));
2291+
Type type;
2292+
2293+
// If this is a situation like `[let] _ = <expr>`, return
2294+
// initializer expression.
2295+
auto getInitializerExpr = [&locator]() -> Expr * {
2296+
auto last = locator.last();
2297+
if (!last)
2298+
return nullptr;
2299+
2300+
auto contextualTy = last->getAs<LocatorPathElt::ContextualType>();
2301+
return (contextualTy && contextualTy->isFor(CTP_Initialization))
2302+
? locator.trySimplifyToExpr()
2303+
: nullptr;
2304+
};
2305+
2306+
// Always prefer a contextual type when it's available.
2307+
if (externalPatternType) {
2308+
type = externalPatternType;
2309+
} else if (auto *initializer = getInitializerExpr()) {
2310+
// For initialization always assume a type of initializer.
2311+
type = CS.getType(initializer)->getRValueType();
2312+
} else {
2313+
type = CS.createTypeVariable(
2314+
CS.getConstraintLocator(pattern,
2315+
ConstraintLocator::AnyPatternDecl),
2316+
TVO_CanBindToNoEscape | TVO_CanBindToHole);
2317+
}
2318+
return setType(type);
22942319
}
22952320

22962321
case PatternKind::Named: {
@@ -2671,7 +2696,9 @@ namespace {
26712696
// and we're matching the type of that subpattern to the parameter
26722697
// types.
26732698
Type subPatternType = getTypeForPattern(
2674-
subPattern, locator, Type(), bindPatternVarsOneWay);
2699+
subPattern,
2700+
locator.withPathElement(LocatorPathElt::PatternMatch(subPattern)),
2701+
Type(), bindPatternVarsOneWay);
26752702

26762703
if (!subPatternType)
26772704
return Type();

lib/Sema/CSSimplify.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7328,7 +7328,11 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyConformsToConstraint(
73287328
TypeChecker::conformsToProtocol(rawValue, protocol,
73297329
DC->getParentModule())) {
73307330
auto *fix = UseRawValue::create(*this, type, protocolTy, loc);
7331-
return recordFix(fix) ? SolutionKind::Error : SolutionKind::Solved;
7331+
// Since this is a conformance requirement failure (where the
7332+
// source is most likely an argument), let's increase its impact
7333+
// to disambiguate vs. conversion failure of the same kind.
7334+
return recordFix(fix, /*impact=*/2) ? SolutionKind::Error
7335+
: SolutionKind::Solved;
73327336
}
73337337
}
73347338

@@ -12938,7 +12942,7 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint(
1293812942
case FixKind::IgnoreInvalidASTNode: {
1293912943
return recordFix(fix, 10) ? SolutionKind::Error : SolutionKind::Solved;
1294012944
}
12941-
case FixKind::IgnoreInvalidNamedPattern: {
12945+
case FixKind::IgnoreUnresolvedPatternVar: {
1294212946
return recordFix(fix, 100) ? SolutionKind::Error : SolutionKind::Solved;
1294312947
}
1294412948

lib/Sema/ConstraintLocator.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ unsigned LocatorPathElt::getNewSummaryFlags() const {
9898
case ConstraintLocator::PackElement:
9999
case ConstraintLocator::PatternBindingElement:
100100
case ConstraintLocator::NamedPatternDecl:
101+
case ConstraintLocator::AnyPatternDecl:
101102
return 0;
102103

103104
case ConstraintLocator::FunctionArgument:
@@ -447,6 +448,11 @@ void LocatorPathElt::dump(raw_ostream &out) const {
447448
out << "named pattern decl";
448449
break;
449450
}
451+
452+
case ConstraintLocator::AnyPatternDecl: {
453+
out << "'_' pattern decl";
454+
break;
455+
}
450456
}
451457
}
452458

lib/Sema/ConstraintSystem.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5277,6 +5277,15 @@ void constraints::simplifyLocator(ASTNode &anchor,
52775277
break;
52785278
}
52795279

5280+
case ConstraintLocator::AnyPatternDecl: {
5281+
// This element is just a marker for `_` pattern since it doesn't
5282+
// have a declaration. We need to make sure that it only appaears
5283+
// when anchored on `AnyPattern`.
5284+
assert(getAsPattern<AnyPattern>(anchor));
5285+
path = path.slice(1);
5286+
break;
5287+
}
5288+
52805289
case ConstraintLocator::ImplicitConversion:
52815290
break;
52825291

test/Constraints/patterns.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -486,6 +486,7 @@ func rdar63510989() {
486486
}
487487

488488
func test(e: E) {
489+
if case .single(_) = e {} // Ok
489490
if case .single(_ as Value) = e {} // Ok
490491
if case .single(let v as Value) = e {} // Ok
491492
// expected-warning@-1 {{immutable value 'v' was never used; consider replacing with '_' or removing it}}

test/Constraints/result_builder_diags.swift

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -855,3 +855,40 @@ func test_invalid_result_is_diagnosed() {
855855
S<Int>()
856856
}
857857
}
858+
859+
func test_associated_values_dont_block_solver_when_unresolved() {
860+
@resultBuilder
861+
struct Builder {
862+
static func buildBlock<T>(_ t: T) -> T { t }
863+
static func buildEither<T>(first: T) -> T { first }
864+
static func buildEither<T>(second: T) -> T { second }
865+
}
866+
867+
struct Value {
868+
enum Kind {
869+
case a(String)
870+
case b
871+
}
872+
873+
var kind: Kind
874+
}
875+
876+
struct Container {
877+
var prop: Value? = nil
878+
}
879+
880+
struct TestWithAny {
881+
var container: Container
882+
883+
@Builder var body: String {
884+
let v = container.prop.kind // expected-error {{value of optional type 'Value?' must be unwrapped to refer to member 'kind' of wrapped base type 'Value'}}
885+
// expected-note@-1 {{chain the optional using '?' to access member 'kind' only for non-'nil' base values}}
886+
// expected-note@-2 {{force-unwrap using '!' to abort execution if the optional value contains 'nil'}}
887+
888+
switch v.kind { // expected-error {{value of type 'Value.Kind' has no member 'kind'}}
889+
case .a(_): "a"
890+
case .b: "b"
891+
}
892+
}
893+
}
894+
}

test/Sema/enum_raw_representable.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -146,10 +146,10 @@ rdar32431165_2(42, E_32431165.bar)
146146
// or constructing raw representable type from second, both ways are valid.
147147
do {
148148
E_32431165.bar == "bar"
149-
// expected-error@-1 {{binary operator '==' cannot be applied to operands of type 'E_32431165' and 'String'}} expected-note@-1 {{partially matching parameter lists: (String, String)}}
149+
// expected-error@-1 {{cannot convert value of type 'E_32431165' to expected argument type 'String'}} {{17-17=.rawValue}}
150150

151151
"bar" == E_32431165.bar
152-
// expected-error@-1 {{binary operator '==' cannot be applied to operands of type 'String' and 'E_32431165'}} expected-note@-1 {{partially matching parameter lists: (String, String)}}
152+
// expected-error@-1 {{cannot convert value of type 'E_32431165' to expected argument type 'String'}} {{26-26=.rawValue}}
153153
}
154154

155155
func rdar32431165_overloaded() -> Int { 42 } // expected-note {{'rdar32431165_overloaded()' produces 'Int', not the expected contextual result type 'E_32431165'}}

0 commit comments

Comments
 (0)