From 1bfee7b22b967c4eb4b724704459769b57da1793 Mon Sep 17 00:00:00 2001 From: Harlan Haskins Date: Fri, 9 Sep 2016 00:21:12 -0400 Subject: [PATCH] Fix var-parameter detection for inferred params Previously, we would skip validating the type (and checking var/inout) on parameters that didn't have an explicit type. Instead, teach validateParameterType how to handle an elided type. --- lib/Sema/TypeCheckPattern.cpp | 22 ++++++++++++------- test/Sema/immutability.swift | 4 +++- ...t-typechecker-typecheckparameterlist.swift | 3 --- ...t-typechecker-typecheckparameterlist.swift | 3 +++ 4 files changed, 20 insertions(+), 12 deletions(-) delete mode 100644 validation-test/IDE/crashers/069-swift-typechecker-typecheckparameterlist.swift create mode 100644 validation-test/IDE/crashers_fixed/069-swift-typechecker-typecheckparameterlist.swift diff --git a/lib/Sema/TypeCheckPattern.cpp b/lib/Sema/TypeCheckPattern.cpp index 6d93839dc44ae..1fa85f4f5d123 100644 --- a/lib/Sema/TypeCheckPattern.cpp +++ b/lib/Sema/TypeCheckPattern.cpp @@ -746,21 +746,28 @@ static bool validateParameterType(ParamDecl *decl, DeclContext *DC, auto elementOptions = (options | (decl->isVariadic() ? TR_VariadicFunctionInput : TR_FunctionInput)); - bool hadError = TC.validateType(decl->getTypeLoc(), DC, - elementOptions, resolver); - + bool hadError = false; + + // We might have a null typeLoc if this is a closure parameter list, + // where parameters are allowed to elide their types. + if (!decl->getTypeLoc().isNull()) { + hadError |= TC.validateType(decl->getTypeLoc(), DC, + elementOptions, resolver); + } + Type Ty = decl->getTypeLoc().getType(); - if (decl->isVariadic() && !hadError) { + if (decl->isVariadic() && !Ty.isNull() && !hadError) { Ty = TC.getArraySliceType(decl->getStartLoc(), Ty); if (Ty.isNull()) { hadError = true; } decl->getTypeLoc().setType(Ty); } + // If the param is not a 'let' and it is not an 'inout'. // It must be a 'var'. Provide helpful diagnostics like a shadow copy // in the function body to fix the 'var' attribute. - if (!decl->isLet() && !decl->isInOut()) { + if (!decl->isLet() && (Ty.isNull() || !Ty->is()) && !hadError) { auto func = dyn_cast_or_null(DC); diagnoseAndMigrateVarParameterToBody(decl, func, TC); decl->setInvalid(); @@ -769,7 +776,7 @@ static bool validateParameterType(ParamDecl *decl, DeclContext *DC, if (hadError) decl->getTypeLoc().setType(ErrorType::get(TC.Context), /*validated*/true); - + return hadError; } @@ -780,8 +787,7 @@ bool TypeChecker::typeCheckParameterList(ParameterList *PL, DeclContext *DC, bool hadError = false; for (auto param : *PL) { - if (param->getTypeLoc().getTypeRepr()) - hadError |= validateParameterType(param, DC, options, resolver, *this); + hadError |= validateParameterType(param, DC, options, resolver, *this); auto type = param->getTypeLoc().getType(); if (!type && param->hasType()) { diff --git a/test/Sema/immutability.swift b/test/Sema/immutability.swift index fd59b2cd7d6bb..4a475e8a21716 100644 --- a/test/Sema/immutability.swift +++ b/test/Sema/immutability.swift @@ -351,7 +351,9 @@ func invalid_inout(inout var x : Int) { // expected-error {{parameter may not ha func invalid_var(var x: Int) { // expected-error {{parameters may not have the 'var' specifier}}{{18-21=}} {{1-1= var x = x\n}} } - +func takesClosure(_: (Int) -> Int) { + takesClosure { (var d) in d } // expected-error {{parameters may not have the 'var' specifier}} +} func updateInt(_ x : inout Int) {} diff --git a/validation-test/IDE/crashers/069-swift-typechecker-typecheckparameterlist.swift b/validation-test/IDE/crashers/069-swift-typechecker-typecheckparameterlist.swift deleted file mode 100644 index 82f588e985ed8..0000000000000 --- a/validation-test/IDE/crashers/069-swift-typechecker-typecheckparameterlist.swift +++ /dev/null @@ -1,3 +0,0 @@ -// RUN: not --crash %target-swift-ide-test -code-completion -code-completion-token=A -source-filename=%s -// REQUIRES: asserts -func b(e:({#^A^#var e){ \ No newline at end of file diff --git a/validation-test/IDE/crashers_fixed/069-swift-typechecker-typecheckparameterlist.swift b/validation-test/IDE/crashers_fixed/069-swift-typechecker-typecheckparameterlist.swift new file mode 100644 index 0000000000000..45e19dfeb39a1 --- /dev/null +++ b/validation-test/IDE/crashers_fixed/069-swift-typechecker-typecheckparameterlist.swift @@ -0,0 +1,3 @@ +// RUN: %target-swift-ide-test -code-completion -code-completion-token=A -source-filename=%s +// REQUIRES: asserts +func b(e:({#^A^#var e){