Skip to content

Commit 328866a

Browse files
authored
Merge pull request #3855 from slavapestov/fix-bad-diagnostic
2 parents 6d2f11a + 9a1fa52 commit 328866a

File tree

6 files changed

+29
-6
lines changed

6 files changed

+29
-6
lines changed

include/swift/AST/Decl.h

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,11 @@ class alignas(1 << DeclAlignInBits) Decl {
288288
/// once (either in its declaration, or once later), making it immutable.
289289
unsigned IsLet : 1;
290290

291+
/// \brief Whether this is an 'inout' parameter; this is preferable
292+
/// to checking if the parameter type is an InOutType, because invalid
293+
/// inout parameters have an error type.
294+
unsigned IsInOut : 1;
295+
291296
/// \brief Whether this vardecl has an initial value bound to it in a way
292297
/// that isn't represented in the AST with an initializer in the pattern
293298
/// binding. This happens in cases like "for i in ...", switch cases, etc.
@@ -301,7 +306,7 @@ class alignas(1 << DeclAlignInBits) Decl {
301306
/// a.storage for lazy var a is a decl that cannot be accessed.
302307
unsigned IsUserAccessible : 1;
303308
};
304-
enum { NumVarDeclBits = NumAbstractStorageDeclBits + 5 };
309+
enum { NumVarDeclBits = NumAbstractStorageDeclBits + 6 };
305310
static_assert(NumVarDeclBits <= 32, "fits in an unsigned");
306311

307312
class EnumElementDeclBitfields {
@@ -4234,6 +4239,7 @@ class VarDecl : public AbstractStorageDecl {
42344239
VarDeclBits.IsUserAccessible = true;
42354240
VarDeclBits.IsStatic = IsStatic;
42364241
VarDeclBits.IsLet = IsLet;
4242+
VarDeclBits.IsInOut = false;
42374243
VarDeclBits.IsDebuggerVar = false;
42384244
VarDeclBits.HasNonPatternBindingInit = false;
42394245
setType(Ty);
@@ -4331,6 +4337,10 @@ class VarDecl : public AbstractStorageDecl {
43314337
bool isLet() const { return VarDeclBits.IsLet; }
43324338
void setLet(bool IsLet) { VarDeclBits.IsLet = IsLet; }
43334339

4340+
/// Is this an 'inout' parameter?
4341+
bool isInOut() const { return VarDeclBits.IsInOut; }
4342+
void setInOut(bool InOut) { VarDeclBits.IsInOut = InOut; }
4343+
43344344
/// Return true if this vardecl has an initial value bound to it in a way
43354345
/// that isn't represented in the AST with an initializer in the pattern
43364346
/// binding. This happens in cases like "for i in ...", switch cases, etc.
@@ -4439,6 +4449,7 @@ class ParamDecl : public VarDecl {
44394449
ExprHandle *getDefaultValue() const {
44404450
return DefaultValueAndIsVariadic.getPointer();
44414451
}
4452+
44424453
/// Whether or not this parameter is varargs.
44434454
bool isVariadic() const { return DefaultValueAndIsVariadic.getInt(); }
44444455
void setVariadic(bool value = true) {DefaultValueAndIsVariadic.setInt(value);}

lib/Parse/ParsePattern.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -387,8 +387,10 @@ mapParsedParameters(Parser &parser,
387387
// If a type was provided, create the type for the parameter.
388388
if (auto type = paramInfo.Type) {
389389
// If 'inout' was specified, turn the type into an in-out type.
390-
if (specifierKind == Parser::ParsedParameter::InOut)
390+
if (specifierKind == Parser::ParsedParameter::InOut) {
391391
type = new (ctx) InOutTypeRepr(type, paramInfo.LetVarInOutLoc);
392+
param->setInOut(true);
393+
}
392394

393395
param->getTypeLoc() = TypeLoc(type);
394396
} else if (paramContext != Parser::ParameterContextKind::Closure) {

lib/Sema/TypeCheckDecl.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1121,6 +1121,7 @@ Type swift::configureImplicitSelf(TypeChecker &tc,
11211121
// 'self' is 'let' for reference types (i.e., classes) or when 'self' is
11221122
// neither inout.
11231123
selfDecl->setLet(!selfTy->is<InOutType>());
1124+
selfDecl->setInOut(selfTy->is<InOutType>());
11241125
selfDecl->overwriteType(selfTy);
11251126

11261127
// Install the self type on the Parameter that contains it. This ensures that

lib/Sema/TypeCheckPattern.cpp

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -781,7 +781,7 @@ static bool validateParameterType(ParamDecl *decl, DeclContext *DC,
781781
// If the param is not a 'let' and it is not an 'inout'.
782782
// It must be a 'var'. Provide helpful diagnostics like a shadow copy
783783
// in the function body to fix the 'var' attribute.
784-
if (!decl->isLet() && !Ty->is<InOutType>()) {
784+
if (!decl->isLet() && !decl->isInOut()) {
785785
auto func = dyn_cast_or_null<AbstractFunctionDecl>(DC);
786786
diagnoseAndMigrateVarParameterToBody(decl, func, TC);
787787
decl->setInvalid();
@@ -828,8 +828,10 @@ bool TypeChecker::typeCheckParameterList(ParameterList *PL, DeclContext *DC,
828828
param->overwriteType(type);
829829

830830
checkTypeModifyingDeclAttributes(param);
831-
if (param->getType()->is<InOutType>())
831+
if (param->getType()->is<InOutType>()) {
832+
param->setInOut(true);
832833
param->setLet(false);
834+
}
833835
}
834836

835837
return hadError;
@@ -1098,8 +1100,10 @@ bool TypeChecker::coercePatternToType(Pattern *&P, DeclContext *dc, Type type,
10981100
var->overwriteType(type);
10991101

11001102
checkTypeModifyingDeclAttributes(var);
1101-
if (type->is<InOutType>())
1103+
if (type->is<InOutType>()) {
1104+
NP->getDecl()->setInOut(true);
11021105
NP->getDecl()->setLet(false);
1106+
}
11031107
if (var->getAttrs().hasAttribute<OwnershipAttr>())
11041108
type = getTypeOfRValue(var, true);
11051109
else if (!var->isInvalid())
@@ -1559,6 +1563,7 @@ bool TypeChecker::coerceParameterListToType(ParameterList *P, DeclContext *DC,
15591563

15601564
if (!ty->isMaterializable()) {
15611565
if (ty->is<InOutType>()) {
1566+
param->setInOut(true);
15621567
param->setLet(false);
15631568
} else if (param->hasName()) {
15641569
diagnose(param->getStartLoc(),

test/Constraints/same_types.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,6 @@ struct BadFooable : Fooable {
139139
var foo: Foo { while true {} }
140140
}
141141

142-
func bogusInOutError(d: inout Brunch<BadFooable>) {} // expected-error{{parameters may not have the 'var' specifier}}
142+
func bogusInOutError(d: inout Brunch<BadFooable>) {}
143143
// expected-error@-1{{'Brunch' requires the types '<<error type>>' and 'X' be equivalent}}
144144

test/decl/func/functions.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,3 +155,7 @@ func testCurryFixits() {
155155
func f5(_ x: Int)()(y: Int) {} // expected-error{{curried function declaration syntax has been removed; use a single parameter list}} {{19-21=}} {{21-23=, }}
156156
func f5a(_ x: Int, y: Int) {}
157157
}
158+
159+
// Bogus diagnostic talking about a 'var' where there is none
160+
func invalidInOutParam(x: inout XYZ) {}
161+
// expected-error@-1{{use of undeclared type 'XYZ'}}

0 commit comments

Comments
 (0)