Skip to content

Commit

Permalink
Merge pull request #1333 from dduan/SE-0031
Browse files Browse the repository at this point in the history
[SE-0031] Adjusting 'inout' Declarations for Type Decoration
  • Loading branch information
lattner committed Feb 26, 2016
2 parents f86f9f0 + fb66ec8 commit dfaaebc
Show file tree
Hide file tree
Showing 72 changed files with 241 additions and 217 deletions.
3 changes: 3 additions & 0 deletions include/swift/AST/DiagnosticsParse.def
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,9 @@ WARNING(lex_editor_placeholder_in_playground,none,

NOTE(note_in_decl_extension,none,
"in %select{declaration|extension}0 of %1", (bool, Identifier))
WARNING(inout_as_attr_deprecated,none,
"'inout' before a parameter name is deprecated, place it before the parameter type instead",
())

ERROR(declaration_same_line_without_semi,none,
"consecutive declarations on a line must be separated by ';'", ())
Expand Down
67 changes: 25 additions & 42 deletions lib/AST/ASTPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -719,35 +719,22 @@ void PrintAST::printAttributes(const Decl *D) {
void PrintAST::printTypedPattern(const TypedPattern *TP) {
auto TheTypeLoc = TP->getTypeLoc();
if (TheTypeLoc.hasLocation()) {
// If the outer typeloc is an InOutTypeRepr, print the inout before the
// subpattern.
if (auto *IOT = dyn_cast<InOutTypeRepr>(TheTypeLoc.getTypeRepr())) {
TheTypeLoc = TypeLoc(IOT->getBase());
Type T = TheTypeLoc.getType();
if (T) {
if (auto *IOT = T->getAs<InOutType>()) {
T = IOT->getObjectType();
TheTypeLoc.setType(T);
}
}

printPattern(TP->getSubPattern());
Printer << ": ";

if (dyn_cast<InOutTypeRepr>(TheTypeLoc.getTypeRepr())) {
Printer << "inout ";
}

printPattern(TP->getSubPattern());
Printer << ": ";
printTypeLoc(TheTypeLoc);
return;
}

Type T = TP->getType();
if (auto *IOT = T->getAs<InOutType>()) {
T = IOT->getObjectType();
Printer << "inout ";
}

printPattern(TP->getSubPattern());
Printer << ": ";
Type T = TP->getType();
T.print(Printer, Options);
}

Expand Down Expand Up @@ -1877,9 +1864,25 @@ void PrintAST::printOneParameter(const ParamDecl *param, bool Curried,
};

auto TheTypeLoc = param->getTypeLoc();

// If the parameter is autoclosure, or noescape, print it. This is stored
// on the type of the decl, not on the typerepr.
if (param->hasType()) {
auto bodyCanType = param->getType()->getCanonicalType();
if (auto patternType = dyn_cast<AnyFunctionType>(bodyCanType)) {
switch (patternType->isAutoClosure()*2 + patternType->isNoEscape()) {
case 0: break; // neither.
case 1: Printer << "@noescape "; break;
case 2: Printer << "@autoclosure(escaping) "; break;
case 3: Printer << "@autoclosure "; break;
}
}
}

printArgName();

if (TheTypeLoc.getTypeRepr()) {
// If the outer typeloc is an InOutTypeRepr, print the 'inout' before the
// subpattern.

if (auto *IOTR = dyn_cast<InOutTypeRepr>(TheTypeLoc.getTypeRepr())) {
TheTypeLoc = TypeLoc(IOTR->getBase());
if (Type T = TheTypeLoc.getType()) {
Expand All @@ -1893,7 +1896,7 @@ void PrintAST::printOneParameter(const ParamDecl *param, bool Curried,
} else {
if (param->hasType())
TheTypeLoc = TypeLoc::withoutLoc(param->getType());

if (Type T = TheTypeLoc.getType()) {
if (auto *IOT = T->getAs<InOutType>()) {
Printer << "inout ";
Expand All @@ -1902,22 +1905,6 @@ void PrintAST::printOneParameter(const ParamDecl *param, bool Curried,
}
}

// If the parameter is autoclosure, or noescape, print it. This is stored
// on the type of the decl, not on the typerepr.
if (param->hasType()) {
auto bodyCanType = param->getType()->getCanonicalType();
if (auto patternType = dyn_cast<AnyFunctionType>(bodyCanType)) {
switch (patternType->isAutoClosure()*2 + patternType->isNoEscape()) {
case 0: break; // neither.
case 1: Printer << "@noescape "; break;
case 2: Printer << "@autoclosure(escaping) "; break;
case 3: Printer << "@autoclosure "; break;
}
}
}

printArgName();

auto ContainsFunc = [&] (DeclAttrKind Kind) {
return Options.ExcludeAttrList.end() != std::find(Options.ExcludeAttrList.
begin(), Options.ExcludeAttrList.end(), Kind);
Expand Down Expand Up @@ -2864,17 +2851,13 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
Printer << ", ";
const TupleTypeElt &TD = Fields[i];
Type EltType = TD.getType();
if (auto *IOT = EltType->getAs<InOutType>()) {
Printer << "inout ";
EltType = IOT->getObjectType();
}


if (TD.hasName()) {
Printer.printName(TD.getName(),
PrintNameContext::FunctionParameterExternal);
Printer << ": ";
}

if (TD.isVararg()) {
visit(TD.getVarargBaseTy());
Printer << "...";
Expand Down
35 changes: 23 additions & 12 deletions lib/Parse/ParsePattern.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -186,9 +186,10 @@ Parser::parseParameterClause(SourceLoc &leftParenLoc,
status |= makeParserCodeCompletionStatus();
}
}

//SourceLoc deprecatedInoutLoc;
// ('inout' | 'let' | 'var')?
if (Tok.is(tok::kw_inout)) {
//deprecatedInoutLoc = Tok.getLoc();
param.LetVarInOutLoc = consumeToken();
param.SpecifierKind = ParsedParameter::InOut;
} else if (Tok.is(tok::kw_let)) {
Expand Down Expand Up @@ -242,8 +243,28 @@ Parser::parseParameterClause(SourceLoc &leftParenLoc,
param.SecondNameLoc = SourceLoc();
}

// (':' type)?
// (':' ('inout')? type)?
if (consumeIf(tok::colon)) {

SourceLoc postColonLoc = Tok.getLoc();

bool hasDeprecatedInOut =
param.SpecifierKind == ParsedParameter::InOut;

if (Tok.is(tok::kw_inout)) {
SourceLoc deprecatedInOutLoc = param.LetVarInOutLoc;
param.LetVarInOutLoc = consumeToken();
param.SpecifierKind = ParsedParameter::InOut;
if (hasDeprecatedInOut) {
diagnose(deprecatedInOutLoc, diag::inout_as_attr_deprecated)
.fixItRemove(deprecatedInOutLoc);
}
} else if (hasDeprecatedInOut) {
diagnose(param.LetVarInOutLoc, diag::inout_as_attr_deprecated)
.fixItRemove(param.LetVarInOutLoc)
.fixItInsert(postColonLoc, "inout ");
}

auto type = parseType(diag::expected_parameter_type);
status |= type;
param.Type = type.getPtrOrNull();
Expand All @@ -252,16 +273,6 @@ Parser::parseParameterClause(SourceLoc &leftParenLoc,
// was invalid. Remember that.
if (type.isParseError() && !type.hasCodeCompletion())
param.isInvalid = true;

// Only allow 'inout' before the parameter name.
if (auto InOutTy = dyn_cast_or_null<InOutTypeRepr>(param.Type)) {
SourceLoc InOutLoc = InOutTy->getInOutLoc();
SourceLoc NameLoc = param.FirstNameLoc;
diagnose(InOutLoc, diag::inout_must_appear_before_param)
.fixItRemove(InOutLoc)
.fixItInsert(NameLoc, "inout ");
param.Type = InOutTy->getBase();
}
}
} else {
// Otherwise, we have invalid code. Check to see if this looks like a
Expand Down
2 changes: 1 addition & 1 deletion test/1_stdlib/Foundation_NewGenericAPIs.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

import Foundation

func expectType<T>(_: T.Type, inout _ x: T) {}
func expectType<T>(_: T.Type, _ x: inout T) {}

func test_NSCoder_decodeObject(coder: NSCoder) {
var r = coder.decodeObject()
Expand Down
2 changes: 1 addition & 1 deletion test/1_stdlib/UnicodeScalarDiagnostics.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// RUN: %target-parse-verify-swift

func isString(inout s: String) {}
func isString(s: inout String) {}

func test_UnicodeScalarDoesNotImplementArithmetic(us: UnicodeScalar, i: Int) {
var a1 = "a" + "b" // OK
Expand Down
2 changes: 1 addition & 1 deletion test/ClangModules/blocks_parse.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ func testNoEscape(@noescape f: @convention(block) () -> Void, nsStr: NSString,
_ = nsStr.enumerateLinesUsingBlock as Int // expected-error{{cannot convert value of type '(@noescape (String!) -> Void) -> Void' to type 'Int' in coercion}}
}

func checkTypeImpl<T>(inout a: T, _: T.Type) {}
func checkTypeImpl<T>(a: inout T, _: T.Type) {}
do {
var block = blockWithoutNullability()
checkTypeImpl(&block, ImplicitlyUnwrappedOptional<dispatch_block_t>.self)
Expand Down
2 changes: 1 addition & 1 deletion test/ClangModules/cf.swift
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ func nameCollisions() {
otherAlias = cfAlias // expected-error {{cannot assign value of type 'MyProblematicAliasRef?' to type 'MyProblematicAlias?'}}
cfAlias = otherAlias // expected-error {{cannot assign value of type 'MyProblematicAlias?' to type 'MyProblematicAliasRef?'}}

func isOptionalFloat(inout _: Optional<Float>) {}
func isOptionalFloat(_: inout Optional<Float>) {}
isOptionalFloat(&otherAlias) // okay

var np: NotAProblem?
Expand Down
2 changes: 1 addition & 1 deletion test/ClangModules/objc_bridging_generics.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ func testNSSetBridging(hive: Hive) {
_ = hive.allBees as Set<Bee>
}

public func expectType<T>(_: T.Type, inout _ x: T) {}
public func expectType<T>(_: T.Type, _ x: inout T) {}

func testNSMutableDictionarySubscript(
dict: NSMutableDictionary, key: NSCopying, value: AnyObject) {
Expand Down
2 changes: 1 addition & 1 deletion test/Constraints/assignment.swift
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ slice[7] = f // expected-error{{cannot assign value of type 'Y' to type 'X'}}
slice[7] = _ // expected-error{{'_' can only appear in a pattern or on the left side of an assignment}}

func value(x: Int) {}
func value2(inout x: Int) {}
func value2(x: inout Int) {}
value2(&_) // expected-error{{'_' can only appear in a pattern or on the left side of an assignment}}
value(_) // expected-error{{'_' can only appear in a pattern or on the left side of an assignment}}

Expand Down
6 changes: 3 additions & 3 deletions test/Constraints/bridging.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,13 @@ struct BridgedStruct : Hashable, _ObjectiveCBridgeable {
}

static func _forceBridgeFromObjectiveC(
x: BridgedClass,
inout result: BridgedStruct?) {
x: BridgedClass,
result: inout BridgedStruct?) {
}

static func _conditionallyBridgeFromObjectiveC(
x: BridgedClass,
inout result: BridgedStruct?
result: inout BridgedStruct?
) -> Bool {
return true
}
Expand Down
2 changes: 1 addition & 1 deletion test/Constraints/closures.swift
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ func r15998821() {
func take_closure(x : (inout Int) -> ()) { }

func test1() {
take_closure { (inout a : Int) in
take_closure { (a : inout Int) in
a = 42
}
}
Expand Down
6 changes: 3 additions & 3 deletions test/Constraints/construction.swift
Original file line number Diff line number Diff line change
Expand Up @@ -104,9 +104,9 @@ z as Z

// Construction from inouts.
struct FooRef { }
struct BarRef {
init(inout x: FooRef) {}
init(inout x: Int) {}
struct BarRef {
init(x: inout FooRef) {}
init(x: inout Int) {}
}
var f = FooRef()
var x = 0
Expand Down
4 changes: 2 additions & 2 deletions test/Constraints/default_literals.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// RUN: %target-parse-verify-swift

func acceptInt(inout _ : Int) {}
func acceptDouble(inout _ : Double) {}
func acceptInt(_ : inout Int) {}
func acceptDouble(_ : inout Double) {}

var i1 = 1
acceptInt(&i1)
Expand Down
4 changes: 2 additions & 2 deletions test/Constraints/diagnostics.swift
Original file line number Diff line number Diff line change
Expand Up @@ -488,7 +488,7 @@ enum Color {
static func overload(a a : Int) -> Color {}
static func overload(b b : Int) -> Color {}

static func frob(a : Int, inout b : Int) -> Color {}
static func frob(a : Int, b : inout Int) -> Color {}
}
let _: (Int, Color) = [1,2].map({ ($0, .Unknown("")) }) // expected-error {{'map' produces '[T]', not the expected contextual result type '(Int, Color)'}}
let _: [(Int, Color)] = [1,2].map({ ($0, .Unknown("")) })// expected-error {{missing argument label 'description:' in call}} {{51-51=description: }}
Expand Down Expand Up @@ -643,7 +643,7 @@ extension Array {
}

// <rdar://problem/22519983> QoI: Weird error when failing to infer archetype
func safeAssign<T: RawRepresentable>(inout lhs: T) -> Bool {}
func safeAssign<T: RawRepresentable>(lhs: inout T) -> Bool {}
// expected-note @-1 {{in call to function 'safeAssign'}}
let a = safeAssign // expected-error {{generic parameter 'T' could not be inferred}}

Expand Down
2 changes: 1 addition & 1 deletion test/Constraints/fixes.swift
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ func forgotAnyObjectBang(obj: AnyObject) {
_ = a
}

func increment(inout x: Int) { }
func increment(x: inout Int) { }

func forgotAmpersand() {
var i = 5
Expand Down
2 changes: 1 addition & 1 deletion test/Constraints/invalid_constraint_lookup.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,6 @@ protocol _CollectionType {
protocol CollectionType : _CollectionType, SequenceType {
subscript(i: Index) -> Generator.Element {get set }
}
func insertionSort<C: Mutable> (inout elements: C, i: C.Index) { // expected-error {{use of undeclared type 'Mutable'}} expected-error {{'Index' is not a member type of 'C'}}
func insertionSort<C: Mutable> (elements: inout C, i: C.Index) { // expected-error {{use of undeclared type 'Mutable'}} expected-error {{'Index' is not a member type of 'C'}}
var x: C.Generator.Element = elements[i] // expected-error {{'Generator' is not a member type of 'C'}}
}
24 changes: 12 additions & 12 deletions test/Constraints/lvalues.swift
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
// RUN: %target-parse-verify-swift

func f0(inout x: Int) {}
func f1<T>(inout x: T) {}
func f2(inout x: X) {}
func f2(inout x: Double) {}
func f0(x: inout Int) {}
func f1<T>(x: inout T) {}
func f2(x: inout X) {}
func f2(x: inout Double) {}

class Reftype {
var property: Double { get {} set {} }
Expand All @@ -27,10 +27,10 @@ var f : Float
var x : X
var y : Y

func +=(inout lhs: X, rhs : X) {}
func +=(inout lhs: Double, rhs : Double) {}
prefix func ++(inout rhs: X) {}
postfix func ++(inout lhs: X) {}
func +=(lhs: inout X, rhs : X) {}
func +=(lhs: inout Double, rhs : Double) {}
prefix func ++(rhs: inout X) {}
postfix func ++(lhs: inout X) {}

f0(&i)
f1(&i)
Expand Down Expand Up @@ -154,7 +154,7 @@ func testFooStruct() {

// Don't load from explicit lvalues.
func takesInt(x: Int) {}
func testInOut(inout arg: Int) {
func testInOut(arg: inout Int) {
var x : Int
takesInt(&x) // expected-error{{'&' used with non-inout argument of type 'Int'}}
}
Expand All @@ -166,7 +166,7 @@ var ir2 = ((&i)) // expected-error{{type 'inout Int' of variable is not material
// expected-error{{'&' can only appear immediately in a call argument list}}

// <rdar://problem/17133089>
func takeArrayRef(inout x:Array<String>) { }
func takeArrayRef(x: inout Array<String>) { }

// rdar://22308291
takeArrayRef(["asdf", "1234"]) // expected-error{{contextual type 'inout Array<String>' cannot be used with array literal}}
Expand Down Expand Up @@ -224,11 +224,11 @@ func rdar23131768() {
f2 { $0 = $0 + 1 } // previously error: Cannot convert value of type '_ -> ()' to expected type '(inout Int) -> Void'

func f3(g: (inout Int) -> Void) { var a = 1; g(&a); print(a) }
f3 { (inout v: Int) -> Void in v += 1 }
f3 { (v: inout Int) -> Void in v += 1 }
}

// <rdar://problem/23331567> Swift: Compiler crash related to closures with inout parameter.
func r23331567(fn: (inout x: Int) -> Void) {
func r23331567(fn: (x: inout Int) -> Void) {
var a = 0
fn(x: &a)
}
Expand Down
Loading

0 comments on commit dfaaebc

Please sign in to comment.