Skip to content

Commit 7d96de5

Browse files
authored
Merge pull request swiftlang#24601 from slavapestov/remove-old-inout-expr-check
Remove MiscDiagnostics diagnosis of invalid InOutExprs
2 parents 431343b + b103fed commit 7d96de5

File tree

9 files changed

+59
-60
lines changed

9 files changed

+59
-60
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2790,8 +2790,6 @@ ERROR(object_literal_broken_proto,none,
27902790
ERROR(discard_expr_outside_of_assignment,none,
27912791
"'_' can only appear in a pattern or on the left side of an assignment",
27922792
())
2793-
ERROR(inout_expr_outside_of_call,none,
2794-
"'&' can only appear immediately in a call argument list", ())
27952793
ERROR(collection_literal_heterogeneous,none,
27962794
"heterogeneous collection literal could only be inferred to %0; add"
27972795
" explicit type annotation if this is intentional", (Type))

lib/Sema/CSApply.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7848,6 +7848,7 @@ Expr *TypeChecker::callWitness(Expr *base, DeclContext *dc,
78487848
auto openedFuncType = openedType->castTo<FunctionType>();
78497849
::matchCallArguments(
78507850
cs, args, openedFuncType->getParams(),
7851+
ConstraintKind::ArgumentConversion,
78517852
cs.getConstraintLocator(call, ConstraintLocator::ApplyArgument));
78527853

78537854
// Solve the system.

lib/Sema/CSDiagnostics.cpp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2755,9 +2755,17 @@ bool InvalidMethodRefInKeyPath::diagnoseAsError() {
27552755
return true;
27562756
}
27572757

2758+
SourceLoc InvalidUseOfAddressOf::getLoc() const {
2759+
auto *anchor = getAnchor();
2760+
2761+
if (auto *assign = dyn_cast<AssignExpr>(anchor))
2762+
anchor = assign->getSrc();
2763+
2764+
return anchor->getLoc();
2765+
}
2766+
27582767
bool InvalidUseOfAddressOf::diagnoseAsError() {
2759-
auto *anchor = cast<AssignExpr>(getAnchor());
2760-
emitDiagnostic(anchor->getSrc()->getLoc(), diag::extraneous_address_of);
2768+
emitDiagnostic(getLoc(), diag::extraneous_address_of);
27612769
return true;
27622770
}
27632771

lib/Sema/CSDiagnostics.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1158,6 +1158,10 @@ class InvalidUseOfAddressOf final : public FailureDiagnostic {
11581158
: FailureDiagnostic(root, cs, locator) {}
11591159

11601160
bool diagnoseAsError() override;
1161+
1162+
protected:
1163+
/// Compute location of the failure for diagnostic.
1164+
SourceLoc getLoc() const;
11611165
};
11621166

11631167
/// Diagnose an attempt return something from a function which

lib/Sema/CSGen.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1292,7 +1292,7 @@ namespace {
12921292
AnyFunctionType::decomposeInput(constrParamType, params);
12931293

12941294
::matchCallArguments(
1295-
CS, args, params,
1295+
CS, args, params, ConstraintKind::ArgumentConversion,
12961296
CS.getConstraintLocator(expr, ConstraintLocator::ApplyArgument));
12971297

12981298
Type result = tv;

lib/Sema/CSSimplify.cpp

Lines changed: 39 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -938,7 +938,8 @@ class ArgumentFailureTracker : public MatchCallArgumentListener {
938938
// Match the argument of a call to the parameter.
939939
ConstraintSystem::TypeMatchResult constraints::matchCallArguments(
940940
ConstraintSystem &cs, ArrayRef<AnyFunctionType::Param> args,
941-
ArrayRef<AnyFunctionType::Param> params, ConstraintLocatorBuilder locator) {
941+
ArrayRef<AnyFunctionType::Param> params, ConstraintKind subKind,
942+
ConstraintLocatorBuilder locator) {
942943
// Extract the parameters.
943944
ValueDecl *callee;
944945
bool hasCurriedSelf;
@@ -971,12 +972,6 @@ ConstraintSystem::TypeMatchResult constraints::matchCallArguments(
971972
// assignment operators.
972973
auto *anchor = locator.getAnchor();
973974
assert(anchor && "locator without anchor expression?");
974-
bool isOperator = (isa<PrefixUnaryExpr>(anchor) ||
975-
isa<PostfixUnaryExpr>(anchor) || isa<BinaryExpr>(anchor));
976-
977-
ConstraintKind subKind = (isOperator
978-
? ConstraintKind::OperatorArgumentConversion
979-
: ConstraintKind::ArgumentConversion);
980975

981976
// Check whether argument of the call at given position refers to
982977
// parameter marked as `@autoclosure`. This function is used to
@@ -2218,7 +2213,8 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
22182213
auto desugar2 = type2->getDesugaredType();
22192214

22202215
// If the types are obviously equivalent, we're done.
2221-
if (desugar1->isEqual(desugar2))
2216+
if (desugar1->isEqual(desugar2) &&
2217+
!isa<InOutType>(desugar2))
22222218
return getTypeMatchSuccess();
22232219

22242220
// Local function that should be used to produce the return value whenever
@@ -2527,11 +2523,15 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
25272523
ConstraintLocator::LValueConversion));
25282524

25292525
case TypeKind::InOut:
2530-
// If the RHS is an inout type, the LHS must be an @lvalue type.
2531-
if (kind == ConstraintKind::BindParam ||
2532-
kind >= ConstraintKind::OperatorArgumentConversion)
2526+
if (kind == ConstraintKind::BindParam)
25332527
return getTypeMatchFailure(locator);
25342528

2529+
if (kind == ConstraintKind::OperatorArgumentConversion) {
2530+
conversionsOrFixes.push_back(
2531+
RemoveAddressOf::create(*this, getConstraintLocator(locator)));
2532+
break;
2533+
}
2534+
25352535
return matchTypes(cast<InOutType>(desugar1)->getObjectType(),
25362536
cast<InOutType>(desugar2)->getObjectType(),
25372537
ConstraintKind::Bind, subflags,
@@ -2557,9 +2557,7 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
25572557
auto opaque1 = cast<OpaqueTypeArchetypeType>(desugar1);
25582558
auto opaque2 = cast<OpaqueTypeArchetypeType>(desugar2);
25592559

2560-
assert(!type2->is<LValueType>() && "Unexpected lvalue type!");
2561-
if (!type1->is<LValueType>()
2562-
&& opaque1->getDecl() == opaque2->getDecl()) {
2560+
if (opaque1->getDecl() == opaque2->getDecl()) {
25632561
conversionsOrFixes.push_back(ConversionRestrictionKind::DeepEquality);
25642562
}
25652563
break;
@@ -2573,15 +2571,13 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
25732571
auto rootOpaque1 = dyn_cast<OpaqueTypeArchetypeType>(nested1->getRoot());
25742572
auto rootOpaque2 = dyn_cast<OpaqueTypeArchetypeType>(nested2->getRoot());
25752573
if (rootOpaque1 && rootOpaque2) {
2576-
assert(!type2->is<LValueType>() && "Unexpected lvalue type!");
25772574
auto interfaceTy1 = nested1->getInterfaceType()
25782575
->getCanonicalType(rootOpaque1->getGenericEnvironment()
25792576
->getGenericSignature());
25802577
auto interfaceTy2 = nested2->getInterfaceType()
25812578
->getCanonicalType(rootOpaque2->getGenericEnvironment()
25822579
->getGenericSignature());
2583-
if (!type1->is<LValueType>()
2584-
&& interfaceTy1 == interfaceTy2
2580+
if (interfaceTy1 == interfaceTy2
25852581
&& rootOpaque1->getDecl() == rootOpaque2->getDecl()) {
25862582
conversionsOrFixes.push_back(ConversionRestrictionKind::DeepEquality);
25872583
break;
@@ -2600,7 +2596,7 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
26002596
// T1 is convertible to T2 (by loading the value). Note that we cannot get
26012597
// a value of inout type as an lvalue though.
26022598
if (type1->is<LValueType>() && !type2->is<InOutType>()) {
2603-
return matchTypes(type1->getRValueType(), type2,
2599+
return matchTypes(type1->getWithoutSpecifierType(), type2,
26042600
kind, subflags, locator);
26052601
}
26062602
}
@@ -2657,7 +2653,6 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
26572653
// We can remove this special case when we implement operator hiding.
26582654
if (!type1->is<LValueType>() &&
26592655
kind != ConstraintKind::OperatorArgumentConversion) {
2660-
assert(!type2->is<LValueType>() && "Unexpected lvalue type!");
26612656
conversionsOrFixes.push_back(
26622657
ConversionRestrictionKind::HashableToAnyHashable);
26632658
}
@@ -2720,16 +2715,13 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
27202715
if (!type1->is<LValueType>() && kind >= ConstraintKind::Subtype) {
27212716
// Array -> Array.
27222717
if (isArrayType(desugar1) && isArrayType(desugar2)) {
2723-
assert(!type2->is<LValueType>() && "Unexpected lvalue type!");
27242718
conversionsOrFixes.push_back(ConversionRestrictionKind::ArrayUpcast);
27252719
// Dictionary -> Dictionary.
27262720
} else if (isDictionaryType(desugar1) && isDictionaryType(desugar2)) {
2727-
assert(!type2->is<LValueType>() && "Unexpected lvalue type!");
27282721
conversionsOrFixes.push_back(
27292722
ConversionRestrictionKind::DictionaryUpcast);
27302723
// Set -> Set.
27312724
} else if (isSetType(desugar1) && isSetType(desugar2)) {
2732-
assert(!type2->is<LValueType>() && "Unexpected lvalue type!");
27332725
conversionsOrFixes.push_back(
27342726
ConversionRestrictionKind::SetUpcast);
27352727
}
@@ -5649,9 +5641,26 @@ ConstraintSystem::simplifyApplicableFnConstraint(
56495641

56505642
TypeMatchOptions subflags = getDefaultDecompositionOptions(flags);
56515643

5652-
// If the types are obviously equivalent, we're done.
5653-
if (type1.getPointer() == desugar2)
5654-
return SolutionKind::Solved;
5644+
SmallVector<LocatorPathElt, 2> parts;
5645+
Expr *anchor = locator.getLocatorParts(parts);
5646+
bool isOperator = (isa<PrefixUnaryExpr>(anchor) ||
5647+
isa<PostfixUnaryExpr>(anchor) ||
5648+
isa<BinaryExpr>(anchor));
5649+
5650+
auto hasInOut = [&]() {
5651+
for (auto param : func1->getParams())
5652+
if (param.isInOut())
5653+
return true;
5654+
return false;
5655+
};
5656+
5657+
// If the types are obviously equivalent, we're done. This optimization
5658+
// is not valid for operators though, where an inout parameter does not
5659+
// have an explicit inout argument.
5660+
if (type1.getPointer() == desugar2) {
5661+
if (!isOperator || !hasInOut())
5662+
return SolutionKind::Solved;
5663+
}
56555664

56565665
// Local function to form an unsolved result.
56575666
auto formUnsolved = [&] {
@@ -5684,8 +5693,6 @@ ConstraintSystem::simplifyApplicableFnConstraint(
56845693

56855694
// Strip the 'ApplyFunction' off the locator.
56865695
// FIXME: Perhaps ApplyFunction can go away entirely?
5687-
SmallVector<LocatorPathElt, 2> parts;
5688-
Expr *anchor = locator.getLocatorParts(parts);
56895696
assert(!parts.empty() && "Nonsensical applicable-function locator");
56905697
assert(parts.back().getKind() == ConstraintLocator::ApplyFunction);
56915698
assert(parts.back().getNewSummaryFlags() == 0);
@@ -5714,9 +5721,13 @@ ConstraintSystem::simplifyApplicableFnConstraint(
57145721

57155722
// For a function, bind the output and convert the argument to the input.
57165723
if (auto func2 = dyn_cast<FunctionType>(desugar2)) {
5724+
ConstraintKind subKind = (isOperator
5725+
? ConstraintKind::OperatorArgumentConversion
5726+
: ConstraintKind::ArgumentConversion);
5727+
57175728
// The argument type must be convertible to the input type.
57185729
if (::matchCallArguments(
5719-
*this, func1->getParams(), func2->getParams(),
5730+
*this, func1->getParams(), func2->getParams(), subKind,
57205731
outerLocator.withPathElement(ConstraintLocator::ApplyArgument))
57215732
.isFailure())
57225733
return SolutionKind::Error;

lib/Sema/ConstraintSystem.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3743,6 +3743,7 @@ ConstraintSystem::TypeMatchResult
37433743
matchCallArguments(ConstraintSystem &cs,
37443744
ArrayRef<AnyFunctionType::Param> args,
37453745
ArrayRef<AnyFunctionType::Param> params,
3746+
ConstraintKind subKind,
37463747
ConstraintLocatorBuilder locator);
37473748

37483749
/// Given an expression that is the target of argument labels (for a call,

lib/Sema/MiscDiagnostics.cpp

Lines changed: 2 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,6 @@ static void diagSyntacticUseRestrictions(TypeChecker &TC, const Expr *E,
6868
// Keep track of acceptable DiscardAssignmentExpr's.
6969
SmallPtrSet<DiscardAssignmentExpr*, 2> CorrectDiscardAssignmentExprs;
7070

71-
/// Keep track of InOutExprs
72-
SmallPtrSet<InOutExpr*, 2> AcceptableInOutExprs;
73-
7471
/// Keep track of the arguments to CallExprs.
7572
SmallPtrSet<Expr *, 2> CallArgs;
7673

@@ -127,15 +124,9 @@ static void diagSyntacticUseRestrictions(TypeChecker &TC, const Expr *E,
127124
if (isa<TypeExpr>(Base))
128125
checkUseOfMetaTypeName(Base);
129126

130-
if (auto *SE = dyn_cast<SubscriptExpr>(E)) {
127+
if (auto *SE = dyn_cast<SubscriptExpr>(E))
131128
CallArgs.insert(SE->getIndex());
132129

133-
// Implicit InOutExpr's are allowed in the base of a subscript expr.
134-
if (auto *IOE = dyn_cast<InOutExpr>(SE->getBase()))
135-
if (IOE->isImplicit())
136-
AcceptableInOutExprs.insert(IOE);
137-
}
138-
139130
if (auto *KPE = dyn_cast<KeyPathExpr>(E)) {
140131
for (auto Comp : KPE->getComponents()) {
141132
if (auto *Arg = Comp.getIndexExpr())
@@ -197,11 +188,6 @@ static void diagSyntacticUseRestrictions(TypeChecker &TC, const Expr *E,
197188
}
198189

199190
visitArguments(Call, [&](unsigned argIndex, Expr *arg) {
200-
// InOutExpr's are allowed in argument lists directly.
201-
if (auto *IOE = dyn_cast<InOutExpr>(arg)) {
202-
if (isa<CallExpr>(Call))
203-
AcceptableInOutExprs.insert(IOE);
204-
}
205191
// InOutExprs can be wrapped in some implicit casts.
206192
Expr *unwrapped = arg;
207193
if (auto *IIO = dyn_cast<InjectIntoOptionalExpr>(arg))
@@ -212,10 +198,8 @@ static void diagSyntacticUseRestrictions(TypeChecker &TC, const Expr *E,
212198
isa<ErasureExpr>(unwrapped)) {
213199
auto operand =
214200
cast<ImplicitConversionExpr>(unwrapped)->getSubExpr();
215-
if (auto *IOE = dyn_cast<InOutExpr>(operand)) {
216-
AcceptableInOutExprs.insert(IOE);
201+
if (auto *IOE = dyn_cast<InOutExpr>(operand))
217202
operand = IOE->getSubExpr();
218-
}
219203

220204
// Also do some additional work based on how the function uses
221205
// the argument.
@@ -238,14 +222,6 @@ static void diagSyntacticUseRestrictions(TypeChecker &TC, const Expr *E,
238222
TC.diagnose(DAE->getLoc(), diag::discard_expr_outside_of_assignment);
239223
}
240224

241-
// Diagnose an '&' that isn't in an argument lists.
242-
if (auto *IOE = dyn_cast<InOutExpr>(E)) {
243-
if (!IOE->isImplicit() && !AcceptableInOutExprs.count(IOE) &&
244-
!IOE->getType()->hasError())
245-
TC.diagnose(IOE->getLoc(), diag::inout_expr_outside_of_call)
246-
.highlight(IOE->getSubExpr()->getSourceRange());
247-
}
248-
249225
// Diagnose 'self.init' or 'super.init' nested in another expression
250226
// or closure.
251227
if (auto *rebindSelfExpr = dyn_cast<RebindSelfInConstructorExpr>(E)) {

test/expr/expressions.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -829,7 +829,7 @@ func inoutTests(_ arr: inout Int) {
829829
inoutTests(&x)
830830

831831
// <rdar://problem/17489894> inout not rejected as operand to assignment operator
832-
&x += y // expected-error {{'&' can only appear immediately in a call argument list}}
832+
&x += y // expected-error {{use of extraneous '&'}}
833833

834834
// <rdar://problem/23249098>
835835
func takeAny(_ x: Any) {}

0 commit comments

Comments
 (0)