From 7c7c5319cff72267a93ee949eaad187889f11d11 Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Wed, 1 Sep 2021 18:40:23 +0100 Subject: [PATCH 01/14] [AST] Introduce ArgumentList Introduce the ArgumentList type, which represents a set of call arguments for a function or subscript. This will supersede the use of tuple and paren exprs as argument lists. --- include/swift/AST/ASTWalker.h | 25 ++ include/swift/AST/ArgumentList.h | 647 +++++++++++++++++++++++++++++++ lib/AST/ASTDumper.cpp | 73 ++++ lib/AST/ASTWalker.cpp | 17 + lib/AST/ArgumentList.cpp | 451 +++++++++++++++++++++ lib/AST/CMakeLists.txt | 1 + 6 files changed, 1214 insertions(+) create mode 100644 include/swift/AST/ArgumentList.h create mode 100644 lib/AST/ArgumentList.cpp diff --git a/include/swift/AST/ASTWalker.h b/include/swift/AST/ASTWalker.h index 74b5850741920..994111f7ffdf4 100644 --- a/include/swift/AST/ASTWalker.h +++ b/include/swift/AST/ASTWalker.h @@ -18,6 +18,7 @@ namespace swift { +class ArgumentList; class Decl; class Expr; class ClosureExpr; @@ -244,6 +245,30 @@ class ASTWalker { /// traversal is terminated and returns failure. virtual bool walkToParameterListPost(ParameterList *PL) { return true; } + /// This method is called when first visiting an argument list before walking + /// into its arguments. + /// + /// \param ArgList The argument list to walk. + /// + /// \returns a pair indicating whether to visit the arguments, along with + /// the argument list that should replace this argument list in the tree. If + /// the latter is null, the traversal will be terminated. + /// + /// The default implementation returns \c {true, ArgList}. + virtual std::pair + walkToArgumentListPre(ArgumentList *ArgList) { + return {true, ArgList}; + } + + /// This method is called after visiting the arguments in an argument list. + /// If it returns null, the walk is terminated; otherwise, the + /// returned argument list is spliced in where the old argument list + /// previously appeared. + /// + /// The default implementation always returns the argument list. + virtual ArgumentList *walkToArgumentListPost(ArgumentList *ArgList) { + return ArgList; + } protected: ASTWalker() = default; diff --git a/include/swift/AST/ArgumentList.h b/include/swift/AST/ArgumentList.h new file mode 100644 index 0000000000000..20d2f73b154e6 --- /dev/null +++ b/include/swift/AST/ArgumentList.h @@ -0,0 +1,647 @@ +//===--- ArgumentList.h - Function and subscript argument lists -*- C++ -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2021 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +// +// This file defines the Argument and ArgumentList classes and support logic. +// +//===----------------------------------------------------------------------===// + +#ifndef SWIFT_AST_ARGUMENTLIST_H +#define SWIFT_AST_ARGUMENTLIST_H + +#include "swift/AST/ASTAllocated.h" +#include "swift/AST/Types.h" +#include "swift/Basic/Debug.h" +#include "llvm/Support/TrailingObjects.h" + +namespace swift { +class OriginalArguments; + +/// Forward declared trampoline for Expr::getType. +Type __Expr_getType(Expr *E); + +/// Represents a single argument in an argument list, including its label +/// information and inout-ness. +/// +/// \code +/// foo.bar(arg, label: arg2, other: &arg3) +/// ^^^ ^^^^^^^^^^^^ +/// an unlabeled 'other' is the label, 'arg3' is the expr, +/// argument and isInout() is true. +/// \endcode +class Argument final { + SourceLoc LabelLoc; + Identifier Label; + Expr *ArgExpr; + // TODO: Store inout bit here. + +public: + Argument(SourceLoc labelLoc, Identifier label, Expr *expr) + : LabelLoc(labelLoc), Label(label), ArgExpr(expr) {} + + /// Make an unlabeled argument. + static Argument unlabeled(Expr *expr) { + return Argument(SourceLoc(), Identifier(), expr); + } + + SourceLoc getStartLoc() const { return getSourceRange().Start; } + SourceLoc getEndLoc() const { return getSourceRange().End; } + SourceRange getSourceRange() const; + + /// If the argument has a label with location information, returns the + /// location. + /// + /// Note this may be present even if the label is empty, e.g for multiple + /// trailing closures where labels are required such as '_: {}'. + SourceLoc getLabelLoc() const { return LabelLoc; } + + /// The argument label written in the call. + Identifier getLabel() const { return Label; } + + /// Set a new argument label. + /// + /// Note this is marked \c & to prevent its use on an rvalue Argument vended + /// from an ArgumentList. + void setLabel(Identifier newLabel) & { Label = newLabel; } + + /// The argument expression. + Expr *getExpr() const { return ArgExpr; } + + /// Set a new argument expression. + /// + /// Note this is marked \c & to prevent its use on an rvalue Argument vended + /// from an ArgumentList. + void setExpr(Expr *newExpr) & { ArgExpr = newExpr; } + + /// Whether the argument is \c inout, denoted with the '&' prefix. + bool isInOut() const; + + bool operator==(const Argument &other) { + return LabelLoc == other.LabelLoc && Label == other.Label && + ArgExpr == other.ArgExpr; + } + bool operator!=(const Argument &other) { return !(*this == other); } +}; + +/// Represents the argument list of a function call or subscript access. +/// \code +/// foo.bar(arg, label: arg2, other: &arg3) +/// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/// \endcode +/// +/// Note that arguments are split up and stored in separate buffers to optimize +/// ArgumentList's memory footprint for the unlabeled cases. +class alignas(Argument) ArgumentList final + : public ASTAllocated, + private llvm::TrailingObjects { + friend TrailingObjects; + + SourceLoc LParenLoc; + SourceLoc RParenLoc; + + /// The number of arguments in the list. + unsigned NumArgs : 16; + + /// The index of the first trailing closure, or \c NumArgs if there are no + /// trailing closures. In type-checked AST, this may be an index to a variadic + /// expansion that contains the first trailing closure. + unsigned RawFirstTrailingClosureIndex : 16; + + /// Whether the argument list has multiple trailing closures. + bool HasMultipleTrailingClosures : 1; + + /// Whether the argument list was implicitly generated. + bool IsImplicit : 1; + + /// Whether any of the arguments are labeled. + bool HasLabels : 1; + + /// Whether any of the arguments have labels with location info. + bool HasLabelLocs : 1; + + ArgumentList(SourceLoc lParenLoc, SourceLoc rParenLoc, unsigned numArgs, + Optional firstTrailingClosureIndex, + bool hasMultipleTrailingClosures, bool isImplicit, + bool hasLabels, bool hasLabelLocs) + : LParenLoc(lParenLoc), RParenLoc(rParenLoc), NumArgs(numArgs), + HasMultipleTrailingClosures(hasMultipleTrailingClosures), + IsImplicit(isImplicit), HasLabels(hasLabels), + HasLabelLocs(hasLabelLocs) { + assert(NumArgs == numArgs && "Num args truncated"); + if (auto idx = firstTrailingClosureIndex) { + assert(*idx < numArgs); + RawFirstTrailingClosureIndex = *idx; + } else { + RawFirstTrailingClosureIndex = numArgs; + assert(!HasMultipleTrailingClosures); + } + } + + ArgumentList(const ArgumentList &) = delete; + ArgumentList &operator=(const ArgumentList &) = delete; + + size_t numTrailingObjects(OverloadToken) const { + return NumArgs; + } + size_t numTrailingObjects(OverloadToken) const { + return HasLabels ? NumArgs : 0; + } + size_t numTrailingObjects(OverloadToken) const { + return HasLabelLocs ? NumArgs : 0; + } + + ArrayRef getExprsBuffer() const { + return {getTrailingObjects(), NumArgs}; + } + MutableArrayRef getExprsBuffer() { + return {getTrailingObjects(), NumArgs}; + } + + ArrayRef getLabelsBuffer() const { + assert(HasLabels); + return {getTrailingObjects(), NumArgs}; + } + MutableArrayRef getLabelsBuffer() { + assert(HasLabels); + return {getTrailingObjects(), NumArgs}; + } + + ArrayRef getLabelLocsBuffer() const { + assert(HasLabelLocs); + return {getTrailingObjects(), NumArgs}; + } + MutableArrayRef getLabelLocsBuffer() { + assert(HasLabelLocs); + return {getTrailingObjects(), NumArgs}; + } + +public: + /// Create a new ArgumentList. + /// + /// \param lParenLoc The location of the opening '('. Note that for a + /// subscript argument list, this will be for the opening '['. + /// \param args The list of arguments in the call. + /// \param rParenLoc The location of the closing ')'. Note that for a + /// subscript argument list, this will be for the closing ']'. + /// \param firstTrailingClosureIndex The index of the first trailing closure, + /// which in type-checked AST may be a variadic expansion with the closure. + /// \param hasMultipleTrailingClosures Whether there are multiple trailing + /// closures. + /// \param isImplicit Whether this is an implicitly generated argument list. + /// \param arena The arena to allocate the ArgumentList in. + static ArgumentList * + create(ASTContext &ctx, SourceLoc lParenLoc, ArrayRef args, + SourceLoc rParenLoc, Optional firstTrailingClosureIndex, + bool hasMultipleTrailingClosures, bool isImplicit, + AllocationArena arena = AllocationArena::Permanent); + + /// Create a new ArgumentList. + /// + /// \param lParenLoc The location of the opening '('. Note that for a + /// subscript argument list, this will be for the opening '['. + /// \param args The list of arguments in the call. + /// \param rParenLoc The location of the closing ')'. Note that for a + /// subscript argument list, this will be for the closing ']'. + /// \param isImplicit Whether this is an implicitly generated argument list. + /// \param arena The arena to allocate the ArgumentList in. + /// + /// The trailing closure information will be inferred from the arguments + /// provided. + static ArgumentList * + create(ASTContext &ctx, SourceLoc lParenLoc, ArrayRef args, + SourceLoc rParenLoc, bool isImplicit, + AllocationArena arena = AllocationArena::Permanent); + + /// Create a new implicit ArgumentList. + /// + /// \param lParenLoc The location of the opening '('. Note that for a + /// subscript argument list, this will be for the opening '['. + /// \param args The list of arguments in the call. + /// \param rParenLoc The location of the closing ')'. Note that for a + /// subscript argument list, this will be for the closing ']'. + /// \param arena The arena to allocate the ArgumentList in. + static ArgumentList * + createImplicit(ASTContext &ctx, SourceLoc lParenLoc, ArrayRef args, + SourceLoc rParenLoc, + AllocationArena arena = AllocationArena::Permanent); + + /// Create a new implicit ArgumentList with a set of \p args. + static ArgumentList * + createImplicit(ASTContext &ctx, ArrayRef args, + AllocationArena arena = AllocationArena::Permanent); + + /// Create a new implicit ArgumentList with a single labeled argument + /// expression. + static ArgumentList *forImplicitSingle(ASTContext &ctx, Identifier label, + Expr *arg); + + /// Create a new implicit ArgumentList with a set of unlabeled arguments. + static ArgumentList *forImplicitUnlabeled(ASTContext &ctx, + ArrayRef argExprs); + + /// Create a new implicit ArgumentList with a set of argument expressions, + /// and a DeclNameRef from which to infer the argument labels. + static ArgumentList *forImplicitCallTo(DeclNameRef fnNameRef, + ArrayRef argExprs, + ASTContext &ctx); + + /// Create a new implicit ArgumentList with a set of argument expressions, + /// and a ParameterList from which to infer the argument labels. + static ArgumentList *forImplicitCallTo(ParameterList *params, + ArrayRef argExprs, + ASTContext &ctx); + + /// The location of the opening '('. Note that for a subscript argument list, + /// this will be for the opening '['. + SourceLoc getLParenLoc() const { return LParenLoc; } + + /// The location of the closing ')'. Note that for a subscript argument list, + /// this will be for the closing ']'. + SourceLoc getRParenLoc() const { return RParenLoc; } + + /// Whether this is an implicitly generated argument list, not written in the + /// source. + bool isImplicit() const { return IsImplicit; } + + /// Whether the argument list has any non-empty argument labels. + bool hasAnyArgumentLabels() const { return HasLabels; } + + SourceLoc getLoc() const; + SourceLoc getStartLoc() const { return getSourceRange().Start; } + SourceLoc getEndLoc() const { return getSourceRange().End; } + SourceRange getSourceRange() const; + + /// Retrieve the argument expression at a given index. + Expr *getExpr(unsigned idx) const { return getExprsBuffer()[idx]; } + void setExpr(unsigned idx, Expr *newExpr) { getExprsBuffer()[idx] = newExpr; } + + /// Retrieve the argument label at a given index. + Identifier getLabel(unsigned idx) const { + if (!HasLabels) + return Identifier(); + return getLabelsBuffer()[idx]; + } + + /// Retrieve the argument label location at a given index. + SourceLoc getLabelLoc(unsigned idx) const { + if (!HasLabelLocs) + return SourceLoc(); + return getLabelLocsBuffer()[idx]; + } + + /// Retrieve the argument at a given index. + Argument get(unsigned idx) const { + return Argument(getLabelLoc(idx), getLabel(idx), getExpr(idx)); + } + + unsigned size() const { return NumArgs; } + bool empty() const { return size() == 0; } + + class iterator final { + const ArgumentList *ArgList; + unsigned Idx; + + public: + using iterator_category = std::random_access_iterator_tag; + using value_type = Argument; + using pointer = const value_type *; + using reference = value_type; + using difference_type = unsigned; + + iterator() : ArgList(nullptr), Idx(0) {} + iterator(const ArgumentList *argList, unsigned idx) + : ArgList(argList), Idx(idx) {} + + Argument operator*() const { + assert(ArgList); + return ArgList->get(Idx); + } + Argument operator[](unsigned i) const { + assert(ArgList); + return ArgList->get(Idx + i); + } + + friend bool operator==(const iterator &lhs, const iterator &rhs) { + assert(lhs.ArgList == rhs.ArgList); + return lhs.Idx == rhs.Idx; + } + friend bool operator!=(const iterator &lhs, const iterator &rhs) { + return !(lhs == rhs); + } + + iterator &operator++() { // pre-increment + ++Idx; + return *this; + } + iterator operator++(int) { // post-increment + auto tmp = *this; + ++*this; + return tmp; + } + iterator &operator--() { // pre-decrement + --Idx; + return *this; + } + iterator operator--(int) { // post-decrement + auto tmp = *this; + --*this; + return tmp; + } + + iterator &operator+=(unsigned i) { + Idx += i; + return *this; + } + iterator operator+(unsigned i) const { + return iterator(ArgList, Idx + i); + } + iterator &operator-=(unsigned i) { + Idx -= i; + return *this; + } + iterator operator-(unsigned i) const { + return iterator(ArgList, Idx - i); + } + + unsigned operator-(const iterator &rhs) const { + assert(ArgList == rhs.ArgList); + return Idx - rhs.Idx; + } + bool operator<(const iterator &rhs) const { + assert(ArgList == rhs.ArgList); + return Idx < rhs.Idx; + } + bool operator<=(const iterator &rhs) const { + assert(ArgList == rhs.ArgList); + return Idx <= rhs.Idx; + } + bool operator>(const iterator &rhs) const { + assert(ArgList == rhs.ArgList); + return Idx > rhs.Idx; + } + bool operator>=(const iterator &rhs) const { + assert(ArgList == rhs.ArgList); + return Idx >= rhs.Idx; + } + }; + + iterator begin() const { return {this, 0}; } + iterator end() const { return {this, size()}; } + + Argument front() const { return get(0); } + Argument back() const { return get(size() - 1); } + + Argument operator[](unsigned idx) const { return get(idx); } + + /// Returns the index of the first trailing closure in the argument list, or + /// \c None if there are no trailing closures. + /// + /// Note that in type-checked AST, this may return an index of a variadic + /// expansion which contains the trailing closure (and it may not necessarily + /// be the first argument of the expansion). + Optional getRawFirstTrailingClosureIndex() const { + if (RawFirstTrailingClosureIndex == NumArgs) + return None; + return RawFirstTrailingClosureIndex; + } + + /// Whether any trailing closures are present in the argument list. + bool hasAnyTrailingClosures() const { + return getRawFirstTrailingClosureIndex().hasValue(); + } + + /// Whether this argument list has a single trailing closure. + bool hasSingleTrailingClosure() const { + return hasAnyTrailingClosures() && !hasMultipleTrailingClosures(); + } + + /// Whether the argument list has multiple trailing closures. + bool hasMultipleTrailingClosures() const { + return HasMultipleTrailingClosures; + } + + /// Whether a given index is for a labeled or unlabeled trailing closure. + /// + /// Note that in type-checked AST, this may return \c true for an index of a + /// variadic expansion which contains a trailing closure (and it may not + /// necessarily be the first argument of the expansion). + bool isRawTrailingClosureIndex(unsigned i) const { + if (!hasAnyTrailingClosures()) + return false; + return i >= getRawFirstTrailingClosureIndex() && i < size(); + } + + // NOTE: There are *intentionally* not that many APIs here that provide access + // to the trailing closures of the argument list. This is because trailing + // closures have a tricky representation in type-checked AST, and you're + // likely better off querying getOriginalArguments(). + // + // When adding additional trailing closure APIs, bear in mind that in + // type-checked AST: + // - Trailing closures may be nested within variadic expansion exprs. + // - Variadic expansion exprs may contain a mix of trailing and non-trailing + // closures. + // - Trailing closures may appear *before* non-trailing arguments in certain + // backward argument matching cases (see comment in getOriginalArguments). + + /// Whether any of the arguments in the argument are inout. + bool hasAnyInOutArgs() const { + return llvm::any_of(*this, [](auto arg) { return arg.isInOut(); }); + } + + /// Whether the argument list has a single argument, which may be labeled or + /// unlabeled. + bool isUnary() const { return size() == 1; } + + /// Whether the argument list has a single unlabeled argument. + bool isUnlabeledUnary() const { return isUnary() && getLabel(0).empty(); } + + /// If the argument list has a single argument, which may be labeled or + /// unlabeled, returns its expression, or \c nullptr if this isn't a unary + /// argument list. + Expr *getUnaryExpr() const { return isUnary() ? getExpr(0) : nullptr; } + + /// If the argument list has a single unlabeled argument, returns its + /// expression, or \c nullptr if this isn't an unlabeled unary argument list. + Expr *getUnlabeledUnaryExpr() const { + return isUnlabeledUnary() ? getExpr(0) : nullptr; + } + + /// Retrieve an array of the argument expressions used in the argument list. + ArrayRef getArgExprs() const { return getExprsBuffer(); } + + /// Retrieve an array of the argument labels used in the argument list. + ArrayRef + getArgumentLabels(SmallVectorImpl &scratch) const; + + /// If the provided expression appears as one of the argument list's + /// arguments, returns its index. Otherwise returns \c None. By default this + /// will match against semantic sub-expressions, but that may be disabled by + /// passing \c false for \c allowSemantic. + Optional findArgumentExpr(Expr *expr, + bool allowSemantic = true) const; + + /// Creates a TupleExpr or ParenExpr that holds the argument exprs. A + /// ParenExpr will be returned for a single argument, otherwise a TupleExpr. + /// Don't use this function unless you actually need an AST transform. + Expr *packIntoImplicitTupleOrParen( + ASTContext &ctx, + llvm::function_ref getType = __Expr_getType) const; + + /// Avoid adding new usages of this. Creates a TupleType or ParenType + /// representing the types in the argument list. A ParenType will be returned + /// for a single argument, otherwise a TupleType. + Type composeTupleOrParenType( + ASTContext &ctx, + llvm::function_ref getType = __Expr_getType) const; + + /// Whether the argument list matches a given parameter list. This will return + /// \c false if the arity doesn't match, or any of the canonical types or + /// labels don't match. Note that this expects types to be present for the + /// arguments and parameters. + bool matches(ArrayRef params, + llvm::function_ref getType = __Expr_getType) const; + + /// Whether this argument list has the same arguments as another set of + /// arguments. + bool hasSameArgs(ArrayRef args) { + if (args.size() != size()) + return false; + return llvm::all_of(indices(args), + [&](auto i) { return get(i) == args[i]; }); + } + + /// When applying a solution to a constraint system, the type checker rewrites + /// argument lists of calls to insert default arguments and collect varargs. + /// Sometimes for diagnostics and IDE functionality we want to work on the + /// original arguments as written by the user; this performs the reverse + /// transformation. This has no effect on un-type-checked argument lists. + OriginalArguments getOriginalArguments() const; + + ArgumentList *walk(ASTWalker &walker); + + SWIFT_DEBUG_DUMP; + void dump(raw_ostream &OS, unsigned Indent = 0) const; +}; + +/// A type that represents the original set of arguments from an ArgumentList. +/// +/// This always has the same set of arguments as an un-type-checked argument +/// list. For a type-checked argument list, this strips default arguments, +/// expands variadic arguments, and re-orders trailing closures such that they +/// are as they appear at the call-site. +class OriginalArguments final { + friend class ArgumentList; + using Storage = SmallVector; + + Storage Args; + Optional FirstTrailingClosureIndex; + + explicit OriginalArguments(Storage args, Optional firstTrailing) + : Args(std::move(args)), FirstTrailingClosureIndex(firstTrailing) {} + +public: + using iterator = ArrayRef::iterator; + iterator begin() const { return Args.begin(); } + iterator end() const { return Args.end(); } + unsigned size() const { return Args.size(); } + bool empty() const { return Args.empty(); } + Argument operator[](unsigned idx) const { return Args[idx]; } + + /// Returns the array of arguments. + /// + /// Note this is marked \c & to try avoid memory bugs by ensuring it's not + /// called on an rvalue. + ArrayRef getArray() /*const*/ & { return Args; } + + /// Retrieve the index of the first trailing closure argument, or \c None if + /// there are no trailing closures. + Optional getFirstTrailingClosureIndex() const { + return FirstTrailingClosureIndex; + } + + /// The number of trailing closures in the argument list. + unsigned getNumTrailingClosures() const { + if (!getFirstTrailingClosureIndex()) + return 0; + return Args.size() - *getFirstTrailingClosureIndex(); + } + + /// Whether any unlabeled or labeled trailing closures are present. + bool hasAnyTrailingClosures() const { + return FirstTrailingClosureIndex.hasValue(); + } + + /// Whether the argument list has multiple trailing closures. + bool hasMultipleTrailingClosures() const { + return getNumTrailingClosures() > 1; + } + + /// Whether a given index is for an unlabeled trailing closure. + bool isUnlabeledTrailingClosureIndex(unsigned i) const { + return hasAnyTrailingClosures() && *getFirstTrailingClosureIndex() == i; + } + + /// Whether a given index is for a labeled trailing closure in an argument + /// list with multiple trailing closures. + bool isLabeledTrailingClosureIndex(unsigned i) const { + if (!hasAnyTrailingClosures()) + return false; + return i > *getFirstTrailingClosureIndex() && i < size(); + } + + /// Whether a given index is for a labeled or unlabeled trailing closure. + bool isTrailingClosureIndex(unsigned i) const { + if (!hasAnyTrailingClosures()) + return false; + return i >= *getFirstTrailingClosureIndex() && i < size(); + } + + /// Returns the range of arguments excluding any trailing closures. + /// + /// Note this is marked \c & to try avoid memory bugs by ensuring it's not + /// called on an rvalue. + ArrayRef getNonTrailingArgs() /*const*/ & { + return getArray().drop_back(getNumTrailingClosures()); + } + + /// Returns the range of trailing closure arguments. + /// + /// Note this is marked \c & to try avoid memory bugs by ensuring it's not + /// called on an rvalue. + ArrayRef getTrailingClosures() /*const*/ & { + return getArray().take_back(getNumTrailingClosures()); + } + + /// Retrieve the first trailing closure argument in the argument list, or + /// \c None if there are no trailing closures. + Optional getFirstTrailingClosure() const { + auto idx = getFirstTrailingClosureIndex(); + if (!idx.hasValue()) + return None; + return Args[*idx]; + } + + /// Retrieve the source range of any trailing closure arguments, or an empty + /// range if there are no trailing closures. + SourceRange getTrailingSourceRange() const { + if (!hasAnyTrailingClosures()) + return SourceRange(); + + auto elts = const_cast(this)->getTrailingClosures(); + return SourceRange(elts.front().getStartLoc(), elts.back().getEndLoc()); + } +}; + +} // end namespace swift + +#endif diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index eed46cbb9542f..9eeefc67e3697 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -72,6 +72,7 @@ DEF_COLOR(Identifier, GREEN, false) DEF_COLOR(Expr, MAGENTA, true) DEF_COLOR(ExprModifier, CYAN, false) DEF_COLOR(DeclModifier, CYAN, false) +DEF_COLOR(ArgModifier, CYAN, false) DEF_COLOR(ClosureModifier, CYAN, false) DEF_COLOR(TypeField, CYAN, false) DEF_COLOR(Location, CYAN, false) @@ -2503,6 +2504,63 @@ class PrintExpr : public ExprVisitor { } } + void printArgument(const Argument &arg) { + OS.indent(Indent); + PrintWithColorRAII(OS, ParenthesisColor) << '('; + PrintWithColorRAII(OS, ExprColor) << "argument"; + + auto label = arg.getLabel(); + if (!label.empty()) { + PrintWithColorRAII(OS, ArgumentsColor) << " label="; + PrintWithColorRAII(OS, ArgumentsColor) << label.str(); + } + if (arg.isInOut()) + PrintWithColorRAII(OS, ArgModifierColor) << " inout"; + + OS << '\n'; + printRec(arg.getExpr()); + PrintWithColorRAII(OS, ParenthesisColor) << ')'; + } + + void printArgumentList(const ArgumentList *argList, bool indent = true) { + if (indent) + Indent += 2; + + OS.indent(Indent); + PrintWithColorRAII(OS, ParenthesisColor) << '('; + PrintWithColorRAII(OS, ExprColor) << "argument_list"; + + if (argList->isImplicit()) + PrintWithColorRAII(OS, ArgModifierColor) << " implicit"; + + if (argList->hasAnyArgumentLabels()) { + PrintWithColorRAII(OS, ArgumentsColor) << " labels="; + for (auto arg : *argList) { + auto label = arg.getLabel(); + PrintWithColorRAII(OS, ArgumentsColor) + << (label.empty() ? "_" : label.str()) << ":"; + } + } + + Indent += 2; + for (auto arg : *argList) { + OS << '\n'; + printArgument(arg); + } + Indent -= 2; + + // If we printed any args, then print the closing ')' on a new line, + // otherwise print inline with the '(argument_list'. + if (!argList->empty()) { + OS << '\n'; + OS.indent(Indent); + } + PrintWithColorRAII(OS, ParenthesisColor) << ')'; + + if (indent) + Indent -= 2; + } + void printApplyExpr(ApplyExpr *E, const char *NodeName) { printCommon(E, NodeName); if (E->isThrowsSet()) { @@ -2857,6 +2915,21 @@ void Expr::print(ASTPrinter &Printer, const PrintOptions &Opts) const { Printer << OS.str(); } +void ArgumentList::dump() const { + dump(llvm::errs(), 0); +} + +void ArgumentList::dump(raw_ostream &OS, unsigned Indent) const { + auto getTypeOfExpr = [](Expr *E) -> Type { return E->getType(); }; + auto getTypeOfKeyPathComponent = [](KeyPathExpr *E, unsigned index) -> Type { + return E->getComponents()[index].getComponentType(); + }; + PrintExpr printer(OS, getTypeOfExpr, /*getTypeOfTypeRepr*/ nullptr, + getTypeOfKeyPathComponent, Indent); + printer.printArgumentList(this, /*indent*/ false); + llvm::errs() << '\n'; +} + //===----------------------------------------------------------------------===// // Printing for TypeRepr and all subclasses. //===----------------------------------------------------------------------===// diff --git a/lib/AST/ASTWalker.cpp b/lib/AST/ASTWalker.cpp index a2adbee92cd57..0780393b9f517 100644 --- a/lib/AST/ASTWalker.cpp +++ b/lib/AST/ASTWalker.cpp @@ -1367,6 +1367,19 @@ class Traversal : public ASTVisitorgetExpr(Idx)); + if (!E) return nullptr; + ArgList->setExpr(Idx, E); + } + return Walker.walkToArgumentListPost(Pre.second); + } }; } // end anonymous namespace @@ -1912,3 +1925,7 @@ bool Decl::walk(ASTWalker &walker) { bool GenericParamList::walk(ASTWalker &walker) { return Traversal(walker).doIt(this); } + +ArgumentList *ArgumentList::walk(ASTWalker &walker) { + return Traversal(walker).doIt(this); +} diff --git a/lib/AST/ArgumentList.cpp b/lib/AST/ArgumentList.cpp new file mode 100644 index 0000000000000..b06729bab7f57 --- /dev/null +++ b/lib/AST/ArgumentList.cpp @@ -0,0 +1,451 @@ +//===--- ArgumentList.cpp - Function and subscript argument lists -*- C++ -*==// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2021 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +// +// This file defines the logic for the Argument and ArgumentList classes. +// +//===----------------------------------------------------------------------===// + +#include "swift/AST/ArgumentList.h" +#include "swift/AST/ASTContext.h" +#include "swift/AST/Expr.h" +#include "swift/AST/ParameterList.h" + +using namespace swift; + +Type swift::__Expr_getType(Expr *E) { return E->getType(); } + +SourceRange Argument::getSourceRange() const { + auto labelLoc = getLabelLoc(); + if (labelLoc.isInvalid()) + return getExpr()->getSourceRange(); + + auto exprEndLoc = getExpr()->getEndLoc(); + if (exprEndLoc.isInvalid()) + return labelLoc; + + return SourceRange(labelLoc, exprEndLoc); +} + +bool Argument::isInOut() const { + return ArgExpr->isSemanticallyInOutExpr(); +} + +/// Attempt to extract the underlying array expr from an implicit variadic +/// expansion expr. +static ArrayExpr *getVariadicArrayFrom(const Expr *E) { + auto *vargExpr = dyn_cast(E); + if (!vargExpr || !vargExpr->isImplicit()) + return nullptr; + auto *vargArray = dyn_cast(vargExpr->getSubExpr()); + if (!vargArray || !vargArray->isImplicit()) + return nullptr; + return vargArray; +} + +namespace { +struct TrailingClosureInfo { + Optional ArgIndex; + bool HasMultiple; + + TrailingClosureInfo() : HasMultiple(false) {} + TrailingClosureInfo(Optional argIndex, bool hasMultiple) + : ArgIndex(argIndex), HasMultiple(hasMultiple) {} +}; +} // end anonymous namespace + +static bool argExprHasValidSourceRange(const Expr *expr) { + // Default arguments may have source info, but it's not a valid argument + // source range. + return !isa(expr) && expr->getSourceRange().isValid(); +} + +/// Whether a given argument expression in a non-implicit arg list is either a +/// trailing closure, or is a variadic expansion containing a trailing closure. +static bool isTrailingArgOfNonImplicitArgList(const Expr *argExpr, + SourceLoc rparenLoc) { + // If the argument has no valid source info, we can't count it as a trailing + // closure. + if (!argExprHasValidSourceRange(argExpr)) + return false; + + // If the right paren loc is invalid, this is something like 'fn {}'. + if (rparenLoc.isInvalid()) + return true; + + // Otherwise the argument must come after the r-paren. Note we check the end + // loc of the argument to match against variadic args that contain both + // non-trailing and trailing closures. + return rparenLoc.getOpaquePointerValue() < + argExpr->getEndLoc().getOpaquePointerValue(); +} + +static TrailingClosureInfo +computeTrailingClosureInfo(ArrayRef args, SourceLoc rparenLoc, + bool isImplicit) { + // Implicit argument lists never have trailing closures. + if (isImplicit) + return {}; + + auto iter = llvm::find_if(args, [&](const auto &arg) { + return isTrailingArgOfNonImplicitArgList(arg.getExpr(), rparenLoc); + }); + if (iter == args.end()) { + assert(rparenLoc.isValid() && + "Explicit argument list with no parens and no trailing closures?"); + return {}; + } + auto argIdx = iter - args.begin(); + + // For the variadic case we need to dig into the variadic array to figure out + // if we have multiple trailing closures. + if (auto *array = getVariadicArrayFrom(args[argIdx].getExpr())) { + auto numTrailing = llvm::count_if(array->getElements(), [&](auto *expr) { + return isTrailingArgOfNonImplicitArgList(expr, rparenLoc); + }); + assert(numTrailing > 0 && "Variadic args didn't have trailing closure?"); + if (numTrailing > 1) + return TrailingClosureInfo(argIdx, /*HasMultiple*/ true); + } + + // Otherwise, look for the next trailing closure if any. + auto restOfArgs = args.drop_front(argIdx + 1); + auto nextIter = llvm::find_if(restOfArgs, [&](const auto &arg) { + return isTrailingArgOfNonImplicitArgList(arg.getExpr(), rparenLoc); + }); + return TrailingClosureInfo(argIdx, /*HasMultiple*/ nextIter != args.end()); +} + +ArgumentList *ArgumentList::create(ASTContext &ctx, SourceLoc lParenLoc, + ArrayRef args, SourceLoc rParenLoc, + Optional firstTrailingClosureIndex, + bool hasMultipleTrailingClosures, + bool isImplicit, AllocationArena arena) { +#ifndef NDEBUG + auto trailingInfo = computeTrailingClosureInfo(args, rParenLoc, isImplicit); + assert(trailingInfo.ArgIndex == firstTrailingClosureIndex); + assert(trailingInfo.HasMultiple == hasMultipleTrailingClosures); +#endif + + assert(lParenLoc.isValid() == rParenLoc.isValid()); + SmallVector exprs; + SmallVector labels; + SmallVector labelLocs; + + bool hasLabels = false; + bool hasLabelLocs = false; + for (auto &arg : args) { + exprs.push_back(arg.getExpr()); + + hasLabels |= !arg.getLabel().empty(); + labels.push_back(arg.getLabel()); + + hasLabelLocs |= arg.getLabelLoc().isValid(); + labelLocs.push_back(arg.getLabelLoc()); + } + if (!hasLabels) + labels.clear(); + if (!hasLabelLocs) + labelLocs.clear(); + + auto numBytes = totalSizeToAlloc( + exprs.size(), labels.size(), labelLocs.size()); + auto *mem = ctx.Allocate(numBytes, alignof(ArgumentList), arena); + auto *argList = new (mem) ArgumentList( + lParenLoc, rParenLoc, args.size(), firstTrailingClosureIndex, + hasMultipleTrailingClosures, isImplicit, hasLabels, hasLabelLocs); + + std::uninitialized_copy(exprs.begin(), exprs.end(), + argList->getExprsBuffer().begin()); + if (hasLabels) { + std::uninitialized_copy(labels.begin(), labels.end(), + argList->getLabelsBuffer().begin()); + } + if (hasLabelLocs) { + std::uninitialized_copy(labelLocs.begin(), labelLocs.end(), + argList->getLabelLocsBuffer().begin()); + } + return argList; +} + +ArgumentList *ArgumentList::create(ASTContext &ctx, SourceLoc lParenLoc, + ArrayRef args, SourceLoc rParenLoc, + bool isImplicit, AllocationArena arena) { + auto trailingClosureInfo = + computeTrailingClosureInfo(args, rParenLoc, isImplicit); + return ArgumentList::create( + ctx, lParenLoc, args, rParenLoc, trailingClosureInfo.ArgIndex, + trailingClosureInfo.HasMultiple, isImplicit, arena); +} + +ArgumentList *ArgumentList::createImplicit(ASTContext &ctx, SourceLoc lParenLoc, + ArrayRef args, + SourceLoc rParenLoc, + AllocationArena arena) { + return create(ctx, lParenLoc, args, rParenLoc, /*implicit*/ true, arena); +} + +ArgumentList *ArgumentList::createImplicit(ASTContext &ctx, + ArrayRef args, + AllocationArena arena) { + return createImplicit(ctx, SourceLoc(), args, SourceLoc()); +} + +ArgumentList *ArgumentList::forImplicitSingle(ASTContext &ctx, Identifier label, + Expr *arg) { + return createImplicit(ctx, {Argument(SourceLoc(), label, arg)}); +} + +ArgumentList *ArgumentList::forImplicitUnlabeled(ASTContext &ctx, + ArrayRef argExprs) { + SmallVector args; + for (auto *argExpr : argExprs) + args.push_back(Argument::unlabeled(argExpr)); + return createImplicit(ctx, args); +} + +ArgumentList *ArgumentList::forImplicitCallTo(DeclNameRef fnNameRef, + ArrayRef argExprs, + ASTContext &ctx) { + auto labels = fnNameRef.getArgumentNames(); + assert(labels.size() == argExprs.size()); + + SmallVector args; + for (auto idx : indices(argExprs)) + args.emplace_back(SourceLoc(), labels[idx], argExprs[idx]); + + return createImplicit(ctx, args); +} + +ArgumentList *ArgumentList::forImplicitCallTo(ParameterList *params, + ArrayRef argExprs, + ASTContext &ctx) { + assert(params->size() == argExprs.size()); + SmallVector args; + for (auto idx : indices(argExprs)) { + auto *param = params->get(idx); + assert(param->isInOut() == argExprs[idx]->isSemanticallyInOutExpr()); + args.emplace_back(SourceLoc(), param->getArgumentName(), argExprs[idx]); + } + return createImplicit(ctx, args); +} + +SourceLoc ArgumentList::getLoc() const { + // If we have an unlabeled unary arg, return the start loc of the expr. This + // preserves the behavior of when such argument lists were represented by + // ParenExprs. + if (auto *unary = getUnlabeledUnaryExpr()) + return unary->getStartLoc(); + return getStartLoc(); +} + +SourceRange ArgumentList::getSourceRange() const { + auto start = LParenLoc; + if (start.isInvalid()) { + // Scan forward for the first valid source loc. + for (auto arg : *this) { + start = arg.getStartLoc(); + if (start.isValid()) + break; + } + } + auto end = RParenLoc; + if (hasAnyTrailingClosures()) { + // If we have trailing closures, the end loc is the end loc of the last + // trailing closure. + for (auto arg : llvm::reverse(*this)) { + if (isTrailingArgOfNonImplicitArgList(arg.getExpr(), RParenLoc)) { + end = arg.getEndLoc(); + break; + } + } + } else if (RParenLoc.isInvalid()) { + // If we don't have trailing closures and the r-paren loc is invalid, this + // is an implicit argument list. Take the last valid argument loc. + assert(isImplicit()); + for (auto arg : llvm::reverse(*this)) { + if (argExprHasValidSourceRange(arg.getExpr())) { + end = arg.getEndLoc(); + break; + } + } + } + if (start.isInvalid() || end.isInvalid()) + return SourceRange(); + + return SourceRange(start, end); +} + +ArrayRef +ArgumentList::getArgumentLabels(SmallVectorImpl &scratch) const { + assert(scratch.empty()); + if (HasLabels) + return getLabelsBuffer(); + scratch.append(size(), Identifier()); + return scratch; +} + +Optional ArgumentList::findArgumentExpr(Expr *expr, + bool allowSemantic) const { + if (allowSemantic) + expr = expr->getSemanticsProvidingExpr(); + for (auto idx : indices(*this)) { + auto *argExpr = getExpr(idx); + if (allowSemantic) + argExpr = argExpr->getSemanticsProvidingExpr(); + + if (expr == argExpr) + return idx; + } + return None; +} + +Expr *ArgumentList::packIntoImplicitTupleOrParen( + ASTContext &ctx, llvm::function_ref getType) const { + assert(!hasAnyInOutArgs() && "Cannot construct bare tuple/paren with inout"); + if (auto *unary = getUnlabeledUnaryExpr()) { + auto *paren = new (ctx) ParenExpr(SourceLoc(), unary, SourceLoc()); + if (auto ty = getType(unary)) + paren->setType(ParenType::get(ctx, ty)); + paren->setImplicit(); + return paren; + } + + SmallVector argExprs; + SmallVector argLabels; + SmallVector tupleEltTypes; + + for (auto arg : *this) { + auto *argExpr = arg.getExpr(); + argExprs.push_back(argExpr); + argLabels.push_back(arg.getLabel()); + if (auto ty = getType(argExpr)) + tupleEltTypes.emplace_back(ty, arg.getLabel()); + } + assert(tupleEltTypes.empty() || tupleEltTypes.size() == argExprs.size()); + + auto *tuple = TupleExpr::createImplicit(ctx, argExprs, argLabels); + if (empty() || !tupleEltTypes.empty()) + tuple->setType(TupleType::get(tupleEltTypes, ctx)); + + return tuple; +} + +Type ArgumentList::composeTupleOrParenType( + ASTContext &ctx, llvm::function_ref getType) const { + if (auto *unary = getUnlabeledUnaryExpr()) { + auto ty = getType(unary); + assert(ty); + ParameterTypeFlags flags; + if (get(0).isInOut()) { + ty = ty->getInOutObjectType(); + flags = flags.withInOut(true); + } + return ParenType::get(ctx, ty, flags); + } + SmallVector elts; + for (auto arg : *this) { + auto ty = getType(arg.getExpr()); + assert(ty); + ParameterTypeFlags flags; + if (arg.isInOut()) { + ty = ty->getInOutObjectType(); + flags = flags.withInOut(true); + } + elts.emplace_back(ty, arg.getLabel(), flags); + } + return TupleType::get(elts, ctx); +} + +bool ArgumentList::matches(ArrayRef params, + llvm::function_ref getType) const { + if (size() != params.size()) + return false; + + for (auto i : indices(*this)) { + auto arg = get(i); + auto ¶m = params[i]; + + if (arg.getLabel() != param.getLabel()) + return false; + + if (arg.isInOut() != param.isInOut()) + return false; + + auto argTy = getType(arg.getExpr()); + assert(argTy && "Expected type for argument"); + auto paramTy = param.getParameterType(); + assert(paramTy && "Expected a type for param"); + + if (arg.isInOut()) + argTy = argTy->getInOutObjectType(); + + if (!argTy->isEqual(paramTy)) + return false; + } + return true; +} + +OriginalArguments ArgumentList::getOriginalArguments() const { + // We need to sort out the trailing closures separately to handle cases like: + // + // func foo(fn: () -> Void, x: Int = 0) {} + // foo(x: 0) {} + // + // where we currently allow the re-ordering of a trailing closure argument + // such that it appears as the first argument in the type-checked AST. To + // remedy this, separate out the trailing closures and make sure to append + // them after the regular arguments. + OriginalArguments::Storage newArgs; + SmallVector trailingClosures; + + auto addArg = [&](Argument arg) { + if (hasAnyTrailingClosures() && + isTrailingArgOfNonImplicitArgList(arg.getExpr(), getRParenLoc())) { + trailingClosures.push_back(arg); + return; + } + newArgs.push_back(arg); + }; + for (auto arg : *this) { + auto *expr = arg.getExpr(); + if (isa(expr)) + continue; + + if (auto *vargArray = getVariadicArrayFrom(expr)) { + auto elts = vargArray->getElements(); + for (auto idx : indices(elts)) { + // The first element in a variadic expansion takes the argument label, + // the rest are unlabeled. + if (idx == 0) { + addArg(Argument(arg.getLabelLoc(), arg.getLabel(), elts[idx])); + } else { + addArg(Argument::unlabeled(elts[idx])); + } + } + continue; + } + addArg(arg); + } + Optional trailingClosureIdx; + if (!trailingClosures.empty()) + trailingClosureIdx = newArgs.size(); + + newArgs.append(trailingClosures.begin(), trailingClosures.end()); + auto origArgs = OriginalArguments(std::move(newArgs), trailingClosureIdx); +#ifndef NDEBUG + auto trailingInfo = computeTrailingClosureInfo(origArgs.getArray(), + getRParenLoc(), isImplicit()); + assert(trailingInfo.ArgIndex == trailingClosureIdx); + assert(trailingInfo.HasMultiple == origArgs.hasMultipleTrailingClosures()); +#endif + return origArgs; +} diff --git a/lib/AST/CMakeLists.txt b/lib/AST/CMakeLists.txt index dca9b2f4a351b..dc801bd89cba1 100644 --- a/lib/AST/CMakeLists.txt +++ b/lib/AST/CMakeLists.txt @@ -13,6 +13,7 @@ add_swift_host_library(swiftAST STATIC AbstractSourceFileDepGraphFactory.cpp AccessNotes.cpp AccessRequests.cpp + ArgumentList.cpp ASTContext.cpp ASTDemangler.cpp ASTDumper.cpp From 01a082a0582092e7ab5d763eb08618b03e3524ad Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Wed, 1 Sep 2021 18:40:23 +0100 Subject: [PATCH 02/14] [AST] Adopt ArgumentList Switch out the representation of argument lists in various AST nodes with ArgumentList. --- include/swift/AST/Attr.h | 36 +- include/swift/AST/Expr.h | 650 ++++--------------- include/swift/AST/TrailingCallArguments.h | 128 ---- include/swift/AST/Types.h | 9 +- lib/AST/ASTContext.cpp | 39 +- lib/AST/ASTDumper.cpp | 33 +- lib/AST/ASTScopeCreation.cpp | 6 +- lib/AST/ASTVerifier.cpp | 159 ++--- lib/AST/ASTWalker.cpp | 71 +-- lib/AST/Attr.cpp | 59 +- lib/AST/Decl.cpp | 10 +- lib/AST/Expr.cpp | 724 ++++------------------ test/Concurrency/async_main.swift | 9 +- test/Frontend/dump-parse.swift | 14 +- test/IDE/expr_type.swift | 10 +- test/IDE/range_info_expr.swift | 2 +- test/Sema/property_wrappers.swift | 21 +- test/Sema/type_eraser.swift | 52 +- test/SourceKit/ExpressionType/basic.swift | 1 - 19 files changed, 443 insertions(+), 1590 deletions(-) delete mode 100644 include/swift/AST/TrailingCallArguments.h diff --git a/include/swift/AST/Attr.h b/include/swift/AST/Attr.h index 891e7fd8a9301..fb329b36eb1e0 100644 --- a/include/swift/AST/Attr.h +++ b/include/swift/AST/Attr.h @@ -37,7 +37,6 @@ #include "swift/AST/PlatformKind.h" #include "swift/AST/Requirement.h" #include "swift/AST/StorageImpl.h" -#include "swift/AST/TrailingCallArguments.h" #include "llvm/ADT/iterator_range.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" @@ -46,6 +45,7 @@ #include "llvm/Support/VersionTuple.h" namespace swift { +class ArgumentList; class ASTPrinter; class ASTContext; struct PrintOptions; @@ -1530,48 +1530,40 @@ class ClangImporterSynthesizedTypeAttr : public DeclAttribute { }; /// Defines a custom attribute. -class CustomAttr final : public DeclAttribute, - public TrailingCallArguments { +class CustomAttr final : public DeclAttribute { TypeExpr *typeExpr; - Expr *arg; + ArgumentList *argList; PatternBindingInitializer *initContext; Expr *semanticInit = nullptr; - unsigned hasArgLabelLocs : 1; - unsigned numArgLabels : 16; mutable unsigned isArgUnsafeBit : 1; CustomAttr(SourceLoc atLoc, SourceRange range, TypeExpr *type, - PatternBindingInitializer *initContext, Expr *arg, - ArrayRef argLabels, ArrayRef argLabelLocs, + PatternBindingInitializer *initContext, ArgumentList *argList, bool implicit); public: static CustomAttr *create(ASTContext &ctx, SourceLoc atLoc, TypeExpr *type, bool implicit = false) { - return create(ctx, atLoc, type, false, nullptr, SourceLoc(), { }, { }, { }, - SourceLoc(), implicit); + return create(ctx, atLoc, type, /*initContext*/ nullptr, + /*argList*/ nullptr, implicit); } static CustomAttr *create(ASTContext &ctx, SourceLoc atLoc, TypeExpr *type, - bool hasInitializer, PatternBindingInitializer *initContext, - SourceLoc lParenLoc, - ArrayRef args, - ArrayRef argLabels, - ArrayRef argLabelLocs, - SourceLoc rParenLoc, - bool implicit = false); - - unsigned getNumArguments() const { return numArgLabels; } - bool hasArgumentLabelLocs() const { return hasArgLabelLocs; } + ArgumentList *argList, bool implicit = false); TypeExpr *getTypeExpr() const { return typeExpr; } TypeRepr *getTypeRepr() const; Type getType() const; - Expr *getArg() const { return arg; } - void setArg(Expr *newArg) { arg = newArg; } + /// Whether the attribute has any arguments. + bool hasArgs() const { return argList != nullptr; } + + /// The argument list of the attribute if it has any arguments, \c nullptr + /// otherwise. + ArgumentList *getArgs() const { return argList; } + void setArgs(ArgumentList *newArgs) { argList = newArgs; } /// Determine whether the argument is '(unsafe)', a special subexpression /// used by global actors. diff --git a/include/swift/AST/Expr.h b/include/swift/AST/Expr.h index 817b3f94ec7d1..ff7aca619307f 100644 --- a/include/swift/AST/Expr.h +++ b/include/swift/AST/Expr.h @@ -17,6 +17,7 @@ #ifndef SWIFT_AST_EXPR_H #define SWIFT_AST_EXPR_H +#include "swift/AST/ArgumentList.h" #include "swift/AST/Attr.h" #include "swift/AST/CaptureInfo.h" #include "swift/AST/ConcreteDeclRef.h" @@ -24,7 +25,6 @@ #include "swift/AST/DeclNameLoc.h" #include "swift/AST/FunctionRefKind.h" #include "swift/AST/ProtocolConformanceRef.h" -#include "swift/AST/TrailingCallArguments.h" #include "swift/AST/TypeAlignments.h" #include "swift/AST/Availability.h" #include "swift/Basic/Debug.h" @@ -67,18 +67,6 @@ namespace swift { class KeyPathExpr; class CaptureListExpr; -struct TrailingClosure { - Identifier Label; - SourceLoc LabelLoc; - Expr *ClosureExpr; - - TrailingClosure(Expr *closure) - : TrailingClosure(Identifier(), SourceLoc(), closure) {} - - TrailingClosure(Identifier label, SourceLoc labelLoc, Expr *closure) - : Label(label), LabelLoc(labelLoc), ClosureExpr(closure) {} -}; - enum class ExprKind : uint8_t { #define EXPR(Id, Parent) Id, #define LAST_EXPR(Id) Last_Expr = Id, @@ -173,10 +161,7 @@ class alignas(8) Expr : public ASTAllocated { ); SWIFT_INLINE_BITFIELD_EMPTY(DynamicLookupExpr, LookupExpr); - SWIFT_INLINE_BITFIELD(ParenExpr, IdentityExpr, 1, - /// Whether we're wrapping a trailing closure expression. - HasTrailingClosure : 1 - ); + SWIFT_INLINE_BITFIELD_EMPTY(ParenExpr, IdentityExpr); SWIFT_INLINE_BITFIELD(NumberLiteralExpr, LiteralExpr, 1+1, IsNegative : 1, @@ -231,28 +216,11 @@ class alignas(8) Expr : public ASTAllocated { FunctionRefKind : 2 ); - SWIFT_INLINE_BITFIELD_FULL(SubscriptExpr, LookupExpr, 2+1+1+16, - Semantics : 2, // an AccessSemantics - /// Whether the SubscriptExpr also has source locations for the argument - /// label. - HasArgLabelLocs : 1, - /// Whether the last argument is a trailing closure. - HasTrailingClosure : 1, - : NumPadBits, - /// # of argument labels stored after the SubscriptExpr. - NumArgLabels : 16 + SWIFT_INLINE_BITFIELD_FULL(SubscriptExpr, LookupExpr, 2, + Semantics : 2 // an AccessSemantics ); - SWIFT_INLINE_BITFIELD_FULL(DynamicSubscriptExpr, DynamicLookupExpr, 1+1+16, - /// Whether the DynamicSubscriptExpr also has source locations for the - /// argument label. - HasArgLabelLocs : 1, - /// Whether the last argument is a trailing closure. - HasTrailingClosure : 1, - : NumPadBits, - /// # of argument labels stored after the DynamicSubscriptExpr. - NumArgLabels : 16 - ); + SWIFT_INLINE_BITFIELD_EMPTY(DynamicSubscriptExpr, DynamicLookupExpr); SWIFT_INLINE_BITFIELD_FULL(UnresolvedMemberExpr, Expr, 2, FunctionRefKind : 2 @@ -271,16 +239,8 @@ class alignas(8) Expr : public ASTAllocated { StringEncoding : 1 ); - SWIFT_INLINE_BITFIELD_FULL(ObjectLiteralExpr, LiteralExpr, 3+1+1+16, - LitKind : 3, - /// Whether the ObjectLiteralExpr also has source locations for the argument - /// label. - HasArgLabelLocs : 1, - /// Whether the last argument is a trailing closure. - HasTrailingClosure : 1, - : NumPadBits, - /// # of argument labels stored after the ObjectLiteralExpr. - NumArgLabels : 16 + SWIFT_INLINE_BITFIELD_FULL(ObjectLiteralExpr, LiteralExpr, 3, + LitKind : 3 ); SWIFT_INLINE_BITFIELD(AbstractClosureExpr, Expr, (16-NumExprBits)+16, @@ -355,15 +315,7 @@ class alignas(8) Expr : public ASTAllocated { NoAsync : 1 ); - SWIFT_INLINE_BITFIELD_FULL(CallExpr, ApplyExpr, 1+1+16, - /// Whether the CallExpr also has source locations for the argument label. - HasArgLabelLocs : 1, - /// Whether the last argument is a trailing closure. - HasTrailingClosure : 1, - : NumPadBits, - /// # of argument labels stored after the CallExpr. - NumArgLabels : 16 - ); + SWIFT_INLINE_BITFIELD_EMPTY(CallExpr, ApplyExpr); enum { NumCheckedCastKindBits = 4 }; SWIFT_INLINE_BITFIELD(CheckedCastExpr, Expr, NumCheckedCastKindBits, @@ -548,10 +500,9 @@ class alignas(8) Expr : public ASTAllocated { bool isSelfExprOf(const AbstractFunctionDecl *AFD, bool sameBase = false) const; - /// Given that this is a packed argument expression of the sort that - /// would be produced from packSingleArgument, return the index of the - /// unlabeled trailing closure, if there is one. - Optional getUnlabeledTrailingClosureIndexOfPackedArgument() const; + /// If the expression has an argument list, returns it. Otherwise, returns + /// \c nullptr. + ArgumentList *getArgs() const; /// Produce a mapping from each subexpression to its parent /// expression, with the provided expression serving as the root of @@ -1081,9 +1032,7 @@ class MagicIdentifierLiteralExpr : public BuiltinLiteralExpr { // '#colorLiteral(red: 1, blue: 0, green: 0, alpha: 1)' with a name and a list // argument. The components of the list argument are meant to be themselves // constant. -class ObjectLiteralExpr final - : public LiteralExpr, - public TrailingCallArguments { +class ObjectLiteralExpr final : public LiteralExpr { public: /// The kind of object literal. enum LiteralKind : unsigned { @@ -1092,63 +1041,28 @@ class ObjectLiteralExpr final }; private: - Expr *Arg; + ArgumentList *ArgList; SourceLoc PoundLoc; - ObjectLiteralExpr(SourceLoc PoundLoc, LiteralKind LitKind, - Expr *Arg, - ArrayRef argLabels, - ArrayRef argLabelLocs, - bool hasTrailingClosure, + ObjectLiteralExpr(SourceLoc poundLoc, LiteralKind litKind, ArgumentList *args, bool implicit); public: - /// Create a new object literal expression. - /// - /// Note: prefer to use the second entry point, which separates out - /// arguments/labels/etc. - static ObjectLiteralExpr *create(ASTContext &ctx, SourceLoc poundLoc, - LiteralKind kind, Expr *arg, bool implicit, - llvm::function_ref getType); - /// Create a new object literal expression. static ObjectLiteralExpr *create(ASTContext &ctx, SourceLoc poundLoc, - LiteralKind kind, - SourceLoc lParenLoc, - ArrayRef args, - ArrayRef argLabels, - ArrayRef argLabelLocs, - SourceLoc rParenLoc, - ArrayRef trailingClosures, + LiteralKind kind, ArgumentList *args, bool implicit); LiteralKind getLiteralKind() const { return static_cast(Bits.ObjectLiteralExpr.LitKind); } - Expr *getArg() const { return Arg; } - void setArg(Expr *arg) { Arg = arg; } - - unsigned getNumArguments() const { - return Bits.ObjectLiteralExpr.NumArgLabels; - } - bool hasArgumentLabelLocs() const { - return Bits.ObjectLiteralExpr.HasArgLabelLocs; - } - - /// Whether this call with written with a trailing closure. - bool hasTrailingClosure() const { - return Bits.ObjectLiteralExpr.HasTrailingClosure; - } - - /// Return the index of the unlabeled trailing closure argument. - Optional getUnlabeledTrailingClosureIndex() const { - return getArg()->getUnlabeledTrailingClosureIndexOfPackedArgument(); - } + ArgumentList *getArgs() const { return ArgList; } + void setArgs(ArgumentList *newArgs) { ArgList = newArgs; } SourceLoc getSourceLoc() const { return PoundLoc; } - SourceRange getSourceRange() const { - return SourceRange(PoundLoc, Arg->getEndLoc()); + SourceRange getSourceRange() const { + return SourceRange(PoundLoc, ArgList->getEndLoc()); } /// Return the string form of the literal name. @@ -1812,57 +1726,24 @@ class DynamicMemberRefExpr : public DynamicLookupExpr { /// var x : AnyObject = /// print(x[27]! // x[27] has type String? /// \endcode -class DynamicSubscriptExpr final - : public DynamicLookupExpr, - public TrailingCallArguments { - friend TrailingCallArguments; +class DynamicSubscriptExpr final : public DynamicLookupExpr { + ArgumentList *ArgList; - Expr *Index; - - DynamicSubscriptExpr(Expr *base, Expr *index, ArrayRef argLabels, - ArrayRef argLabelLocs, - bool hasTrailingClosure, ConcreteDeclRef member, - bool implicit); + DynamicSubscriptExpr(Expr *base, ArgumentList *argList, + ConcreteDeclRef member, bool implicit); public: - /// Create a dynamic subscript. - /// - /// Note: do not create new callers to this entry point; use the entry point - /// that takes separate index arguments. - static DynamicSubscriptExpr *create( - ASTContext &ctx, Expr *base, Expr *index, ConcreteDeclRef decl, - bool implicit, - llvm::function_ref getType = [](Expr *E) -> Type { - return E->getType(); - }); - - /// getIndex - Retrieve the index of the subscript expression, i.e., the - /// "offset" into the base value. - Expr *getIndex() const { return Index; } - void setIndex(Expr *E) { Index = E; } + static DynamicSubscriptExpr *create(ASTContext &ctx, Expr *base, + ArgumentList *argList, + ConcreteDeclRef member, bool implicit); - unsigned getNumArguments() const { - return Bits.DynamicSubscriptExpr.NumArgLabels; - } - - bool hasArgumentLabelLocs() const { - return Bits.DynamicSubscriptExpr.HasArgLabelLocs; - } - - /// Whether this call with written with a trailing closure. - bool hasTrailingClosure() const { - return Bits.DynamicSubscriptExpr.HasTrailingClosure; - } + ArgumentList *getArgs() const { return ArgList; } + void setArgs(ArgumentList *newArgs) { ArgList = newArgs; } - /// Return the index of the unlabeled trailing closure argument. - Optional getUnlabeledTrailingClosureIndex() const { - return Index->getUnlabeledTrailingClosureIndexOfPackedArgument(); - } - - SourceLoc getLoc() const { return Index->getStartLoc(); } + SourceLoc getLoc() const { return getArgs()->getStartLoc(); } SourceLoc getStartLoc() const { return getBase()->getStartLoc(); } - SourceLoc getEndLoc() const { return Index->getEndLoc(); } + SourceLoc getEndLoc() const { return getArgs()->getEndLoc(); } static bool classof(const Expr *E) { return E->getKind() == ExprKind::DynamicSubscript; @@ -2060,12 +1941,9 @@ class ParenExpr : public IdentityExpr { SourceLoc LParenLoc, RParenLoc; public: - ParenExpr(SourceLoc lploc, Expr *subExpr, SourceLoc rploc, - bool hasTrailingClosure, - Type ty = Type()) - : IdentityExpr(ExprKind::Paren, subExpr, ty), - LParenLoc(lploc), RParenLoc(rploc) { - Bits.ParenExpr.HasTrailingClosure = hasTrailingClosure; + ParenExpr(SourceLoc lploc, Expr *subExpr, SourceLoc rploc, Type ty = Type()) + : IdentityExpr(ExprKind::Paren, subExpr, ty), LParenLoc(lploc), + RParenLoc(rploc) { assert(lploc.isValid() == rploc.isValid() && "Mismatched source location information"); } @@ -2081,21 +1959,11 @@ class ParenExpr : public IdentityExpr { return (LParenLoc.isInvalid() ? getSubExpr()->getStartLoc() : LParenLoc); } SourceLoc getEndLoc() const { - // If we have a trailing closure, our end point is the end of the - // trailing closure. - if (RParenLoc.isInvalid() || Bits.ParenExpr.HasTrailingClosure) + if (RParenLoc.isInvalid()) return getSubExpr()->getEndLoc(); return RParenLoc; } - /// Whether this expression has a trailing closure as its argument. - bool hasTrailingClosure() const { return Bits.ParenExpr.HasTrailingClosure; } - - Optional - getUnlabeledTrailingClosureIndexOfPackedArgument() const { - return hasTrailingClosure() ? Optional(0) : None; - } - static bool classof(const Expr *E) { return E->getKind() == ExprKind::Paren; } }; @@ -2149,10 +2017,8 @@ class AwaitExpr final : public IdentityExpr { } }; - -/// TupleExpr - Parenthesized expressions like '(a: x+x)' and '(x, y, 4)'. Also -/// used to represent the operands to a binary operator. Note that -/// expressions like '(4)' are represented with a ParenExpr. +/// TupleExpr - Parenthesized expressions like '(a: x+x)' and '(x, y, 4)'. Note +/// that expressions like '(4)' are represented with a ParenExpr. class TupleExpr final : public Expr, private llvm::TrailingObjects { friend TrailingObjects; @@ -2160,8 +2026,6 @@ class TupleExpr final : public Expr, SourceLoc LParenLoc; SourceLoc RParenLoc; - Optional FirstTrailingArgumentAt; - size_t numTrailingObjects(OverloadToken) const { return getNumElements(); } @@ -2189,10 +2053,8 @@ class TupleExpr final : public Expr, } TupleExpr(SourceLoc LParenLoc, SourceLoc RParenLoc, - ArrayRef SubExprs, - ArrayRef ElementNames, - ArrayRef ElementNameLocs, - Optional FirstTrailingArgumentAt, bool Implicit, Type Ty); + ArrayRef SubExprs, ArrayRef ElementNames, + ArrayRef ElementNameLocs, bool Implicit, Type Ty); public: /// Create a tuple. @@ -2201,17 +2063,8 @@ class TupleExpr final : public Expr, ArrayRef SubExprs, ArrayRef ElementNames, ArrayRef ElementNameLocs, - SourceLoc RParenLoc, bool HasTrailingClosure, - bool Implicit, Type Ty = Type()); - - static TupleExpr *create(ASTContext &ctx, - SourceLoc LParenLoc, - SourceLoc RParenLoc, - ArrayRef SubExprs, - ArrayRef ElementNames, - ArrayRef ElementNameLocs, - Optional FirstTrailingArgumentAt, - bool Implicit, Type Ty = Type()); + SourceLoc RParenLoc, bool Implicit, + Type Ty = Type()); /// Create an empty tuple. static TupleExpr *createEmpty(ASTContext &ctx, SourceLoc LParenLoc, @@ -2226,26 +2079,6 @@ class TupleExpr final : public Expr, SourceRange getSourceRange() const; - bool hasAnyTrailingClosures() const { - return (bool) FirstTrailingArgumentAt; - } - - /// Whether this expression has a trailing closure as its argument. - bool hasTrailingClosure() const { - return FirstTrailingArgumentAt - ? *FirstTrailingArgumentAt == getNumElements() - 1 - : false; - } - - bool hasMultipleTrailingClosures() const { - return FirstTrailingArgumentAt ? !hasTrailingClosure() : false; - } - - Optional - getUnlabeledTrailingClosureIndexOfPackedArgument() const { - return FirstTrailingArgumentAt; - } - /// Retrieve the elements of this tuple. MutableArrayRef getElements() { return { getTrailingObjects(), getNumElements() }; @@ -2256,22 +2089,8 @@ class TupleExpr final : public Expr, return { getTrailingObjects(), getNumElements() }; } - MutableArrayRef getTrailingElements() { - return getElements().take_back(getNumTrailingElements()); - } - - ArrayRef getTrailingElements() const { - return getElements().take_back(getNumTrailingElements()); - } - unsigned getNumElements() const { return Bits.TupleExpr.NumElements; } - unsigned getNumTrailingElements() const { - return FirstTrailingArgumentAt - ? getNumElements() - *FirstTrailingArgumentAt - : 0; - } - Expr *getElement(unsigned i) const { return getElements()[i]; } @@ -2477,75 +2296,32 @@ class DictionaryExpr final : public CollectionExpr, /// type-checked and well-formed subscript expression refers to a subscript /// declaration, which provides a getter and (optionally) a setter that will /// be used to perform reads/writes. -class SubscriptExpr final : public LookupExpr, - public TrailingCallArguments { - friend TrailingCallArguments; +class SubscriptExpr final : public LookupExpr { + ArgumentList *ArgList; - Expr *Index; + SubscriptExpr(Expr *base, ArgumentList *argList, ConcreteDeclRef decl, + bool implicit, AccessSemantics semantics); - SubscriptExpr(Expr *base, Expr *index, ArrayRef argLabels, - ArrayRef argLabelLocs, bool hasTrailingClosure, - ConcreteDeclRef decl, bool implicit, AccessSemantics semantics); - public: - /// Create a subscript. - /// - /// Note: do not create new callers to this entry point; use the entry point - /// that takes separate index arguments. - static SubscriptExpr *create( - ASTContext &ctx, Expr *base, Expr *index, - ConcreteDeclRef decl = ConcreteDeclRef(), bool implicit = false, - AccessSemantics semantics = AccessSemantics::Ordinary, - llvm::function_ref getType = [](Expr *E) -> Type { - return E->getType(); - }); - /// Create a new subscript. - static SubscriptExpr *create(ASTContext &ctx, Expr *base, - SourceLoc lSquareLoc, - ArrayRef indexArgs, - ArrayRef indexArgLabels, - ArrayRef indexArgLabelLocs, - SourceLoc rSquareLoc, - ArrayRef trailingClosures, - ConcreteDeclRef decl = ConcreteDeclRef(), - bool implicit = false, - AccessSemantics semantics - = AccessSemantics::Ordinary); + static SubscriptExpr * + create(ASTContext &ctx, Expr *base, ArgumentList *argList, + ConcreteDeclRef decl = ConcreteDeclRef(), bool implicit = false, + AccessSemantics semantics = AccessSemantics::Ordinary); - /// getIndex - Retrieve the index of the subscript expression, i.e., the - /// "offset" into the base value. - Expr *getIndex() const { return Index; } - void setIndex(Expr *E) { Index = E; } - - unsigned getNumArguments() const { - return Bits.SubscriptExpr.NumArgLabels; - } - - bool hasArgumentLabelLocs() const { - return Bits.SubscriptExpr.HasArgLabelLocs; - } - - /// Whether this call was written with a trailing closure. - bool hasTrailingClosure() const { - return Bits.SubscriptExpr.HasTrailingClosure; - } - - /// Return the index of the unlabeled trailing closure argument. - Optional getUnlabeledTrailingClosureIndex() const { - return getIndex()->getUnlabeledTrailingClosureIndexOfPackedArgument(); - } + ArgumentList *getArgs() const { return ArgList; } + void setArgs(ArgumentList *newArgs) { ArgList = newArgs; } /// Determine whether this subscript reference should bypass the /// ordinary accessors. AccessSemantics getAccessSemantics() const { return (AccessSemantics) Bits.SubscriptExpr.Semantics; } - - SourceLoc getLoc() const { return Index->getStartLoc(); } + + SourceLoc getLoc() const { return getArgs()->getStartLoc(); } SourceLoc getStartLoc() const { return getBase()->getStartLoc(); } SourceLoc getEndLoc() const { - auto end = Index->getEndLoc(); + auto end = getArgs()->getEndLoc(); return end.isValid() ? end : getBase()->getEndLoc(); } @@ -4544,20 +4320,17 @@ class ApplyExpr : public Expr { /// The function being called. Expr *Fn; - /// The argument being passed to it. - Expr *Arg; + /// The list of arguments to call the function with. + ArgumentList *ArgList; ImplicitActorHopTarget implicitActorHopTarget; - /// Returns true if \c e could be used as the call's argument. For most \c ApplyExpr - /// subclasses, this means it is a \c ParenExpr or \c TupleExpr. - bool validateArg(Expr *e) const; - protected: - ApplyExpr(ExprKind Kind, Expr *Fn, Expr *Arg, bool Implicit, Type Ty = Type()) - : Expr(Kind, Implicit, Ty), Fn(Fn), Arg(Arg) { + ApplyExpr(ExprKind kind, Expr *fn, ArgumentList *argList, bool implicit, + Type ty = Type()) + : Expr(kind, implicit, ty), Fn(fn), ArgList(argList) { + assert(ArgList); assert(classof((Expr*)this) && "ApplyExpr::classof out of date"); - assert(validateArg(Arg) && "Arg is not a permitted expr kind"); Bits.ApplyExpr.ThrowsIsSet = false; Bits.ApplyExpr.ImplicitlyAsync = false; Bits.ApplyExpr.ImplicitlyThrows = false; @@ -4568,12 +4341,9 @@ class ApplyExpr : public Expr { Expr *getFn() const { return Fn; } void setFn(Expr *e) { Fn = e; } Expr *getSemanticFn() const { return Fn->getSemanticsProvidingExpr(); } - - Expr *getArg() const { return Arg; } - void setArg(Expr *e) { - assert(validateArg(e) && "Arg is not a permitted expr kind"); - Arg = e; - } + + ArgumentList *getArgs() const { return ArgList; } + void setArgs(ArgumentList *newArgList) { ArgList = newArgList; } /// Has the type-checker set the 'throws' bit yet? /// @@ -4651,19 +4421,6 @@ class ApplyExpr : public Expr { ValueDecl *getCalledValue() const; - /// Retrieve the argument labels provided at the call site. - /// - /// \param scratch Scratch space that will be used when the argument labels - /// aren't already stored in the AST context. - ArrayRef - getArgumentLabels(SmallVectorImpl &scratch) const; - - /// Whether this application was written using a trailing closure. - bool hasTrailingClosure() const; - - /// Return the index of the unlabeled trailing closure argument. - Optional getUnlabeledTrailingClosureIndex() const; - static bool classof(const Expr *E) { return E->getKind() >= ExprKind::First_ApplyExpr && E->getKind() <= ExprKind::Last_ApplyExpr; @@ -4673,98 +4430,47 @@ class ApplyExpr : public Expr { /// CallExpr - Application of an argument to a function, which occurs /// syntactically through juxtaposition with a TupleExpr whose /// leading '(' is unspaced. -class CallExpr final : public ApplyExpr, - public TrailingCallArguments { - friend TrailingCallArguments; - - CallExpr(Expr *fn, Expr *arg, bool Implicit, - ArrayRef argLabels, - ArrayRef argLabelLocs, - bool hasTrailingClosure, - Type ty); +class CallExpr final : public ApplyExpr { + CallExpr(Expr *fn, ArgumentList *argList, bool implicit, Type ty); public: /// Create a new call expression. /// - /// Note: prefer to use the entry points that separate out the arguments. - static CallExpr *create( - ASTContext &ctx, Expr *fn, Expr *arg, ArrayRef argLabels, - ArrayRef argLabelLocs, bool hasTrailingClosure, bool implicit, - Type type = Type(), - llvm::function_ref getType = [](Expr *E) -> Type { - return E->getType(); - }); + /// \param fn The function being called + /// \param argList The argument list. + static CallExpr *create(ASTContext &ctx, Expr *fn, ArgumentList *argList, + bool implicit); /// Create a new implicit call expression without any source-location /// information. /// - /// \param fn The function being called - /// \param args The call arguments, not including a trailing closure (if any). - /// \param argLabels The argument labels, whose size must equal args.size(), - /// or which must be empty. - static CallExpr *createImplicit( - ASTContext &ctx, Expr *fn, ArrayRef args, - ArrayRef argLabels, - llvm::function_ref getType = [](Expr *E) -> Type { - return E->getType(); - }) { - return create(ctx, fn, SourceLoc(), args, argLabels, {}, SourceLoc(), - /*trailingClosures=*/{}, /*implicit=*/true, getType); + /// \param fn The function being called. + /// \param argList The argument list. + static CallExpr *createImplicit(ASTContext &ctx, Expr *fn, + ArgumentList *argList) { + return create(ctx, fn, argList, /*implicit*/ true); } /// Create a new implicit call expression with no arguments and no /// source-location information. /// /// \param fn The nullary function being called. - static CallExpr *createImplicitEmpty(ASTContext &ctx, Expr *fn) { - return createImplicit(ctx, fn, {}, {}); - } - - /// Create a new call expression. - /// - /// \param fn The function being called - /// \param args The call arguments, not including a trailing closure (if any). - /// \param argLabels The argument labels, whose size must equal args.size(), - /// or which must be empty. - /// \param argLabelLocs The locations of the argument labels, whose size must - /// equal args.size() or which must be empty. - /// \param trailingClosures The list of trailing closures, if any. - static CallExpr *create( - ASTContext &ctx, Expr *fn, SourceLoc lParenLoc, ArrayRef args, - ArrayRef argLabels, ArrayRef argLabelLocs, - SourceLoc rParenLoc, ArrayRef trailingClosures, - bool implicit, - llvm::function_ref getType = [](Expr *E) -> Type { - return E->getType(); - }); + static CallExpr *createImplicitEmpty(ASTContext &ctx, Expr *fn); SourceLoc getStartLoc() const { SourceLoc fnLoc = getFn()->getStartLoc(); - return (fnLoc.isValid() ? fnLoc : getArg()->getStartLoc()); + return (fnLoc.isValid() ? fnLoc : getArgs()->getStartLoc()); } SourceLoc getEndLoc() const { - SourceLoc argLoc = getArg()->getEndLoc(); + SourceLoc argLoc = getArgs()->getEndLoc(); return (argLoc.isValid() ? argLoc : getFn()->getEndLoc()); } SourceLoc getLoc() const { SourceLoc FnLoc = getFn()->getLoc(); - return FnLoc.isValid() ? FnLoc : getArg()->getLoc(); - } - - unsigned getNumArguments() const { return Bits.CallExpr.NumArgLabels; } - bool hasArgumentLabelLocs() const { return Bits.CallExpr.HasArgLabelLocs; } - - /// Whether this call with written with a single trailing closure. - bool hasTrailingClosure() const { return Bits.CallExpr.HasTrailingClosure; } - - /// Return the index of the unlabeled trailing closure argument. - Optional getUnlabeledTrailingClosureIndex() const { - return getArg()->getUnlabeledTrailingClosureIndexOfPackedArgument(); + return FnLoc.isValid() ? FnLoc : getArgs()->getStartLoc(); } - using TrailingCallArguments::getArgumentLabels; - /// Retrieve the expression that directly represents the callee. /// /// The "direct" callee is the expression representing the callee @@ -4778,8 +4484,10 @@ class CallExpr final : public ApplyExpr, /// PrefixUnaryExpr - Prefix unary expressions like '!y'. class PrefixUnaryExpr : public ApplyExpr { - PrefixUnaryExpr(Expr *fn, Expr *operand, Type ty = Type()) - : ApplyExpr(ExprKind::PrefixUnary, fn, operand, /*implicit*/ false, ty) {} + PrefixUnaryExpr(Expr *fn, ArgumentList *argList, Type ty = Type()) + : ApplyExpr(ExprKind::PrefixUnary, fn, argList, /*implicit*/ false, ty) { + assert(argList->isUnlabeledUnary()); + } public: static PrefixUnaryExpr *create(ASTContext &ctx, Expr *fn, Expr *operand, @@ -4790,9 +4498,10 @@ class PrefixUnaryExpr : public ApplyExpr { SourceLoc getStartLoc() const { return getFn()->getStartLoc(); } - SourceLoc getEndLoc() const { - return getArg()->getEndLoc(); - } + SourceLoc getEndLoc() const { return getOperand()->getEndLoc(); } + + Expr *getOperand() const { return getArgs()->getExpr(0); } + void setOperand(Expr *E) { getArgs()->setExpr(0, E); } static bool classof(const Expr *E) { return E->getKind() == ExprKind::PrefixUnary; @@ -4801,8 +4510,9 @@ class PrefixUnaryExpr : public ApplyExpr { /// PostfixUnaryExpr - Postfix unary expressions like 'y!'. class PostfixUnaryExpr : public ApplyExpr { - PostfixUnaryExpr(Expr *fn, Expr *operand, Type ty = Type()) - : ApplyExpr(ExprKind::PostfixUnary, fn, operand, /*implicit*/ false, ty) { + PostfixUnaryExpr(Expr *fn, ArgumentList *argList, Type ty = Type()) + : ApplyExpr(ExprKind::PostfixUnary, fn, argList, /*implicit*/ false, ty) { + assert(argList->isUnlabeledUnary()); } public: @@ -4810,14 +4520,15 @@ class PostfixUnaryExpr : public ApplyExpr { Type ty = Type()); SourceLoc getLoc() const { return getFn()->getStartLoc(); } - - SourceLoc getStartLoc() const { - return getArg()->getStartLoc(); - } + + SourceLoc getStartLoc() const { return getOperand()->getStartLoc(); } SourceLoc getEndLoc() const { return getFn()->getEndLoc(); } + Expr *getOperand() const { return getArgs()->getExpr(0); } + void setOperand(Expr *E) { getArgs()->setExpr(0, E); } + static bool classof(const Expr *E) { return E->getKind() == ExprKind::PostfixUnary; } @@ -4826,9 +4537,9 @@ class PostfixUnaryExpr : public ApplyExpr { /// BinaryExpr - Infix binary expressions like 'x+y'. The argument is always /// an implicit tuple expression of the type expected by the function. class BinaryExpr : public ApplyExpr { - BinaryExpr(Expr *fn, TupleExpr *arg, bool implicit, Type ty = Type()) - : ApplyExpr(ExprKind::Binary, fn, arg, implicit, ty) { - assert(arg->getNumElements() == 2); + BinaryExpr(Expr *fn, ArgumentList *argList, bool implicit, Type ty = Type()) + : ApplyExpr(ExprKind::Binary, fn, argList, implicit, ty) { + assert(argList->size() == 2); } public: @@ -4836,16 +4547,16 @@ class BinaryExpr : public ApplyExpr { bool implicit, Type ty = Type()); /// The left-hand argument of the binary operation. - Expr *getLHS() const { return cast(getArg())->getElement(0); } + Expr *getLHS() const { return getArgs()->getExpr(0); } /// The right-hand argument of the binary operation. - Expr *getRHS() const { return cast(getArg())->getElement(1); } + Expr *getRHS() const { return getArgs()->getExpr(1); } SourceLoc getLoc() const { return getFn()->getLoc(); } - SourceRange getSourceRange() const { return getArg()->getSourceRange(); } - SourceLoc getStartLoc() const { return getArg()->getStartLoc(); } - SourceLoc getEndLoc() const { return getArg()->getEndLoc(); } + SourceRange getSourceRange() const { return getArgs()->getSourceRange(); } + SourceLoc getStartLoc() const { return getArgs()->getStartLoc(); } + SourceLoc getEndLoc() const { return getArgs()->getEndLoc(); } static bool classof(const Expr *E) { return E->getKind() == ExprKind::Binary;} }; @@ -4858,12 +4569,14 @@ class BinaryExpr : public ApplyExpr { /// materialized from an rvalue. class SelfApplyExpr : public ApplyExpr { protected: - SelfApplyExpr(ExprKind K, Expr *FnExpr, Expr *BaseExpr, Type Ty) - : ApplyExpr(K, FnExpr, BaseExpr, FnExpr->isImplicit(), Ty) { } - + SelfApplyExpr(ExprKind kind, Expr *fnExpr, ArgumentList *argList, Type ty) + : ApplyExpr(kind, fnExpr, argList, fnExpr->isImplicit(), ty) { + assert(argList->isUnary()); + } + public: - Expr *getBase() const { return getArg(); } - void setBase(Expr *E) { setArg(E); } + Expr *getBase() const { return getArgs()->getExpr(0); } + void setBase(Expr *E) { getArgs()->setExpr(0, E); } static bool classof(const Expr *E) { return E->getKind() >= ExprKind::First_SelfApplyExpr && @@ -4876,9 +4589,9 @@ class SelfApplyExpr : public ApplyExpr { class DotSyntaxCallExpr : public SelfApplyExpr { SourceLoc DotLoc; - DotSyntaxCallExpr(Expr *fnExpr, SourceLoc dotLoc, Expr *baseExpr, + DotSyntaxCallExpr(Expr *fnExpr, SourceLoc dotLoc, ArgumentList *argList, Type ty = Type()) - : SelfApplyExpr(ExprKind::DotSyntaxCall, fnExpr, baseExpr, ty), + : SelfApplyExpr(ExprKind::DotSyntaxCall, fnExpr, argList, ty), DotLoc(dotLoc) { setImplicit(DotLoc.isInvalid()); } @@ -4903,8 +4616,8 @@ class DotSyntaxCallExpr : public SelfApplyExpr { /// actual reference to function which returns the constructor is modeled /// as a DeclRefExpr. class ConstructorRefCallExpr : public SelfApplyExpr { - ConstructorRefCallExpr(Expr *fnExpr, Expr *baseExpr, Type ty = Type()) - : SelfApplyExpr(ExprKind::ConstructorRefCall, fnExpr, baseExpr, ty) {} + ConstructorRefCallExpr(Expr *fnExpr, ArgumentList *argList, Type ty = Type()) + : SelfApplyExpr(ExprKind::ConstructorRefCall, fnExpr, argList, ty) {} public: static ConstructorRefCallExpr *create(ASTContext &ctx, Expr *fnExpr, @@ -5586,30 +5299,19 @@ class KeyPathExpr : public Expr { DeclNameOrRef(DeclNameRef un) : UnresolvedName(un) {} DeclNameOrRef(ConcreteDeclRef rd) : ResolvedDecl(rd) {} } Decl; - - - Expr *SubscriptIndexExpr; - const Identifier *SubscriptLabelsData; + + ArgumentList *SubscriptArgList; const ProtocolConformanceRef *SubscriptHashableConformancesData; - - union { - unsigned SubscriptSize; - unsigned TupleIndex; - }; - + + unsigned TupleIndex; Kind KindValue; Type ComponentType; SourceLoc Loc; // Private constructor for subscript component. - explicit Component(ASTContext *ctxForCopyingLabels, - DeclNameOrRef decl, - Expr *indexExpr, - ArrayRef subscriptLabels, + explicit Component(DeclNameOrRef decl, ArgumentList *argList, ArrayRef indexHashables, - Kind kind, - Type type, - SourceLoc loc); + Kind kind, Type type, SourceLoc loc); // Private constructor for property or #keyPath dictionary key. explicit Component(DeclNameOrRef decl, Kind kind, Type type, SourceLoc loc) @@ -5640,29 +5342,8 @@ class KeyPathExpr : public Expr { /// Create an unresolved component for a subscript. static Component forUnresolvedSubscript(ASTContext &ctx, - SourceLoc lSquareLoc, - ArrayRef indexArgs, - ArrayRef indexArgLabels, - ArrayRef indexArgLabelLocs, - SourceLoc rSquareLoc, - ArrayRef trailingClosures); - - /// Create an unresolved component for a subscript. - /// - /// You shouldn't add new uses of this overload; use the one that takes a - /// list of index arguments. - static Component forUnresolvedSubscriptWithPrebuiltIndexExpr( - ASTContext &context, - Expr *index, - ArrayRef subscriptLabels, - SourceLoc loc) { - - return Component(&context, - {}, index, subscriptLabels, {}, - Kind::UnresolvedSubscript, - Type(), loc); - } - + ArgumentList *argList); + /// Create an unresolved optional force `!` component. static Component forUnresolvedOptionalForce(SourceLoc BangLoc) { return Component(Kind::OptionalForce, Type(), BangLoc); @@ -5688,26 +5369,11 @@ class KeyPathExpr : public Expr { } /// Create a component for a subscript. - static Component forSubscript(ASTContext &ctx, - ConcreteDeclRef subscript, - SourceLoc lSquareLoc, - ArrayRef indexArgs, - ArrayRef indexArgLabels, - ArrayRef indexArgLabelLocs, - SourceLoc rSquareLoc, - ArrayRef trailingClosures, - Type elementType, - ArrayRef indexHashables); + static Component + forSubscript(ASTContext &ctx, ConcreteDeclRef subscript, + ArgumentList *argList, Type elementType, + ArrayRef indexHashables); - /// Create a component for a subscript. - /// - /// You shouldn't add new uses of this overload; use the one that takes a - /// list of index arguments. - static Component forSubscriptWithPrebuiltIndexExpr( - ConcreteDeclRef subscript, Expr *index, ArrayRef labels, - Type elementType, SourceLoc loc, - ArrayRef indexHashables); - /// Create an optional-forcing `!` component. static Component forOptionalForce(Type forcedType, SourceLoc bangLoc) { return Component(Kind::OptionalForce, forcedType, bangLoc); @@ -5745,8 +5411,8 @@ class KeyPathExpr : public Expr { } SourceRange getSourceRange() const { - if (auto *indexExpr = getIndexExpr()) { - return indexExpr->getSourceRange(); + if (auto *args = getSubscriptArgs()) { + return args->getSourceRange(); } return Loc; } @@ -5783,11 +5449,11 @@ class KeyPathExpr : public Expr { llvm_unreachable("unhandled kind"); } - Expr *getIndexExpr() const { + ArgumentList *getSubscriptArgs() const { switch (getKind()) { case Kind::Subscript: case Kind::UnresolvedSubscript: - return SubscriptIndexExpr; + return SubscriptArgList; case Kind::Invalid: case Kind::OptionalChain: @@ -5804,25 +5470,9 @@ class KeyPathExpr : public Expr { llvm_unreachable("unhandled kind"); } - ArrayRef getSubscriptLabels() const { - switch (getKind()) { - case Kind::Subscript: - case Kind::UnresolvedSubscript: - return {SubscriptLabelsData, (size_t)SubscriptSize}; - - case Kind::Invalid: - case Kind::OptionalChain: - case Kind::OptionalWrap: - case Kind::OptionalForce: - case Kind::UnresolvedProperty: - case Kind::Property: - case Kind::Identity: - case Kind::TupleElement: - case Kind::DictionaryKey: - case Kind::CodeCompletion: - llvm_unreachable("no subscript labels for this kind"); - } - llvm_unreachable("unhandled kind"); + void setSubscriptArgs(ArgumentList *newArgs) { + assert(getSubscriptArgs() && "Should be replacing existing args"); + SubscriptArgList = newArgs; } ArrayRef @@ -5831,7 +5481,7 @@ class KeyPathExpr : public Expr { case Kind::Subscript: if (!SubscriptHashableConformancesData) return {}; - return {SubscriptHashableConformancesData, (size_t)SubscriptSize}; + return {SubscriptHashableConformancesData, SubscriptArgList->size()}; case Kind::UnresolvedSubscript: case Kind::Invalid: @@ -5849,9 +5499,6 @@ class KeyPathExpr : public Expr { llvm_unreachable("unhandled kind"); } - void setSubscriptIndexHashableConformances( - ArrayRef hashables); - DeclNameRef getUnresolvedDeclName() const { switch (getKind()) { case Kind::UnresolvedProperty: @@ -5992,6 +5639,11 @@ class KeyPathExpr : public Expr { return false; } + /// If the provided expression appears as an argument to a subscript component + /// of the key path, returns the index of that component. Otherwise, returns + /// \c None. + Optional findComponentWithSubscriptArg(Expr *arg); + /// Retrieve the string literal expression, which will be \c NULL prior to /// type checking and a string literal after type checking for an /// @objc key path. @@ -6090,15 +5742,6 @@ inline bool Expr::isInfixOperator() const { return isa(this) || isa(this) || isa(this) || isa(this); } - -inline bool ApplyExpr::validateArg(Expr *e) const { - if (isa(this)) - return true; - else if (isa(this)) - return isa(e); - else - return isa(e) || isa(e); -} inline Expr *const *CollectionExpr::getTrailingObjectsPointer() const { if (auto ty = dyn_cast(this)) @@ -6118,25 +5761,6 @@ inline const SourceLoc *CollectionExpr::getTrailingSourceLocs() const { #undef SWIFT_FORWARD_SOURCE_LOCS_TO -/// Pack the argument information into a single argument, to match the -/// representation expected by the AST. -/// -/// \param argLabels The argument labels, which might be updated by this -/// function. -/// -/// \param argLabelLocs The argument label locations, which might be updated by -/// this function. -Expr *packSingleArgument( - ASTContext &ctx, SourceLoc lParenLoc, ArrayRef args, - ArrayRef &argLabels, ArrayRef &argLabelLocs, - SourceLoc rParenLoc, ArrayRef trailingClosures, - bool implicit, - SmallVectorImpl &argLabelsScratch, - SmallVectorImpl &argLabelLocsScratch, - llvm::function_ref getType = [](Expr *E) -> Type { - return E->getType(); - }); - void simple_display(llvm::raw_ostream &out, const ClosureExpr *CE); void simple_display(llvm::raw_ostream &out, const DefaultArgumentExpr *expr); void simple_display(llvm::raw_ostream &out, const Expr *expr); diff --git a/include/swift/AST/TrailingCallArguments.h b/include/swift/AST/TrailingCallArguments.h deleted file mode 100644 index 1c88c9b69db64..0000000000000 --- a/include/swift/AST/TrailingCallArguments.h +++ /dev/null @@ -1,128 +0,0 @@ -//===--- TrailingCallArguments.h - Trailing Call Arguments ------*- C++ -*-===// -// -// This source file is part of the Swift.org open source project -// -// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception -// -// See https://swift.org/LICENSE.txt for license information -// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors -// -//===----------------------------------------------------------------------===// -// -// This file defines the TrailingCallArguments template, which is used -// to tail-allocate the names and source locations of argument labels in a -// call. -// -//===----------------------------------------------------------------------===// - -#ifndef SWIFT_AST_TRAILINGCALLARGUMENTS_H -#define SWIFT_AST_TRAILINGCALLARGUMENTS_H - -#include "swift/AST/Identifier.h" -#include "swift/Basic/SourceLoc.h" -#include "llvm/ADT/ArrayRef.h" -#include "llvm/Support/TrailingObjects.h" - -namespace swift { - -/// Helper class to capture trailing call argument labels and related -/// information, for expression nodes that involve argument labels, trailing -/// closures, etc. -template -class TrailingCallArguments - : private llvm::TrailingObjects { - // We need to friend TrailingObjects twice here to work around an MSVC bug. - // If we have two functions of the same name with the parameter - // typename TrailingObjectsIdentifier::template OverloadToken where T is - // different for each function, then MSVC reports a "member function already - // defined or declared" error, which is incorrect. - using TrailingObjectsIdentifier = llvm::TrailingObjects; - friend TrailingObjectsIdentifier; - - using TrailingObjects = llvm::TrailingObjects; - friend TrailingObjects; - - Derived &asDerived() { - return *static_cast(this); - } - - const Derived &asDerived() const { - return *static_cast(this); - } - - size_t numTrailingObjects( - typename TrailingObjectsIdentifier::template OverloadToken) - const { - return asDerived().getNumArguments(); - } - - size_t numTrailingObjects( - typename TrailingObjectsIdentifier::template OverloadToken) - const { - return asDerived().hasArgumentLabelLocs() ? asDerived().getNumArguments() - : 0; - } - - /// Retrieve the buffer containing the argument labels. - MutableArrayRef getArgumentLabelsBuffer() { - return { this->template getTrailingObjects(), - asDerived().getNumArguments() }; - } - - /// Retrieve the buffer containing the argument label locations. - MutableArrayRef getArgumentLabelLocsBuffer() { - if (!asDerived().hasArgumentLabelLocs()) - return { }; - - return { this->template getTrailingObjects(), - asDerived().getNumArguments() }; - } - -protected: - /// Determine the total size to allocate. - static size_t totalSizeToAlloc(ArrayRef argLabels, - ArrayRef argLabelLocs) { - return TrailingObjects::template totalSizeToAlloc( - argLabels.size(), argLabelLocs.size()); - } - - /// Initialize the actual call arguments. - void initializeCallArguments(ArrayRef argLabels, - ArrayRef argLabelLocs) { - if (!argLabels.empty()) { - std::uninitialized_copy(argLabels.begin(), argLabels.end(), - this->template getTrailingObjects()); - } - - if (!argLabelLocs.empty()) - std::uninitialized_copy(argLabelLocs.begin(), argLabelLocs.end(), - this->template getTrailingObjects()); - } - -public: - /// Retrieve the argument labels provided at the call site. - ArrayRef getArgumentLabels() const { - return { this->template getTrailingObjects(), - asDerived().getNumArguments() }; - } - - /// Retrieve the buffer containing the argument label locations. - ArrayRef getArgumentLabelLocs() const { - if (!asDerived().hasArgumentLabelLocs()) - return { }; - - return { this->template getTrailingObjects(), - asDerived().getNumArguments() }; - } - - /// Retrieve the location of the ith argument label. - SourceLoc getArgumentLabelLoc(unsigned i) const { - auto locs = getArgumentLabelLocs(); - return i < locs.size() ? locs[i] : SourceLoc(); - } -}; - -} // end namespace swift - -#endif // SWIFT_AST_TRAILINGCALLARGUMENTS_H diff --git a/include/swift/AST/Types.h b/include/swift/AST/Types.h index b6450c108dc74..e455b25a86a19 100644 --- a/include/swift/AST/Types.h +++ b/include/swift/AST/Types.h @@ -54,6 +54,7 @@ namespace swift { enum class AllocationArena; class ArchetypeType; +class ArgumentList; class AssociatedTypeDecl; class ASTContext; enum BufferPointerTypeKind : unsigned; @@ -3003,10 +3004,6 @@ class AnyFunctionType : public TypeBase { } public: - /// Break a tuple or paren type into an array of \c AnyFunctionType::Params. - static void decomposeTuple(Type type, - SmallVectorImpl &result); - /// Take an array of parameters and turn it into a tuple or paren type. static Type composeTuple(ASTContext &ctx, ArrayRef params, bool canonicalVararg); @@ -3025,11 +3022,11 @@ class AnyFunctionType : public TypeBase { /// account. static bool equalParams(CanParamArrayRef a, CanParamArrayRef b); - /// Given an array of parameters and an array of labels of the + /// Given an array of parameters and an argument list of the /// same length, update each parameter to have the corresponding label. /// The internal parameter labels remain the same. static void relabelParams(MutableArrayRef params, - ArrayRef labels); + ArgumentList *argList); Type getResult() const { return Output; } ArrayRef getParams() const; diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 42f41b66b9cd9..1777ad0e1d8ee 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -3440,39 +3440,6 @@ AnyFunctionType *AnyFunctionType::withExtInfo(ExtInfo info) const { getParams(), getResult(), info); } -void AnyFunctionType::decomposeTuple( - Type type, SmallVectorImpl &result) { - switch (type->getKind()) { - case TypeKind::Tuple: { - auto tupleTy = cast(type.getPointer()); - for (auto &elt : tupleTy->getElements()) { - result.emplace_back((elt.isVararg() - ? elt.getVarargBaseTy() - : elt.getRawType()), - elt.getName(), - elt.getParameterFlags()); - } - return; - } - - case TypeKind::Paren: { - auto pty = cast(type.getPointer()); - result.emplace_back(pty->getUnderlyingType()->getInOutObjectType(), - Identifier(), - pty->getParameterFlags()); - return; - } - - default: - result.emplace_back( - type->getInOutObjectType(), Identifier(), - ParameterTypeFlags::fromParameterType(type, false, false, false, - ValueOwnership::Default, false, - false)); - return; - } -} - Type AnyFunctionType::Param::getParameterType(bool forCanonical, ASTContext *ctx) const { Type type = getPlainType(); @@ -3526,11 +3493,11 @@ bool AnyFunctionType::equalParams(CanParamArrayRef a, CanParamArrayRef b) { } void AnyFunctionType::relabelParams(MutableArrayRef params, - ArrayRef labels) { - assert(params.size() == labels.size()); + ArgumentList *argList) { + assert(params.size() == argList->size()); for (auto i : indices(params)) { auto ¶m = params[i]; - param = AnyFunctionType::Param(param.getPlainType(), labels[i], + param = AnyFunctionType::Param(param.getPlainType(), argList->getLabel(i), param.getParameterFlags(), param.getInternalLabel()); } diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index 9eeefc67e3697..80571d99b0a64 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -1908,9 +1908,8 @@ class PrintExpr : public ExprVisitor { << " kind='" << E->getLiteralKindPlainName() << "'"; PrintWithColorRAII(OS, LiteralValueColor) << " initializer="; E->getInitializer().dump(PrintWithColorRAII(OS, LiteralValueColor).getOS()); - printArgumentLabels(E->getArgumentLabels()); OS << "\n"; - printRec(E->getArg()); + printArgumentList(E->getArgs()); PrintWithColorRAII(OS, ParenthesisColor) << ')'; } @@ -2023,8 +2022,6 @@ class PrintExpr : public ExprVisitor { } void visitParenExpr(ParenExpr *E) { printCommon(E, "paren_expr"); - if (E->hasTrailingClosure()) - OS << " trailing-closure"; OS << '\n'; printRec(E->getSubExpr()); PrintWithColorRAII(OS, ParenthesisColor) << ')'; @@ -2043,8 +2040,6 @@ class PrintExpr : public ExprVisitor { } void visitTupleExpr(TupleExpr *E) { printCommon(E, "tuple_expr"); - if (E->hasTrailingClosure()) - OS << " trailing-closure"; if (E->hasElementNames()) { PrintWithColorRAII(OS, IdentifierColor) << " names="; @@ -2097,11 +2092,10 @@ class PrintExpr : public ExprVisitor { PrintWithColorRAII(OS, DeclColor) << " decl="; printDeclRef(E->getDecl()); } - printArgumentLabels(E->getArgumentLabels()); OS << '\n'; printRec(E->getBase()); OS << '\n'; - printRec(E->getIndex()); + printArgumentList(E->getArgs()); PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitKeyPathApplicationExpr(KeyPathApplicationExpr *E) { @@ -2116,11 +2110,10 @@ class PrintExpr : public ExprVisitor { printCommon(E, "dynamic_subscript_expr"); PrintWithColorRAII(OS, DeclColor) << " decl="; printDeclRef(E->getMember()); - printArgumentLabels(E->getArgumentLabels()); OS << '\n'; printRec(E->getBase()); OS << '\n'; - printRec(E->getIndex()); + printArgumentList(E->getArgs()); PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitUnresolvedDotExpr(UnresolvedDotExpr *E) { @@ -2496,14 +2489,6 @@ class PrintExpr : public ExprVisitor { PrintWithColorRAII(OS, ParenthesisColor) << ')'; } - void printArgumentLabels(ArrayRef argLabels) { - PrintWithColorRAII(OS, ArgumentsColor) << " arg_labels="; - for (auto label : argLabels) { - PrintWithColorRAII(OS, ArgumentsColor) - << (label.empty() ? "_" : label.str()) << ":"; - } - } - void printArgument(const Argument &arg) { OS.indent(Indent); PrintWithColorRAII(OS, ParenthesisColor) << '('; @@ -2567,13 +2552,10 @@ class PrintExpr : public ExprVisitor { PrintWithColorRAII(OS, ExprModifierColor) << (E->throws() ? " throws" : " nothrow"); } - if (auto call = dyn_cast(E)) - printArgumentLabels(call->getArgumentLabels()); - OS << '\n'; printRec(E->getFn()); OS << '\n'; - printRec(E->getArg()); + printArgumentList(E->getArgs()); PrintWithColorRAII(OS, ParenthesisColor) << ')'; } @@ -2804,7 +2786,6 @@ class PrintExpr : public ExprVisitor { case KeyPathExpr::Component::Kind::UnresolvedSubscript: PrintWithColorRAII(OS, ASTNodeColor) << "unresolved_subscript"; - printArgumentLabels(component.getSubscriptLabels()); break; case KeyPathExpr::Component::Kind::Identity: PrintWithColorRAII(OS, ASTNodeColor) << "identity"; @@ -2826,11 +2807,9 @@ class PrintExpr : public ExprVisitor { } PrintWithColorRAII(OS, TypeColor) << " type='" << GetTypeOfKeyPathComponent(E, i) << "'"; - if (auto indexExpr = component.getIndexExpr()) { + if (auto *args = component.getSubscriptArgs()) { OS << '\n'; - Indent += 2; - printRec(indexExpr); - Indent -= 2; + printArgumentList(args); } PrintWithColorRAII(OS, ParenthesisColor) << ')'; } diff --git a/lib/AST/ASTScopeCreation.cpp b/lib/AST/ASTScopeCreation.cpp index b7b78abdd0daf..54e2b0b7f92d9 100644 --- a/lib/AST/ASTScopeCreation.cpp +++ b/lib/AST/ASTScopeCreation.cpp @@ -1038,8 +1038,10 @@ void DefaultArgumentInitializerScope:: void AttachedPropertyWrapperScope:: expandAScopeThatDoesNotCreateANewInsertionPoint( ScopeCreator &scopeCreator) { - if (auto *expr = attr->getArg()) - scopeCreator.addToScopeTree(expr, this); + if (auto *args = attr->getArgs()) { + for (auto arg : *args) + scopeCreator.addToScopeTree(arg.getExpr(), this); + } } #pragma mark expandScope diff --git a/lib/AST/ASTVerifier.cpp b/lib/AST/ASTVerifier.cpp index a046d786f91d7..59dd14d686897 100644 --- a/lib/AST/ASTVerifier.cpp +++ b/lib/AST/ASTVerifier.cpp @@ -118,7 +118,7 @@ std::pair dispatchVisitPreExprHelper( if (V.shouldVerify(node)) { // Record any inout_to_pointer or array_to_pointer that we see in // the proper position. - V.maybeRecordValidPointerConversion(node, node->getArg()); + V.maybeRecordValidPointerConversion(node->getArgs()); return {true, node}; } V.cleanup(node); @@ -134,7 +134,7 @@ std::pair dispatchVisitPreExprHelper( if (V.shouldVerify(node)) { // Record any inout_to_pointer or array_to_pointer that we see in // the proper position. - V.maybeRecordValidPointerConversion(node, node->getIndex()); + V.maybeRecordValidPointerConversion(node->getArgs()); return {true, node}; } V.cleanup(node); @@ -150,7 +150,7 @@ std::pair dispatchVisitPreExprHelper( if (V.shouldVerify(node)) { // Record any inout_to_pointer or array_to_pointer that we see in // the proper position. - V.maybeRecordValidPointerConversion(node, node->getSingleExpressionBody()); + V.maybeRecordValidPointerConversionForArg(node->getSingleExpressionBody()); return {true, node}; } V.cleanup(node); @@ -1675,107 +1675,71 @@ class Verifier : public ASTWalker { verifyCheckedBase(E); } - void maybeRecordValidPointerConversion(Expr *Base, Expr *Arg) { - auto handleSubExpr = [&](Expr *origSubExpr) { - auto subExpr = origSubExpr; - unsigned optionalDepth = 0; + void maybeRecordValidPointerConversionForArg(Expr *argExpr) { + auto *subExpr = argExpr; + unsigned optionalDepth = 0; - auto checkIsBindOptional = [&](Expr *expr) { - for (unsigned depth = optionalDepth; depth; --depth) { - if (auto bind = dyn_cast(expr)) { - expr = bind->getSubExpr(); - } else { - Out << "malformed optional pointer conversion\n"; - origSubExpr->dump(Out); - Out << '\n'; - abort(); - } - } - }; - - // FIXME: This doesn't seem like a particularly robust - // approach to tracking whether pointer conversions - // always appear as call arguments. - while (true) { - // Look through optional evaluations. - if (auto *optionalEval = dyn_cast(subExpr)) { - subExpr = optionalEval->getSubExpr(); - ++optionalDepth; - continue; - } - - // Look through injections into Optional. - if (auto *injectIntoOpt = dyn_cast(subExpr)) { - subExpr = injectIntoOpt->getSubExpr(); - continue; - } - - // FIXME: This is only handling the value conversion, not - // the key conversion. What this verifier check - // should probably do is just track whether we're - // currently visiting arguments of an apply when we - // find these conversions. - if (auto *upcast = - dyn_cast(subExpr)) { - subExpr = upcast->getValueConversion().Conversion; - continue; - } - - break; + // FIXME: This doesn't seem like a particularly robust + // approach to tracking whether pointer conversions + // always appear as call arguments. + while (true) { + // Look through optional evaluations. + if (auto *optionalEval = dyn_cast(subExpr)) { + subExpr = optionalEval->getSubExpr(); + ++optionalDepth; + continue; } - // Record inout-to-pointer conversions. - if (auto *inOutToPtr = dyn_cast(subExpr)) { - ValidInOutToPointerExprs.insert(inOutToPtr); - checkIsBindOptional(inOutToPtr->getSubExpr()); - return; + // Look through injections into Optional. + if (auto *injectIntoOpt = dyn_cast(subExpr)) { + subExpr = injectIntoOpt->getSubExpr(); + continue; } - // Record array-to-pointer conversions. - if (auto *arrayToPtr = dyn_cast(subExpr)) { - ValidArrayToPointerExprs.insert(arrayToPtr); - checkIsBindOptional(arrayToPtr->getSubExpr()); - return; + // FIXME: This is only handling the value conversion, not + // the key conversion. What this verifier check + // should probably do is just track whether we're + // currently visiting arguments of an apply when we + // find these conversions. + if (auto *upcast = dyn_cast(subExpr)) { + subExpr = upcast->getValueConversion().Conversion; + continue; } - }; - if (auto *ParentExprArg = dyn_cast(Arg)) { - return handleSubExpr(ParentExprArg->getSubExpr()); + break; } - if (auto *TupleArg = dyn_cast(Arg)) { - for (auto *SubExpr : TupleArg->getElements()) { - handleSubExpr(SubExpr); + auto checkIsBindOptional = [&](Expr *expr) { + for (unsigned depth = optionalDepth; depth; --depth) { + if (auto bind = dyn_cast(expr)) { + expr = bind->getSubExpr(); + } else { + Out << "malformed optional pointer conversion\n"; + argExpr->dump(Out); + Out << '\n'; + abort(); + } } + }; + + // Record inout-to-pointer conversions. + if (auto *inOutToPtr = dyn_cast(subExpr)) { + ValidInOutToPointerExprs.insert(inOutToPtr); + checkIsBindOptional(inOutToPtr->getSubExpr()); return; } - // Otherwise, just run it through handle sub expr. This case can happen if - // we have an autoclosure. - if (isa(Base)) { - handleSubExpr(Arg); + // Record array-to-pointer conversions. + if (auto *arrayToPtr = dyn_cast(subExpr)) { + ValidArrayToPointerExprs.insert(arrayToPtr); + checkIsBindOptional(arrayToPtr->getSubExpr()); return; } } - /// A version of AnyFunctionType::equalParams() that ignores "isolated" - /// parameters, which aren't represented in the type system. - static bool equalParamsIgnoringIsolation( - ArrayRef a, - ArrayRef b) { - auto withoutIsolation = [](AnyFunctionType::Param param) { - return param.withFlags(param.getParameterFlags().withIsolated(false)); - }; - - if (a.size() != b.size()) - return false; - - for (unsigned i = 0, n = a.size(); i != n; ++i) { - if (withoutIsolation(a[i]) != withoutIsolation(b[i])) - return false; - } - - return true; + void maybeRecordValidPointerConversion(ArgumentList *argList) { + for (auto arg : *argList) + maybeRecordValidPointerConversionForArg(arg.getExpr()); } void verifyChecked(ApplyExpr *E) { @@ -1798,14 +1762,10 @@ class Verifier : public ASTWalker { abort(); } - SmallVector Args; - Type InputExprTy = E->getArg()->getType(); - AnyFunctionType::decomposeTuple(InputExprTy, Args); - auto Params = FT->getParams(); - if (!equalParamsIgnoringIsolation(Args, Params)) { - Out << "Argument type does not match parameter type in ApplyExpr:" - "\nArgument type: "; - InputExprTy.print(Out); + if (!E->getArgs()->matches(FT->getParams())) { + Out << "Argument list does not match parameters in ApplyExpr:" + "\nArgument list: "; + E->getArgs()->dump(Out); Out << "\nParameter types: "; AnyFunctionType::printParams(FT->getParams(), Out); Out << "\n"; @@ -2191,8 +2151,13 @@ class Verifier : public ASTWalker { abort(); } - auto callArgTy = call->getArg()->getType()->getAs(); - if (!callArgTy) { + auto *unaryArg = call->getArgs()->getUnaryExpr(); + if (!unaryArg) { + Out << "MakeTemporarilyEscapableExpr doesn't have a unary argument\n"; + abort(); + } + + if (!unaryArg->getType()->is()) { Out << "MakeTemporarilyEscapableExpr call argument is not a function\n"; abort(); } diff --git a/lib/AST/ASTWalker.cpp b/lib/AST/ASTWalker.cpp index 0780393b9f517..cec431fdc05df 100644 --- a/lib/AST/ASTWalker.cpp +++ b/lib/AST/ASTWalker.cpp @@ -539,12 +539,10 @@ class Traversal : public ASTVisitorgetArg()) { - if (Expr *arg2 = doIt(arg)) { - E->setArg(arg2); - } else { - return nullptr; - } + if (auto *args = doIt(E->getArgs())) { + E->setArgs(args); + } else { + return nullptr; } return E; } @@ -609,11 +607,12 @@ class Traversal : public ASTVisitorsetBase(Base); else return nullptr; - - if (Expr *Index = doIt(E->getIndex())) - E->setIndex(Index); - else + + if (auto *args = doIt(E->getArgs())) { + E->setArgs(args); + } else { return nullptr; + } return E; } @@ -635,11 +634,12 @@ class Traversal : public ASTVisitorsetBase(Base); else return nullptr; - - if (Expr *Index = doIt(E->getIndex())) - E->setIndex(Index); - else + + if (auto *args = doIt(E->getArgs())) { + E->setArgs(args); + } else { return nullptr; + } return E; } @@ -853,15 +853,10 @@ class Traversal : public ASTVisitorsetFn(E2); } - if (E->getArg()) { - Expr *E2 = doIt(E->getArg()); - if (E2 == nullptr) return nullptr; - - // Protect against setting a non-tuple argument expression for a binop, - // which may occur as a result of error recovery. - // E.g., "print(Array(E) || isa(E2)) - E->setArg(E2); + if (auto *args = doIt(E->getArgs())) { + E->setArgs(args); + } else { + return nullptr; } return E; @@ -1089,30 +1084,15 @@ class Traversal : public ASTVisitor updatedComponents; - bool didChangeComponents = false; for (auto &origComponent : components) { auto component = origComponent; switch (auto kind = component.getKind()) { case KeyPathExpr::Component::Kind::Subscript: case KeyPathExpr::Component::Kind::UnresolvedSubscript: { - Expr *origIndex = component.getIndexExpr(); - Expr *newIndex = doIt(origIndex); - if (!newIndex) return nullptr; - if (newIndex != origIndex) { - didChangeComponents = true; - component = kind == KeyPathExpr::Component::Kind::Subscript - ? KeyPathExpr::Component::forSubscriptWithPrebuiltIndexExpr( - component.getDeclRef(), - newIndex, - component.getSubscriptLabels(), - component.getComponentType(), - component.getLoc(), - component.getSubscriptIndexHashableConformances()) - : KeyPathExpr::Component - ::forUnresolvedSubscriptWithPrebuiltIndexExpr( - E->getType()->getASTContext(), - newIndex, component.getSubscriptLabels(), component.getLoc()); + if (auto *newArgs = doIt(component.getSubscriptArgs())) { + component.setSubscriptArgs(newArgs); + } else { + return nullptr; } break; } @@ -1130,14 +1110,7 @@ class Traversal : public ASTVisitorresolveComponents(E->getType()->getASTContext(), - updatedComponents); - } - return E; } diff --git a/lib/AST/Attr.cpp b/lib/AST/Attr.cpp index 48af246aeb413..7ae249d00977b 100644 --- a/lib/AST/Attr.cpp +++ b/lib/AST/Attr.cpp @@ -1987,47 +1987,24 @@ TypeRepr *ImplementsAttr::getProtocolTypeRepr() const { } CustomAttr::CustomAttr(SourceLoc atLoc, SourceRange range, TypeExpr *type, - PatternBindingInitializer *initContext, Expr *arg, - ArrayRef argLabels, - ArrayRef argLabelLocs, bool implicit) - : DeclAttribute(DAK_Custom, atLoc, range, implicit), - typeExpr(type), - arg(arg), - initContext(initContext) { + PatternBindingInitializer *initContext, + ArgumentList *argList, bool implicit) + : DeclAttribute(DAK_Custom, atLoc, range, implicit), typeExpr(type), + argList(argList), initContext(initContext) { assert(type); - hasArgLabelLocs = !argLabelLocs.empty(); - numArgLabels = argLabels.size(); isArgUnsafeBit = false; - initializeCallArguments(argLabels, argLabelLocs); } CustomAttr *CustomAttr::create(ASTContext &ctx, SourceLoc atLoc, TypeExpr *type, - bool hasInitializer, PatternBindingInitializer *initContext, - SourceLoc lParenLoc, - ArrayRef args, - ArrayRef argLabels, - ArrayRef argLabelLocs, - SourceLoc rParenLoc, - bool implicit) { + ArgumentList *argList, bool implicit) { assert(type); - SmallVector argLabelsScratch; - SmallVector argLabelLocsScratch; - Expr *arg = nullptr; - if (hasInitializer) { - arg = packSingleArgument(ctx, lParenLoc, args, argLabels, argLabelLocs, - rParenLoc, /*trailingClosures=*/{}, implicit, - argLabelsScratch, argLabelLocsScratch); - } - SourceRange range(atLoc, type->getSourceRange().End); - if (arg) - range.End = arg->getEndLoc(); + if (argList) + range.End = argList->getEndLoc(); - size_t size = totalSizeToAlloc(argLabels, argLabelLocs); - void *mem = ctx.Allocate(size, alignof(CustomAttr)); - return new (mem) CustomAttr(atLoc, range, type, initContext, arg, argLabels, - argLabelLocs, implicit); + return new (ctx) + CustomAttr(atLoc, range, type, initContext, argList, implicit); } TypeRepr *CustomAttr::getTypeRepr() const { return typeExpr->getTypeRepr(); } @@ -2044,17 +2021,17 @@ bool CustomAttr::isArgUnsafe() const { if (isArgUnsafeBit) return true; - auto arg = getArg(); - if (!arg) + auto args = getArgs(); + if (!args) return false; - if (auto parenExpr = dyn_cast(arg)) { - if (auto declRef = - dyn_cast(parenExpr->getSubExpr())) { - if (declRef->getName().isSimpleName("unsafe")) { - isArgUnsafeBit = true; - } - } + auto *unary = args->getUnlabeledUnaryExpr(); + if (!unary) + return false; + + if (auto declRef = dyn_cast(unary)) { + if (declRef->getName().isSimpleName("unsafe")) + isArgUnsafeBit = true; } return isArgUnsafeBit; diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index c85507d6093b0..067df4401cc21 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -1493,7 +1493,7 @@ bool PatternBindingEntry::isInitialized(bool onlyExplicit) const { // Initialized via a property wrapper. if (auto var = getPattern()->getSingleVar()) { auto customAttrs = var->getAttachedPropertyWrappers(); - if (customAttrs.size() > 0 && customAttrs[0]->getArg() != nullptr) + if (customAttrs.size() > 0 && customAttrs[0]->hasArgs()) return true; } @@ -6107,7 +6107,7 @@ bool VarDecl::hasExternalPropertyWrapper() const { return true; // Wrappers with attribute arguments are always implementation-detail. - if (getAttachedPropertyWrappers().front()->getArg()) + if (getAttachedPropertyWrappers().front()->hasArgs()) return false; auto wrapperInfo = getAttachedPropertyWrapperTypeInfo(0); @@ -6265,7 +6265,7 @@ bool VarDecl::isPropertyMemberwiseInitializedWithWrappedType() const { // If there was an initializer on the outermost wrapper, initialize // via the full wrapper. - if (customAttrs[0]->getArg() != nullptr) + if (customAttrs[0]->hasArgs()) return false; // Default initialization does not use a value. @@ -6773,9 +6773,9 @@ ParamDecl::getDefaultValueStringRepresentation( auto wrapperAttrs = original->getAttachedPropertyWrappers(); if (wrapperAttrs.size() > 0) { auto attr = wrapperAttrs.front(); - if (auto arg = attr->getArg()) { + if (auto *args = attr->getArgs()) { SourceRange fullRange(attr->getTypeRepr()->getSourceRange().Start, - arg->getEndLoc()); + args->getEndLoc()); auto charRange = Lexer::getCharSourceRangeFromSourceRange( getASTContext().SourceMgr, fullRange); return getASTContext().SourceMgr.extractText(charRange); diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 8e3149aa01904..d7453934021b5 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -714,6 +714,18 @@ bool Expr::canAppendPostfixExpression(bool appendingPostfixOperator) const { llvm_unreachable("Unhandled ExprKind in switch."); } +ArgumentList *Expr::getArgs() const { + if (auto *AE = dyn_cast(this)) + return AE->getArgs(); + if (auto *SE = dyn_cast(this)) + return SE->getArgs(); + if (auto *DSE = dyn_cast(this)) + return DSE->getArgs(); + if (auto *OLE = dyn_cast(this)) + return OLE->getArgs(); + return nullptr; +} + llvm::DenseMap Expr::getParentMap() { class RecordingTraversal : public ASTWalker { public: @@ -1005,278 +1017,19 @@ StringLiteralExpr::StringLiteralExpr(StringRef Val, SourceRange Range, unicode::isSingleExtendedGraphemeCluster(Val); } -static ArrayRef getArgumentLabelsFromArgument( - Expr *arg, SmallVectorImpl &scratch, - SmallVectorImpl *sourceLocs = nullptr, - bool *hasTrailingClosure = nullptr, - llvm::function_ref getType = [](Expr *E) -> Type { - return E->getType(); - }) { - if (sourceLocs) sourceLocs->clear(); - if (hasTrailingClosure) *hasTrailingClosure = false; - - // A parenthesized expression is a single, unlabeled argument. - if (auto paren = dyn_cast(arg)) { - scratch.clear(); - scratch.push_back(Identifier()); - if (hasTrailingClosure) *hasTrailingClosure = paren->hasTrailingClosure(); - return scratch; - } - - // A tuple expression stores its element names, if they exist. - if (auto tuple = dyn_cast(arg)) { - if (sourceLocs && tuple->hasElementNameLocs()) { - sourceLocs->append(tuple->getElementNameLocs().begin(), - tuple->getElementNameLocs().end()); - } - - if (hasTrailingClosure) *hasTrailingClosure = tuple->hasTrailingClosure(); - - if (tuple->hasElementNames()) { - assert(tuple->getElementNames().size() == tuple->getNumElements()); - return tuple->getElementNames(); - } - - scratch.assign(tuple->getNumElements(), Identifier()); - return scratch; - } - - // Otherwise, use the type information. - auto type = getType(arg); - if (type->hasParenSugar()) { - scratch.clear(); - scratch.push_back(Identifier()); - return scratch; - } - - // FIXME: Should be a dyn_cast. - if (auto tupleTy = type->getAs()) { - scratch.clear(); - for (const auto &elt : tupleTy->getElements()) - scratch.push_back(elt.getName()); - return scratch; - } - - // FIXME: Shouldn't get here. - scratch.clear(); - scratch.push_back(Identifier()); - return scratch; -} - -/// Compute the type of an argument to a call (or call-like) AST -static void -computeSingleArgumentType(ASTContext &ctx, Expr *arg, bool implicit, - llvm::function_ref getType) { - // Propagate 'implicit' to the argument. - if (implicit) { - arg->setImplicit(true); - } - - // Handle parenthesized expressions. - if (auto paren = dyn_cast(arg)) { - if (auto type = getType(paren->getSubExpr())) { - auto parenFlags = ParameterTypeFlags().withInOut(type->is()); - arg->setType(ParenType::get(ctx, type->getInOutObjectType(), parenFlags)); - } - return; - } - - // Handle tuples. - auto tuple = dyn_cast(arg); - SmallVector typeElements; - for (unsigned i = 0, n = tuple->getNumElements(); i != n; ++i) { - auto type = getType(tuple->getElement(i)); - if (!type) return; - - bool isInOut = tuple->getElement(i)->isSemanticallyInOutExpr(); - typeElements.push_back(TupleTypeElt(type->getInOutObjectType(), - tuple->getElementName(i), - ParameterTypeFlags().withInOut(isInOut))); - } - arg->setType(TupleType::get(typeElements, ctx)); -} - -Expr *swift::packSingleArgument(ASTContext &ctx, SourceLoc lParenLoc, - ArrayRef args, - ArrayRef &argLabels, - ArrayRef &argLabelLocs, - SourceLoc rParenLoc, - ArrayRef trailingClosures, - bool implicit, - SmallVectorImpl &argLabelsScratch, - SmallVectorImpl &argLabelLocsScratch, - llvm::function_ref getType) { - // Clear out our scratch space. - argLabelsScratch.clear(); - argLabelLocsScratch.clear(); - - // Construct a TupleExpr or ParenExpr, as appropriate, for the argument. - if (trailingClosures.empty()) { - // Do we have a single, unlabeled argument? - if (args.size() == 1 && (argLabels.empty() || argLabels[0].empty())) { - auto arg = new (ctx) ParenExpr(lParenLoc, args[0], rParenLoc, - /*hasTrailingClosure=*/false); - computeSingleArgumentType(ctx, arg, implicit, getType); - argLabelsScratch.push_back(Identifier()); - argLabels = argLabelsScratch; - argLabelLocs = { }; - return arg; - } - - // Make sure we have argument labels. - if (argLabels.empty()) { - argLabelsScratch.assign(args.size(), Identifier()); - argLabels = argLabelsScratch; - } - - // Construct the argument tuple. - if (argLabels.empty() && !args.empty()) { - argLabelsScratch.assign(args.size(), Identifier()); - argLabels = argLabelsScratch; - } - - auto arg = TupleExpr::create(ctx, lParenLoc, args, argLabels, argLabelLocs, - rParenLoc, /*HasTrailingClosure=*/false, - implicit); - computeSingleArgumentType(ctx, arg, implicit, getType); - return arg; - } - - // If we have no other arguments, represent the a single trailing closure as a - // parenthesized expression. - if (args.empty() && trailingClosures.size() == 1 && - trailingClosures.front().LabelLoc.isInvalid()) { - auto &trailingClosure = trailingClosures.front(); - auto arg = - new (ctx) ParenExpr(lParenLoc, trailingClosure.ClosureExpr, rParenLoc, - /*hasTrailingClosure=*/true); - computeSingleArgumentType(ctx, arg, implicit, getType); - argLabelsScratch.push_back(Identifier()); - argLabels = argLabelsScratch; - argLabelLocs = { }; - return arg; - } - - assert(argLabels.empty() || args.size() == argLabels.size()); - - unsigned numRegularArgs = args.size(); - - // Form a tuple, including the trailing closure. - SmallVector argsScratch; - argsScratch.reserve(numRegularArgs + trailingClosures.size()); - argsScratch.append(args.begin(), args.end()); - for (const auto &closure : trailingClosures) - argsScratch.push_back(closure.ClosureExpr); - args = argsScratch; - - { - if (argLabels.empty()) { - argLabelsScratch.resize(numRegularArgs); - } else { - argLabelsScratch.append(argLabels.begin(), argLabels.end()); - } - - for (const auto &closure : trailingClosures) - argLabelsScratch.push_back(closure.Label); - - argLabels = argLabelsScratch; - } - - { - if (argLabelLocs.empty()) { - argLabelLocsScratch.resize(numRegularArgs); - } else { - argLabelLocsScratch.append(argLabelLocs.begin(), argLabelLocs.end()); - } - - for (const auto &closure : trailingClosures) - argLabelLocsScratch.push_back(closure.LabelLoc); - - argLabelLocs = argLabelLocsScratch; - } - - Optional unlabeledTrailingClosureIndex; - if (!trailingClosures.empty() && trailingClosures[0].Label.empty()) - unlabeledTrailingClosureIndex = args.size() - trailingClosures.size(); - - auto arg = TupleExpr::create(ctx, lParenLoc, rParenLoc, args, argLabels, - argLabelLocs, - unlabeledTrailingClosureIndex, - /*Implicit=*/false); - computeSingleArgumentType(ctx, arg, implicit, getType); - return arg; -} - -Optional -Expr::getUnlabeledTrailingClosureIndexOfPackedArgument() const { - if (auto PE = dyn_cast(this)) - return PE->getUnlabeledTrailingClosureIndexOfPackedArgument(); - if (auto TE = dyn_cast(this)) - return TE->getUnlabeledTrailingClosureIndexOfPackedArgument(); - return None; -} - -ObjectLiteralExpr::ObjectLiteralExpr(SourceLoc PoundLoc, LiteralKind LitKind, - Expr *Arg, - ArrayRef argLabels, - ArrayRef argLabelLocs, - bool hasTrailingClosure, - bool implicit) - : LiteralExpr(ExprKind::ObjectLiteral, implicit), - Arg(Arg), PoundLoc(PoundLoc) { - Bits.ObjectLiteralExpr.LitKind = static_cast(LitKind); - assert(getLiteralKind() == LitKind); - Bits.ObjectLiteralExpr.NumArgLabels = argLabels.size(); - Bits.ObjectLiteralExpr.HasArgLabelLocs = !argLabelLocs.empty(); - Bits.ObjectLiteralExpr.HasTrailingClosure = hasTrailingClosure; - initializeCallArguments(argLabels, argLabelLocs); +ObjectLiteralExpr::ObjectLiteralExpr(SourceLoc poundLoc, LiteralKind litKind, + ArgumentList *argList, bool implicit) + : LiteralExpr(ExprKind::ObjectLiteral, implicit), ArgList(argList), + PoundLoc(poundLoc) { + assert(argList); + Bits.ObjectLiteralExpr.LitKind = static_cast(litKind); + assert(getLiteralKind() == litKind); } ObjectLiteralExpr * ObjectLiteralExpr::create(ASTContext &ctx, SourceLoc poundLoc, LiteralKind kind, - Expr *arg, bool implicit, - llvm::function_ref getType) { - // Inspect the argument to dig out the argument labels, their location, and - // whether there is a trailing closure. - SmallVector argLabelsScratch; - SmallVector argLabelLocs; - bool hasTrailingClosure = false; - auto argLabels = getArgumentLabelsFromArgument(arg, argLabelsScratch, - &argLabelLocs, - &hasTrailingClosure, - getType); - - size_t size = totalSizeToAlloc(argLabels, argLabelLocs); - - void *memory = ctx.Allocate(size, alignof(ObjectLiteralExpr)); - return new (memory) ObjectLiteralExpr(poundLoc, kind, arg, argLabels, - argLabelLocs, hasTrailingClosure, - implicit); -} - -ObjectLiteralExpr *ObjectLiteralExpr::create(ASTContext &ctx, - SourceLoc poundLoc, - LiteralKind kind, - SourceLoc lParenLoc, - ArrayRef args, - ArrayRef argLabels, - ArrayRef argLabelLocs, - SourceLoc rParenLoc, - ArrayRef trailingClosures, - bool implicit) { - SmallVector argLabelsScratch; - SmallVector argLabelLocsScratch; - Expr *arg = packSingleArgument(ctx, lParenLoc, args, argLabels, argLabelLocs, - rParenLoc, - trailingClosures, implicit, argLabelsScratch, - argLabelLocsScratch); - - size_t size = totalSizeToAlloc(argLabels, argLabelLocs); - - void *memory = ctx.Allocate(size, alignof(ObjectLiteralExpr)); - return new (memory) ObjectLiteralExpr(poundLoc, kind, arg, argLabels, - argLabelLocs, - trailingClosures.size() == 1, implicit); + ArgumentList *args, bool implicit) { + return new (ctx) ObjectLiteralExpr(poundLoc, kind, args, implicit); } StringRef ObjectLiteralExpr::getLiteralKindRawName() const { @@ -1415,72 +1168,39 @@ DestructureTupleExpr::create(ASTContext &ctx, } SourceRange TupleExpr::getSourceRange() const { - SourceLoc start = SourceLoc(); - SourceLoc end = SourceLoc(); - if (LParenLoc.isValid()) { - start = LParenLoc; - } else if (getNumElements() == 0) { - return { SourceLoc(), SourceLoc() }; - } else { + auto start = LParenLoc; + if (start.isInvalid()) { // Scan forward for the first valid source loc. - for (Expr *expr : getElements()) { + for (auto *expr : getElements()) { start = expr->getStartLoc(); - if (start.isValid()) { + if (start.isValid()) break; - } } } - - if (hasAnyTrailingClosures() || RParenLoc.isInvalid()) { - if (getNumElements() == 0) { - return { SourceLoc(), SourceLoc() }; - } else { - // Scan backwards for a valid source loc. - bool hasSingleTrailingClosure = hasTrailingClosure(); - for (Expr *expr : llvm::reverse(getElements())) { - // Default arguments are located at the start of their parent tuple, so - // skip over them. - if (isa(expr)) - continue; - - SourceLoc newEnd = expr->getEndLoc(); - if (newEnd.isInvalid()) - continue; - - // There is a quirk with the backward scan logic for trailing - // closures that can cause arguments to be flipped. If there is a - // single trailing closure, only stop when the "end" point we hit comes - // after the close parenthesis (if there is one). - if (end.isInvalid() || - end.getOpaquePointerValue() < newEnd.getOpaquePointerValue()) { - end = newEnd; - } - if (!hasSingleTrailingClosure || RParenLoc.isInvalid() || - RParenLoc.getOpaquePointerValue() < end.getOpaquePointerValue()) - break; - } + auto end = RParenLoc; + if (end.isInvalid()) { + // Scan backwards for a valid source loc. + for (auto *expr : llvm::reverse(getElements())) { + end = expr->getEndLoc(); + if (end.isValid()) + break; } - } else { - end = RParenLoc; - } - - if (start.isValid() && end.isValid()) { - return { start, end }; - } else { - return { SourceLoc(), SourceLoc() }; } + + if (start.isInvalid() || end.isInvalid()) + return SourceRange(); + + return SourceRange(start, end); } TupleExpr::TupleExpr(SourceLoc LParenLoc, SourceLoc RParenLoc, ArrayRef SubExprs, ArrayRef ElementNames, ArrayRef ElementNameLocs, - Optional FirstTrailingArgumentAt, bool Implicit, Type Ty) : Expr(ExprKind::Tuple, Implicit, Ty), - LParenLoc(LParenLoc), RParenLoc(RParenLoc), - FirstTrailingArgumentAt(FirstTrailingArgumentAt) { + LParenLoc(LParenLoc), RParenLoc(RParenLoc) { Bits.TupleExpr.HasElementNames = !ElementNames.empty(); Bits.TupleExpr.HasElementNameLocations = !ElementNameLocs.empty(); Bits.TupleExpr.NumElements = SubExprs.size(); @@ -1513,24 +1233,7 @@ TupleExpr *TupleExpr::create(ASTContext &ctx, ArrayRef SubExprs, ArrayRef ElementNames, ArrayRef ElementNameLocs, - SourceLoc RParenLoc, - bool HasTrailingClosure, - bool Implicit, Type Ty) { - Optional FirstTrailingArgumentAt = - HasTrailingClosure ? SubExprs.size() - 1 : Optional(); - - return create(ctx, LParenLoc, RParenLoc, SubExprs, ElementNames, - ElementNameLocs, FirstTrailingArgumentAt, Implicit, Ty); -} - -TupleExpr *TupleExpr::create(ASTContext &ctx, - SourceLoc LParenLoc, - SourceLoc RParenLoc, - ArrayRef SubExprs, - ArrayRef ElementNames, - ArrayRef ElementNameLocs, - Optional FirstTrailingArgumentAt, - bool Implicit, Type Ty) { + SourceLoc RParenLoc, bool Implicit, Type Ty) { assert(!Ty || isa(Ty.getPointer())); auto hasNonEmptyIdentifier = [](ArrayRef Ids) -> bool { for (auto ident : Ids) { @@ -1550,21 +1253,19 @@ TupleExpr *TupleExpr::create(ASTContext &ctx, ElementNameLocs.size()); void *mem = ctx.Allocate(size, alignof(TupleExpr)); return new (mem) TupleExpr(LParenLoc, RParenLoc, SubExprs, ElementNames, - ElementNameLocs, - FirstTrailingArgumentAt, Implicit, Ty); + ElementNameLocs, Implicit, Ty); } TupleExpr *TupleExpr::createEmpty(ASTContext &ctx, SourceLoc LParenLoc, SourceLoc RParenLoc, bool Implicit) { - return create(ctx, LParenLoc, RParenLoc, {}, {}, {}, - /*FirstTrailingArgumentAt=*/None, Implicit, + return create(ctx, LParenLoc, {}, {}, {}, RParenLoc, Implicit, TupleType::getEmpty(ctx)); } TupleExpr *TupleExpr::createImplicit(ASTContext &ctx, ArrayRef SubExprs, ArrayRef ElementNames) { - return create(ctx, SourceLoc(), SourceLoc(), SubExprs, ElementNames, {}, - /*FirstTrailingArgumentAt=*/None, /*Implicit=*/true, Type()); + return create(ctx, SourceLoc(), SubExprs, ElementNames, {}, SourceLoc(), + /*Implicit=*/true, Type()); } ArrayExpr *ArrayExpr::create(ASTContext &C, SourceLoc LBracketLoc, @@ -1674,156 +1375,38 @@ ValueDecl *ApplyExpr::getCalledValue() const { return ::getCalledValue(Fn); } -SubscriptExpr::SubscriptExpr(Expr *base, Expr *index, - ArrayRef argLabels, - ArrayRef argLabelLocs, - bool hasTrailingClosure, - ConcreteDeclRef decl, - bool implicit, AccessSemantics semantics) - : LookupExpr(ExprKind::Subscript, base, decl, implicit), - Index(index) { +SubscriptExpr::SubscriptExpr(Expr *base, ArgumentList *argList, + ConcreteDeclRef decl, bool implicit, + AccessSemantics semantics) + : LookupExpr(ExprKind::Subscript, base, decl, implicit), ArgList(argList) { Bits.SubscriptExpr.Semantics = (unsigned) semantics; - Bits.SubscriptExpr.NumArgLabels = argLabels.size(); - Bits.SubscriptExpr.HasArgLabelLocs = !argLabelLocs.empty(); - Bits.SubscriptExpr.HasTrailingClosure = hasTrailingClosure; - initializeCallArguments(argLabels, argLabelLocs); -} - -SubscriptExpr *SubscriptExpr::create(ASTContext &ctx, Expr *base, Expr *index, - ConcreteDeclRef decl, bool implicit, - AccessSemantics semantics, - llvm::function_ref getType) { - // Inspect the argument to dig out the argument labels, their location, and - // whether there is a trailing closure. - SmallVector argLabelsScratch; - SmallVector argLabelLocs; - bool hasTrailingClosure = false; - auto argLabels = getArgumentLabelsFromArgument(index, argLabelsScratch, - &argLabelLocs, - &hasTrailingClosure, - getType); - - size_t size = totalSizeToAlloc(argLabels, argLabelLocs); - - void *memory = ctx.Allocate(size, alignof(SubscriptExpr)); - return new (memory) SubscriptExpr(base, index, argLabels, argLabelLocs, - hasTrailingClosure, decl, implicit, - semantics); } SubscriptExpr *SubscriptExpr::create(ASTContext &ctx, Expr *base, - SourceLoc lSquareLoc, - ArrayRef indexArgs, - ArrayRef indexArgLabels, - ArrayRef indexArgLabelLocs, - SourceLoc rSquareLoc, - ArrayRef trailingClosures, + ArgumentList *argList, ConcreteDeclRef decl, bool implicit, AccessSemantics semantics) { - SmallVector indexArgLabelsScratch; - SmallVector indexArgLabelLocsScratch; - Expr *index = packSingleArgument(ctx, lSquareLoc, indexArgs, indexArgLabels, - indexArgLabelLocs, rSquareLoc, - trailingClosures, implicit, - indexArgLabelsScratch, - indexArgLabelLocsScratch); - - size_t size = totalSizeToAlloc(indexArgLabels, indexArgLabelLocs); - - void *memory = ctx.Allocate(size, alignof(SubscriptExpr)); - return new (memory) SubscriptExpr(base, index, indexArgLabels, - indexArgLabelLocs, - trailingClosures.size() == 1, - decl, implicit, semantics); -} - -DynamicSubscriptExpr::DynamicSubscriptExpr(Expr *base, Expr *index, - ArrayRef argLabels, - ArrayRef argLabelLocs, - bool hasTrailingClosure, + return new (ctx) SubscriptExpr(base, argList, decl, implicit, semantics); +} + +DynamicSubscriptExpr::DynamicSubscriptExpr(Expr *base, ArgumentList *argList, ConcreteDeclRef member, bool implicit) : DynamicLookupExpr(ExprKind::DynamicSubscript, member, base), - Index(index) { - Bits.DynamicSubscriptExpr.NumArgLabels = argLabels.size(); - Bits.DynamicSubscriptExpr.HasArgLabelLocs = !argLabelLocs.empty(); - Bits.DynamicSubscriptExpr.HasTrailingClosure = hasTrailingClosure; - initializeCallArguments(argLabels, argLabelLocs); + ArgList(argList) { if (implicit) setImplicit(implicit); } -DynamicSubscriptExpr * -DynamicSubscriptExpr::create(ASTContext &ctx, Expr *base, Expr *index, - ConcreteDeclRef decl, bool implicit, - llvm::function_ref getType) { - // Inspect the argument to dig out the argument labels, their location, and - // whether there is a trailing closure. - SmallVector argLabelsScratch; - SmallVector argLabelLocs; - bool hasTrailingClosure = false; - auto argLabels = getArgumentLabelsFromArgument(index, argLabelsScratch, - &argLabelLocs, - &hasTrailingClosure, - getType); - - size_t size = totalSizeToAlloc(argLabels, argLabelLocs); - - void *memory = ctx.Allocate(size, alignof(DynamicSubscriptExpr)); - return new (memory) DynamicSubscriptExpr(base, index, argLabels, argLabelLocs, - hasTrailingClosure, decl, implicit); -} - -ArrayRef ApplyExpr::getArgumentLabels( - SmallVectorImpl &scratch) const { - // Unary operators and 'self' applications have a single, unlabeled argument. - if (isa(this) || isa(this) || - isa(this)) { - scratch.clear(); - scratch.push_back(Identifier()); - return scratch; - } - - // Binary operators have two unlabeled arguments. - if (isa(this)) { - scratch.clear(); - scratch.reserve(2); - scratch.push_back(Identifier()); - scratch.push_back(Identifier()); - return scratch; - } - - // For calls, get the argument labels directly. - auto call = cast(this); - return call->getArgumentLabels(); -} - -bool ApplyExpr::hasTrailingClosure() const { - if (auto call = dyn_cast(this)) - return call->hasTrailingClosure(); - - return false; -} - -Optional ApplyExpr::getUnlabeledTrailingClosureIndex() const { - if (auto call = dyn_cast(this)) - return call->getUnlabeledTrailingClosureIndex(); - - return None; +DynamicSubscriptExpr *DynamicSubscriptExpr::create(ASTContext &ctx, Expr *base, + ArgumentList *argList, + ConcreteDeclRef member, + bool implicit) { + return new (ctx) DynamicSubscriptExpr(base, argList, member, implicit); } -CallExpr::CallExpr(Expr *fn, Expr *arg, bool Implicit, - ArrayRef argLabels, - ArrayRef argLabelLocs, - bool hasTrailingClosure, - Type ty) - : ApplyExpr(ExprKind::Call, fn, arg, Implicit, ty) -{ - Bits.CallExpr.NumArgLabels = argLabels.size(); - Bits.CallExpr.HasArgLabelLocs = !argLabelLocs.empty(); - Bits.CallExpr.HasTrailingClosure = hasTrailingClosure; - initializeCallArguments(argLabels, argLabelLocs); - +CallExpr::CallExpr(Expr *fn, ArgumentList *argList, bool implicit, Type ty) + : ApplyExpr(ExprKind::Call, fn, argList, implicit, ty) { #ifndef NDEBUG Expr *calleeFn = fn->getSemanticsProvidingExpr(); if (auto *calleeDRE = dyn_cast(calleeFn)) @@ -1831,51 +1414,13 @@ CallExpr::CallExpr(Expr *fn, Expr *arg, bool Implicit, #endif } -CallExpr *CallExpr::create(ASTContext &ctx, Expr *fn, Expr *arg, - ArrayRef argLabels, - ArrayRef argLabelLocs, - bool hasTrailingClosure, - bool implicit, Type type, - llvm::function_ref getType) { - SmallVector argLabelsScratch; - SmallVector argLabelLocsScratch; - if (argLabels.empty()) { - // Inspect the argument to dig out the argument labels, their location, and - // whether there is a trailing closure. - argLabels = getArgumentLabelsFromArgument(arg, argLabelsScratch, - &argLabelLocsScratch, - &hasTrailingClosure, - getType); - argLabelLocs = argLabelLocsScratch; - } - - size_t size = totalSizeToAlloc(argLabels, argLabelLocs); - - void *memory = ctx.Allocate(size, alignof(CallExpr)); - return new (memory) CallExpr(fn, arg, implicit, argLabels, argLabelLocs, - hasTrailingClosure, type); +CallExpr *CallExpr::create(ASTContext &ctx, Expr *fn, ArgumentList *argList, + bool implicit) { + return new (ctx) CallExpr(fn, argList, implicit, Type()); } -CallExpr *CallExpr::create(ASTContext &ctx, Expr *fn, SourceLoc lParenLoc, - ArrayRef args, - ArrayRef argLabels, - ArrayRef argLabelLocs, - SourceLoc rParenLoc, - ArrayRef trailingClosures, - bool implicit, - llvm::function_ref getType) { - SmallVector argLabelsScratch; - SmallVector argLabelLocsScratch; - Expr *arg = packSingleArgument(ctx, lParenLoc, args, argLabels, argLabelLocs, - rParenLoc, trailingClosures, implicit, - argLabelsScratch, argLabelLocsScratch, - getType); - - size_t size = totalSizeToAlloc(argLabels, argLabelLocs); - - void *memory = ctx.Allocate(size, alignof(CallExpr)); - return new (memory) CallExpr(fn, arg, implicit, argLabels, argLabelLocs, - trailingClosures.size() == 1, Type()); +CallExpr *CallExpr::createImplicitEmpty(ASTContext &ctx, Expr *fn) { + return createImplicit(ctx, fn, ArgumentList::createImplicit(ctx, {})); } Expr *CallExpr::getDirectCallee() const { @@ -1904,26 +1449,27 @@ Expr *CallExpr::getDirectCallee() const { PrefixUnaryExpr *PrefixUnaryExpr::create(ASTContext &ctx, Expr *fn, Expr *operand, Type ty) { - return new (ctx) PrefixUnaryExpr(fn, operand, ty); + auto *argList = ArgumentList::forImplicitUnlabeled(ctx, {operand}); + return new (ctx) PrefixUnaryExpr(fn, argList, ty); } PostfixUnaryExpr *PostfixUnaryExpr::create(ASTContext &ctx, Expr *fn, Expr *operand, Type ty) { - return new (ctx) PostfixUnaryExpr(fn, operand, ty); + auto *argList = ArgumentList::forImplicitUnlabeled(ctx, {operand}); + return new (ctx) PostfixUnaryExpr(fn, argList, ty); } BinaryExpr *BinaryExpr::create(ASTContext &ctx, Expr *lhs, Expr *fn, Expr *rhs, bool implicit, Type ty) { - auto *packedArg = TupleExpr::createImplicit(ctx, {lhs, rhs}, /*labels*/ {}); - computeSingleArgumentType(ctx, packedArg, /*implicit*/ true, - [](Expr *E) { return E->getType(); }); - return new (ctx) BinaryExpr(fn, packedArg, implicit, ty); + auto *argList = ArgumentList::forImplicitUnlabeled(ctx, {lhs, rhs}); + return new (ctx) BinaryExpr(fn, argList, implicit, ty); } DotSyntaxCallExpr *DotSyntaxCallExpr::create(ASTContext &ctx, Expr *fnExpr, SourceLoc dotLoc, Expr *baseExpr, Type ty) { - return new (ctx) DotSyntaxCallExpr(fnExpr, dotLoc, baseExpr, ty); + auto *argList = ArgumentList::forImplicitUnlabeled(ctx, {baseExpr}); + return new (ctx) DotSyntaxCallExpr(fnExpr, dotLoc, argList, ty); } SourceLoc DotSyntaxCallExpr::getLoc() const { @@ -1957,7 +1503,8 @@ ConstructorRefCallExpr *ConstructorRefCallExpr::create(ASTContext &ctx, Expr *fnExpr, Expr *baseExpr, Type ty) { - return new (ctx) ConstructorRefCallExpr(fnExpr, baseExpr, ty); + auto *argList = ArgumentList::forImplicitUnlabeled(ctx, {baseExpr}); + return new (ctx) ConstructorRefCallExpr(fnExpr, argList, ty); } void ExplicitCastExpr::setCastType(Type type) { @@ -2082,7 +1629,9 @@ RebindSelfInConstructorExpr::getCalledConstructor(bool &isChainToSuper) const { otherCtorRef = dyn_cast(candidateUnwrapped); } while (!otherCtorRef); - isChainToSuper = apply->getArg()->isSuperExpr(); + auto *unaryArg = apply->getArgs()->getUnaryExpr(); + assert(unaryArg); + isChainToSuper = unaryArg->isSuperExpr(); return otherCtorRef; } @@ -2471,102 +2020,41 @@ KeyPathExpr::resolveComponents(ASTContext &C, Components = Components.slice(0, resolvedComponents.size()); } -KeyPathExpr::Component -KeyPathExpr::Component::forSubscript(ASTContext &ctx, - ConcreteDeclRef subscript, - SourceLoc lSquareLoc, - ArrayRef indexArgs, - ArrayRef indexArgLabels, - ArrayRef indexArgLabelLocs, - SourceLoc rSquareLoc, - ArrayRef trailingClosures, - Type elementType, - ArrayRef indexHashables) { - SmallVector indexArgLabelsScratch; - SmallVector indexArgLabelLocsScratch; - Expr *index = packSingleArgument(ctx, lSquareLoc, indexArgs, indexArgLabels, - indexArgLabelLocs, rSquareLoc, - trailingClosures, /*implicit*/ false, - indexArgLabelsScratch, - indexArgLabelLocsScratch); - return forSubscriptWithPrebuiltIndexExpr(subscript, index, - indexArgLabels, - elementType, - lSquareLoc, - indexHashables); +Optional KeyPathExpr::findComponentWithSubscriptArg(Expr *arg) { + for (auto idx : indices(getComponents())) { + if (auto *args = getComponents()[idx].getSubscriptArgs()) { + if (args->findArgumentExpr(arg)) + return idx; + } + } + return None; } -KeyPathExpr::Component -KeyPathExpr::Component::forUnresolvedSubscript(ASTContext &ctx, - SourceLoc lSquareLoc, - ArrayRef indexArgs, - ArrayRef indexArgLabels, - ArrayRef indexArgLabelLocs, - SourceLoc rSquareLoc, - ArrayRef trailingClosures) { - SmallVector indexArgLabelsScratch; - SmallVector indexArgLabelLocsScratch; - Expr *index = packSingleArgument( - ctx, lSquareLoc, indexArgs, indexArgLabels, indexArgLabelLocs, rSquareLoc, - trailingClosures, /*implicit*/ false, - indexArgLabelsScratch, indexArgLabelLocsScratch); - return forUnresolvedSubscriptWithPrebuiltIndexExpr(ctx, index, indexArgLabels, - lSquareLoc); -} - -KeyPathExpr::Component::Component(ASTContext *ctxForCopyingLabels, - DeclNameOrRef decl, - Expr *indexExpr, - ArrayRef subscriptLabels, - ArrayRef indexHashables, - Kind kind, - Type type, - SourceLoc loc) - : Decl(decl), SubscriptIndexExpr(indexExpr), KindValue(kind), - ComponentType(type), Loc(loc) -{ - assert(kind == Kind::Subscript || kind == Kind::UnresolvedSubscript); - assert(subscriptLabels.size() == indexHashables.size() - || indexHashables.empty()); - SubscriptLabelsData = subscriptLabels.data(); - SubscriptHashableConformancesData = indexHashables.empty() - ? nullptr : indexHashables.data(); - SubscriptSize = subscriptLabels.size(); +KeyPathExpr::Component KeyPathExpr::Component::forSubscript( + ASTContext &ctx, ConcreteDeclRef subscript, ArgumentList *argList, + Type elementType, ArrayRef indexHashables) { + return Component(subscript, argList, indexHashables, Kind::Subscript, + elementType, argList->getLParenLoc()); } KeyPathExpr::Component -KeyPathExpr::Component::forSubscriptWithPrebuiltIndexExpr( - ConcreteDeclRef subscript, Expr *index, ArrayRef labels, - Type elementType, SourceLoc loc, - ArrayRef indexHashables) { - return Component(&elementType->getASTContext(), - subscript, index, labels, indexHashables, - Kind::Subscript, elementType, loc); +KeyPathExpr::Component::forUnresolvedSubscript(ASTContext &ctx, + ArgumentList *argList) { + return Component({}, argList, {}, Kind::UnresolvedSubscript, Type(), + argList->getLParenLoc()); } -void KeyPathExpr::Component::setSubscriptIndexHashableConformances( - ArrayRef hashables) { - switch (getKind()) { - case Kind::Subscript: - assert(hashables.size() == SubscriptSize); - SubscriptHashableConformancesData = getComponentType()->getASTContext() - .AllocateCopy(hashables) - .data(); - return; - - case Kind::UnresolvedSubscript: - case Kind::Invalid: - case Kind::OptionalChain: - case Kind::OptionalWrap: - case Kind::OptionalForce: - case Kind::UnresolvedProperty: - case Kind::Property: - case Kind::Identity: - case Kind::TupleElement: - case Kind::DictionaryKey: - case Kind::CodeCompletion: - llvm_unreachable("no hashable conformances for this kind"); - } +KeyPathExpr::Component::Component( + DeclNameOrRef decl, ArgumentList *argList, + ArrayRef indexHashables, Kind kind, Type type, + SourceLoc loc) + : Decl(decl), SubscriptArgList(argList), KindValue(kind), + ComponentType(type), Loc(loc) { + assert(kind == Kind::Subscript || kind == Kind::UnresolvedSubscript); + assert(argList); + assert(argList->size() == indexHashables.size() || indexHashables.empty()); + SubscriptHashableConformancesData = indexHashables.empty() + ? nullptr : indexHashables.data(); } void InterpolatedStringLiteralExpr::forEachSegment(ASTContext &Ctx, diff --git a/test/Concurrency/async_main.swift b/test/Concurrency/async_main.swift index f3aea13eeeca5..9ff2171b43bdf 100644 --- a/test/Concurrency/async_main.swift +++ b/test/Concurrency/async_main.swift @@ -36,7 +36,8 @@ func asyncFunc() async { // CHECK-AST-SAME: type='(@escaping () async throws -> ()) -> ()' // CHECK-AST-SAME: decl=_Concurrency.(file)._runAsyncMain // CHECK-AST-SAME: function_ref=single -// CHECK-AST-NEXT: (paren_expr implicit type='(() async throws -> ())' -// CHECK-AST-NEXT: (function_conversion_expr implicit type='() async throws -> ()' -// CHECK-AST-NEXT: (dot_syntax_call_expr -// CHECK-AST-NEXT: (autoclosure_expr implicit type='(MyProgram.Type) -> () async -> ()' +// CHECK-AST-NEXT: (argument_list +// CHECK-AST-NEXT: (argument +// CHECK-AST-NEXT: (function_conversion_expr implicit type='() async throws -> ()' +// CHECK-AST-NEXT: (dot_syntax_call_expr +// CHECK-AST-NEXT: (autoclosure_expr implicit type='(MyProgram.Type) -> () async -> ()' diff --git a/test/Frontend/dump-parse.swift b/test/Frontend/dump-parse.swift index 900ad3643c816..6535e55dc8388 100644 --- a/test/Frontend/dump-parse.swift +++ b/test/Frontend/dump-parse.swift @@ -65,14 +65,16 @@ let _: (Int) -> () = generic func escaping(_: @escaping (Int) -> Int) {} escaping({ $0 }) // CHECK-AST: (declref_expr type='(@escaping (Int) -> Int) -> ()' -// CHECK-AST-NEXT: (paren_expr -// CHECK-AST-NEXT: (closure_expr type='(Int) -> Int' {{.*}} discriminator=0 escaping single-expression +// CHECK-AST-NEXT: (argument_list +// CHECK-AST-NEXT: (argument +// CHECK-AST-NEXT: (closure_expr type='(Int) -> Int' {{.*}} discriminator=0 escaping single-expression func nonescaping(_: (Int) -> Int) {} nonescaping({ $0 }) // CHECK-AST: (declref_expr type='((Int) -> Int) -> ()' -// CHECK-AST-NEXT: (paren_expr -// CHECK-AST-NEXT: (closure_expr type='(Int) -> Int' {{.*}} discriminator=1 single-expression +// CHECK-AST-NEXT: (argument_list +// CHECK-AST-NEXT: (argument +// CHECK-AST-NEXT: (closure_expr type='(Int) -> Int' {{.*}} discriminator=1 single-expression // CHECK-LABEL: (struct_decl range=[{{.+}}] "MyStruct") struct MyStruct {} @@ -117,9 +119,9 @@ struct SelfParam { // CHECK-NEXT: (component id='SelfParam' bind=none)))) static func createOptional() -> SelfParam? { - // CHECK-LABEL: (call_expr type='' arg_labels= + // CHECK-LABEL: (call_expr type='' // CHECK-NEXT: (unresolved_decl_ref_expr type='' name=SelfParam function_ref=unapplied) - // CHECK-NEXT: (tuple_expr type='()'{{.*}})) + // CHECK-NEXT: (argument_list) SelfParam() } } diff --git a/test/IDE/expr_type.swift b/test/IDE/expr_type.swift index 05190bcbcd569..91d4335d9606d 100644 --- a/test/IDE/expr_type.swift +++ b/test/IDE/expr_type.swift @@ -2,12 +2,12 @@ // RUN: %target-swift-ide-test -print-expr-type -source-filename %S/Inputs/ExprType.swift -swift-version 5 -canonicalize-type | %FileCheck %s -check-prefix=CHECK-CANON // CHECK-SUGAR: func foo() -> Int { return 1 } -// CHECK-SUGAR: func bar(f: Float) -> Float { return Float">bar(f: 1) } -// CHECK-SUGAR: func fooP(_ p: P) { ()">fooP(p) } +// CHECK-SUGAR: func bar(f: Float) -> Float { return Float">bar(f: 1) } +// CHECK-SUGAR: func fooP(_ p: P) { ()">fooP(p) } // CHECK-SUGAR: _ = a.count -// CHECK-SUGAR: _ = Int">a.description.count. (Int) -> Int">advanced(by: 1).description -// CHECK-SUGAR: _ = Int">a[2]?.val. (Int) -> Int">advanced(by: 1).byteSwapped +// CHECK-SUGAR: _ = Int">a.description.count. (Int) -> Int">advanced(by: 1).description +// CHECK-SUGAR: _ = Int">a[2]?.val. (Int) -> Int">advanced(by: 1).byteSwapped // CHECK-SUGAR: return a Int">+ b -// CHECK-CANON: return a Int">+ b \ No newline at end of file +// CHECK-CANON: return a Int">+ b diff --git a/test/IDE/range_info_expr.swift b/test/IDE/range_info_expr.swift index dea627e54fd7e..2334b9c077d66 100644 --- a/test/IDE/range_info_expr.swift +++ b/test/IDE/range_info_expr.swift @@ -67,7 +67,7 @@ func bar(x: SR12957 = .main) {} // CHECK-PART-EXPR-NEXT: getSelf() // CHECK-PART-EXPR-NEXT: swift_ide_test.(file).foo1(_:) // CHECK-PART-EXPR-NEXT: Call -// CHECK-PART-EXPR-NEXT: 2 +// CHECK-PART-EXPR-NEXT: 1 // CHECK-PART-EXPR-NEXT: // CHECK-PART-EXPR1: PartOfExpression diff --git a/test/Sema/property_wrappers.swift b/test/Sema/property_wrappers.swift index d15e69de95833..dc2bf3fda765f 100644 --- a/test/Sema/property_wrappers.swift +++ b/test/Sema/property_wrappers.swift @@ -17,10 +17,11 @@ struct WrapperWithClosureArg { // rdar://problem/59685601 // CHECK-LABEL: R_59685601 struct R_59685601 { - // CHECK: tuple_expr implicit type='(wrappedValue: String, reset: (String, inout Transaction) -> Void)' - // CHECK-NEXT: property_wrapper_value_placeholder_expr implicit type='String' - // CHECK-NEXT: opaque_value_expr implicit type='String' - // CHECK-NEXT: string_literal_expr type='String' + // CHECK: argument_list implicit labels=wrappedValue:reset: + // CHECK-NEXT: argument label=wrappedValue + // CHECK-NEXT: property_wrapper_value_placeholder_expr implicit type='String' + // CHECK-NEXT: opaque_value_expr implicit type='String' + // CHECK-NEXT: string_literal_expr type='String' @WrapperWithClosureArg(reset: { value, transaction in transaction.state = 10 }) @@ -36,11 +37,13 @@ struct Wrapper { struct TestInitSubscript { enum Color: CaseIterable { case pink } - // CHECK: tuple_expr type='(wrappedValue: TestInitSubscript.Color)' - // CHECK: subscript_expr type='TestInitSubscript.Color' - // CHECK: paren_expr type='(Int)' - // CHECK-NOT: property_wrapper_value_placeholder_expr implicit type='Int' - // CHECK: integer_literal_expr type='Int' + // CHECK: argument_list labels=wrappedValue: + // CHECK-NEXT: argument label=wrappedValue + // CHECK-NEXT: subscript_expr type='TestInitSubscript.Color' + // CHECK: argument_list implicit + // CHECK-NEXT: argument + // CHECK-NOT: property_wrapper_value_placeholder_expr implicit type='Int' + // CHECK: integer_literal_expr type='Int' @Wrapper(wrappedValue: Color.allCases[0]) var color: Color } diff --git a/test/Sema/type_eraser.swift b/test/Sema/type_eraser.swift index b337cf74d490e..7dee74c1462d9 100644 --- a/test/Sema/type_eraser.swift +++ b/test/Sema/type_eraser.swift @@ -11,18 +11,22 @@ struct ConcreteP: P, Hashable {} // CHECK-LABEL: testBasic dynamic func testBasic() -> some P { - // CHECK: underlying_to_opaque_expr{{.*}}'some P' - // CHECK-NEXT: call_expr implicit type='AnyP'{{.*}}arg_labels=erasing: - // CHECK: call_expr type='ConcreteP' + // CHECK: underlying_to_opaque_expr{{.*}}'some P' + // CHECK-NEXT: call_expr implicit type='AnyP' + // CHECK: argument_list implicit labels=erasing: + // CHECK-NEXT: argument label=erasing + // CHECK-NEXT: call_expr type='ConcreteP' ConcreteP() } // CHECK-LABEL: testTypeAlias typealias AliasForP = P dynamic func testTypeAlias() -> some AliasForP { - // CHECK: underlying_to_opaque_expr{{.*}}'some P' - // CHECK-NEXT: call_expr implicit type='AnyP'{{.*}}arg_labels=erasing: - // CHECK: call_expr type='ConcreteP' + // CHECK: underlying_to_opaque_expr{{.*}}'some P' + // CHECK-NEXT: call_expr implicit type='AnyP' + // CHECK: argument_list implicit labels=erasing: + // CHECK-NEXT: argument label=erasing + // CHECK-NEXT: call_expr type='ConcreteP' ConcreteP() } @@ -61,10 +65,12 @@ struct Builder { class TestResultBuilder { // CHECK-LABEL: testTransformFnBody @Builder dynamic var testTransformFnBody: some P { - // CHECK: return_stmt - // CHECK-NEXT: underlying_to_opaque_expr implicit type='some P' - // CHECK-NEXT: call_expr implicit type='AnyP'{{.*}}arg_labels=erasing: - // CHECK: declref_expr implicit type='@lvalue ConcreteP' + // CHECK: return_stmt + // CHECK-NEXT: underlying_to_opaque_expr implicit type='some P' + // CHECK-NEXT: call_expr implicit type='AnyP' + // CHECK: argument_list implicit labels=erasing: + // CHECK-NEXT: argument label=erasing + // CHECK: declref_expr implicit type='@lvalue ConcreteP' ConcreteP() } @@ -73,9 +79,11 @@ class TestResultBuilder { // CHECK-LABEL: testClosureBuilder dynamic var testClosureBuilder: some P { - // CHECK: underlying_to_opaque_expr implicit type='some P' - // CHECK-NEXT: call_expr implicit type='AnyP'{{.*}}arg_labels=erasing: - // CHECK: closure_expr type='() -> ConcreteP' + // CHECK: underlying_to_opaque_expr implicit type='some P' + // CHECK-NEXT: call_expr implicit type='AnyP' + // CHECK: argument_list implicit labels=erasing: + // CHECK-NEXT: argument label=erasing + // CHECK: closure_expr type='() -> ConcreteP' takesBuilder { // CHECK: return_stmt // CHECK-NEXT: load_expr implicit type='ConcreteP' @@ -87,9 +95,11 @@ class TestResultBuilder { // CHECK-LABEL: class_decl{{.*}}DynamicReplacement class DynamicReplacement { dynamic func testDynamicReplaceable() -> some P { - // CHECK: underlying_to_opaque_expr implicit type='some P' - // CHECK-NEXT: call_expr implicit type='AnyP'{{.*}}arg_labels=erasing: - // CHECK: call_expr type='ConcreteP' + // CHECK: underlying_to_opaque_expr implicit type='some P' + // CHECK-NEXT: call_expr implicit type='AnyP' + // CHECK: argument_list implicit labels=erasing: + // CHECK-NEXT: argument label=erasing + // CHECK-NEXT: call_expr type='ConcreteP' ConcreteP() } } @@ -100,10 +110,12 @@ extension DynamicReplacement { @_dynamicReplacement(for: testDynamicReplaceable) func testDynamicReplacement() -> some P { print("not single expr return") - // CHECK: return_stmt - // CHECK-NEXT: underlying_to_opaque_expr implicit type='some P' - // CHECK-NEXT: call_expr implicit type='AnyP'{{.*}}arg_labels=erasing: - // CHECK: call_expr type='ConcreteP' + // CHECK: return_stmt + // CHECK-NEXT: underlying_to_opaque_expr implicit type='some P' + // CHECK-NEXT: call_expr implicit type='AnyP' + // CHECK: argument_list implicit labels=erasing: + // CHECK-NEXT: argument label=erasing + // CHECK-NEXT: call_expr type='ConcreteP' return ConcreteP() } } diff --git a/test/SourceKit/ExpressionType/basic.swift b/test/SourceKit/ExpressionType/basic.swift index a4832ffde5fdc..97887beb2e1dd 100644 --- a/test/SourceKit/ExpressionType/basic.swift +++ b/test/SourceKit/ExpressionType/basic.swift @@ -25,7 +25,6 @@ func DictS(_ a: [Int: S]) { // CHECK: (183, 196): String // CHECK: (183, 184): [C] // CHECK: (203, 211): (Int) -> (Int) -> Int -// CHECK: (211, 218): (by: Int) // CHECK: (216, 217): Int // CHECK: (257, 258): Int // CHECK: (291, 332): () From a5775482eec056d7bb76ef2e6f663fc50b6e5b20 Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Wed, 1 Sep 2021 18:40:24 +0100 Subject: [PATCH 03/14] [Parser] Adopt ArgumentList Split up the expr list parsing members such that there are separate entry points for tuple and argument list parsing, and start using the argument list parsing member for call and subscripts. --- include/swift/Parse/Parser.h | 40 +++-- lib/Parse/ParseDecl.cpp | 29 ++-- lib/Parse/ParseExpr.cpp | 309 ++++++++++++++--------------------- lib/Parse/ParseIfConfig.cpp | 66 ++++---- lib/Parse/ParsePattern.cpp | 22 +-- lib/Parse/ParseStmt.cpp | 23 +-- 6 files changed, 205 insertions(+), 284 deletions(-) diff --git a/include/swift/Parse/Parser.h b/include/swift/Parse/Parser.h index 132c971e43a17..3611bf98ce5e0 100644 --- a/include/swift/Parse/Parser.h +++ b/include/swift/Parse/Parser.h @@ -1695,24 +1695,32 @@ class Parser { SourceLoc &inLoc); Expr *parseExprAnonClosureArg(); - ParserResult parseExprList(tok LeftTok, tok RightTok, - syntax::SyntaxKind Kind); - /// Parse an expression list, keeping all of the pieces separated. - ParserStatus parseExprList(tok leftTok, tok rightTok, - bool isPostfix, - bool isExprBasic, - SourceLoc &leftLoc, - SmallVectorImpl &exprs, - SmallVectorImpl &exprLabels, - SmallVectorImpl &exprLabelLocs, - SourceLoc &rightLoc, - SmallVectorImpl &trailingClosures, - syntax::SyntaxKind Kind); + /// An element of an expression list, which may become e.g a tuple element or + /// argument list argument. + struct ExprListElt { + SourceLoc LabelLoc; + Identifier Label; + Expr *E; + }; - ParserStatus - parseTrailingClosures(bool isExprBasic, SourceRange calleeRange, - SmallVectorImpl &closures); + /// Parse a tuple or paren expr. + ParserResult parseTupleOrParenExpr(tok leftTok, tok rightTok); + + /// Parse an argument list. + ParserResult + parseArgumentList(tok leftTok, tok rightTok, bool isExprBasic, + bool allowTrailingClosure = true); + + /// Parse one or more trailing closures after an argument list. + ParserStatus parseTrailingClosures(bool isExprBasic, SourceRange calleeRange, + SmallVectorImpl &closures); + + /// Parse an expression list. + ParserStatus parseExprList(tok leftTok, tok rightTok, bool isArgumentList, + SourceLoc &leftLoc, + SmallVectorImpl &elts, + SourceLoc &rightLoc, SyntaxKind Kind); /// Parse an object literal. /// diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index a552cef9991c8..22651357fdf8c 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -2762,18 +2762,11 @@ ParserResult Parser::parseCustomAttribute( return ParserResult(ParserStatus(type)); } - // Parse the optional arguments. - SourceLoc lParenLoc, rParenLoc; - SmallVector args; - SmallVector argLabels; - SmallVector argLabelLocs; - SmallVector trailingClosures; - bool hasInitializer = false; - // If we're not in a local context, we'll need a context to parse // initializers into (should we have one). This happens for properties // and global variables in libraries. ParserStatus status; + ArgumentList *argList = nullptr; if (Tok.isFollowingLParen() && isCustomAttributeArgument()) { if (peekToken().is(tok::code_complete)) { consumeToken(tok::l_paren); @@ -2800,22 +2793,20 @@ ParserResult Parser::parseCustomAttribute( initParser.emplace(*this, initContext); } - status |= parseExprList(tok::l_paren, tok::r_paren, - /*isPostfix=*/false, /*isExprBasic=*/true, - lParenLoc, args, argLabels, argLabelLocs, - rParenLoc, - trailingClosures, - SyntaxKind::TupleExprElementList); - assert(trailingClosures.empty() && "Cannot parse a trailing closure here"); - hasInitializer = true; + auto result = parseArgumentList(tok::l_paren, tok::r_paren, + /*isExprBasic*/ true, + /*allowTrailingClosure*/ false); + status |= result; + argList = result.get(); + assert(!argList->hasAnyTrailingClosures() && + "Cannot parse a trailing closure here"); } } // Form the attribute. auto *TE = new (Context) TypeExpr(type.get()); - auto customAttr = CustomAttr::create(Context, atLoc, TE, hasInitializer, - initContext, lParenLoc, args, argLabels, - argLabelLocs, rParenLoc); + auto *customAttr = CustomAttr::create(Context, atLoc, TE, initContext, + argList); return makeParserResult(status, customAttr); } diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index bf6a6c5438627..de8ff948e7480 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -501,17 +501,6 @@ ParserResult Parser::parseExprSequenceElement(Diag<> message, return sub; } -static Expr *formUnaryArgument(ASTContext &context, Expr *argument) { - if (isa(argument)) - return argument; - - auto *arg = new (context) - ParenExpr(argument->getStartLoc(), argument, argument->getEndLoc(), - /*hasTrailingClosure*/ false); - arg->setImplicit(); - return arg; -} - /// parseExprUnary /// /// expr-unary(Mode): @@ -586,8 +575,7 @@ ParserResult Parser::parseExprUnary(Diag<> Message, bool isExprBasic) { } } - auto *opCall = PrefixUnaryExpr::create( - Context, Operator, formUnaryArgument(Context, SubExpr.get())); + auto *opCall = PrefixUnaryExpr::create(Context, Operator, SubExpr.get()); return makeParserResult(Status, opCall); } @@ -1237,23 +1225,10 @@ Parser::parseExprPostfixSuffix(ParserResult Result, bool isExprBasic, // Check for a [expr] suffix. // Note that this cannot be the start of a new line. if (Tok.isFollowingLSquare()) { - SourceLoc lSquareLoc, rSquareLoc; - SmallVector indexArgs; - SmallVector indexArgLabels; - SmallVector indexArgLabelLocs; - SmallVector trailingClosures; - - ParserStatus status = parseExprList( - tok::l_square, tok::r_square, - /*isPostfix=*/true, isExprBasic, lSquareLoc, indexArgs, - indexArgLabels, indexArgLabelLocs, rSquareLoc, - trailingClosures, SyntaxKind::TupleExprElementList); - Result = makeParserResult( - status | Result, - SubscriptExpr::create(Context, Result.get(), lSquareLoc, indexArgs, - indexArgLabels, indexArgLabelLocs, rSquareLoc, - trailingClosures, ConcreteDeclRef(), - /*implicit=*/false)); + auto args = parseArgumentList(tok::l_square, tok::r_square, isExprBasic); + auto *subscript = SubscriptExpr::create(Context, Result.get(), + args.get()); + Result = makeParserResult(ParserStatus(args) | Result, subscript); SyntaxContext->createNodeInPlace(SyntaxKind::SubscriptExpr); continue; } @@ -1275,7 +1250,7 @@ Parser::parseExprPostfixSuffix(ParserResult Result, bool isExprBasic, leadingTriviaLoc(), *SyntaxContext)); } - SmallVector trailingClosures; + SmallVector trailingClosures; auto trailingResult = parseTrailingClosures(isExprBasic, callee->getSourceRange(), trailingClosures); @@ -1283,11 +1258,12 @@ Parser::parseExprPostfixSuffix(ParserResult Result, bool isExprBasic, return nullptr; // Trailing closure implicitly forms a call. + auto *argList = ArgumentList::create(Context, SourceLoc(), + trailingClosures, + SourceLoc(), /*implicit*/ false); Result = makeParserResult( ParserStatus(Result) | trailingResult, - CallExpr::create(Context, Result.get(), SourceLoc(), {}, {}, {}, - SourceLoc(), trailingClosures, - /*implicit=*/false)); + CallExpr::create(Context, Result.get(), argList, /*implicit*/ false)); SyntaxContext->createNodeInPlace(SyntaxKind::FunctionCallExpr); // We only allow a single trailing closure on a call. This could be @@ -1323,9 +1299,8 @@ Parser::parseExprPostfixSuffix(ParserResult Result, bool isExprBasic, Expr *oper = parseExprOperator(); - auto *opCall = PostfixUnaryExpr::create( - Context, oper, formUnaryArgument(Context, Result.get())); - Result = makeParserResult(Result, opCall); + Result = makeParserResult( + Result, PostfixUnaryExpr::create(Context, oper, Result.get())); SyntaxContext->createNodeInPlace(SyntaxKind::PostfixUnaryExpr); continue; } @@ -1743,8 +1718,7 @@ ParserResult Parser::parseExprPrimary(Diag<> ID, bool isExprBasic) { // differentiation. A tuple expression node in libSyntax can have a single // element without label. ExprContext.setCreateSyntax(SyntaxKind::TupleExpr); - return parseExprList(tok::l_paren, tok::r_paren, - SyntaxKind::TupleExprElementList); + return parseTupleOrParenExpr(tok::l_paren, tok::r_paren); case tok::l_square: return parseExprCollection(); @@ -1873,8 +1847,9 @@ parseStringSegments(SmallVectorImpl &Segments, appendLiteral, /*nameloc=*/DeclNameLoc(), /*Implicit=*/true); + auto *ArgList = ArgumentList::forImplicitUnlabeled(Context, {Literal}); auto AppendLiteralCall = - CallExpr::createImplicit(Context, AppendLiteralRef, {Literal}, {}); + CallExpr::createImplicit(Context, AppendLiteralRef, ArgList); Stmts.push_back(AppendLiteralCall); // Since the string is already parsed, Tok already points to the first @@ -3066,70 +3041,99 @@ Expr *Parser::parseExprAnonClosureArg() { /*Implicit=*/false); } - -/// parseExprList - Parse a list of expressions. +/// parseTupleOrParenExpr - Parse a tuple or paren expression. /// /// expr-paren: /// lparen-any ')' -/// lparen-any binary-op ')' /// lparen-any expr-paren-element (',' expr-paren-element)* ')' /// /// expr-paren-element: /// (identifier ':')? expr /// -ParserResult -Parser::parseExprList(tok leftTok, tok rightTok, SyntaxKind Kind) { - SmallVector subExprs; - SmallVector subExprNames; - SmallVector subExprNameLocs; - SmallVector trailingClosures; - +ParserResult Parser::parseTupleOrParenExpr(tok leftTok, tok rightTok) { + SmallVector elts; SourceLoc leftLoc, rightLoc; - ParserStatus status = parseExprList(leftTok, rightTok, /*isPostfix=*/false, - /*isExprBasic=*/true, - leftLoc, - subExprs, - subExprNames, - subExprNameLocs, - rightLoc, - trailingClosures, - Kind); + auto status = + parseExprList(leftTok, rightTok, /*isArgumentList*/ false, leftLoc, elts, + rightLoc, SyntaxKind::TupleExprElementList); // A tuple with a single, unlabeled element is just parentheses. - if (subExprs.size() == 1 && - (subExprNames.empty() || subExprNames[0].empty())) { + if (elts.size() == 1 && elts[0].Label.empty()) { return makeParserResult( - status, new (Context) ParenExpr(leftLoc, subExprs[0], rightLoc, - /*hasTrailingClosure=*/false)); + status, new (Context) ParenExpr(leftLoc, elts[0].E, rightLoc)); } - return makeParserResult( - status, - TupleExpr::create(Context, leftLoc, subExprs, subExprNames, - subExprNameLocs, rightLoc, /*HasTrailingClosure=*/false, - /*Implicit=*/false)); + SmallVector exprs; + SmallVector labels; + SmallVector labelLocs; + for (auto &elt : elts) { + exprs.push_back(elt.E); + labels.push_back(elt.Label); + labelLocs.push_back(elt.LabelLoc); + } + return makeParserResult(status, TupleExpr::create(Context, leftLoc, exprs, + labels, labelLocs, rightLoc, + /*implicit*/ false)); +} + +/// parseArgumentList - Parse an argument list. +/// +/// arg-list: +/// lparen-any ')' +/// lparen-any argument (',' argument)* ')' +/// +/// argument: +/// (identifier ':')? '&'? expr +/// +ParserResult +Parser::parseArgumentList(tok leftTok, tok rightTok, bool isExprBasic, + bool allowTrailingClosure) { + SourceLoc leftLoc, rightLoc; + SmallVector elts; + + // FIXME: Introduce new SyntaxKind for ArgumentList (rdar://81786229) + auto status = + parseExprList(leftTok, rightTok, /*isArgumentList*/ true, leftLoc, elts, + rightLoc, SyntaxKind::TupleExprElementList); + + SmallVector args; + for (auto &elt : elts) + args.emplace_back(elt.LabelLoc, elt.Label, elt.E); + + auto numNonTrailing = args.size(); + Optional trailingClosureIndex; + bool hasMultipleTrailing = false; + + // If we can parse trailing closures, do so. + if (allowTrailingClosure && Tok.is(tok::l_brace) && + isValidTrailingClosure(isExprBasic, *this)) { + status |= parseTrailingClosures(isExprBasic, SourceRange(leftLoc, rightLoc), + args); + auto numTrailing = args.size() - numNonTrailing; + if (numTrailing > 0) { + trailingClosureIndex = numNonTrailing; + hasMultipleTrailing = numTrailing > 1; + } + } + auto *argList = ArgumentList::create(Context, leftLoc, args, rightLoc, + trailingClosureIndex, + hasMultipleTrailing, /*implicit*/ false); + return makeParserResult(status, argList); } /// parseExprList - Parse a list of expressions. /// -/// expr-paren: +/// expr-list: /// lparen-any ')' -/// lparen-any binary-op ')' -/// lparen-any expr-paren-element (',' expr-paren-element)* ')' +/// lparen-any expr-list-element (',' expr-list-element)* ')' /// -/// expr-paren-element: -/// (identifier ':')? expr +/// expr-list-element: +/// (identifier ':')? '&'? expr /// ParserStatus Parser::parseExprList(tok leftTok, tok rightTok, - bool isPostfix, - bool isExprBasic, - SourceLoc &leftLoc, - SmallVectorImpl &exprs, - SmallVectorImpl &exprLabels, - SmallVectorImpl &exprLabelLocs, - SourceLoc &rightLoc, - SmallVectorImpl &trailingClosures, - SyntaxKind Kind) { + bool isArgumentList, SourceLoc &leftLoc, + SmallVectorImpl &elts, + SourceLoc &rightLoc, SyntaxKind Kind) { StructureMarkerRAII ParsingExprList(*this, Tok); if (ParsingExprList.isFailed()) { @@ -3137,13 +3141,10 @@ ParserStatus Parser::parseExprList(tok leftTok, tok rightTok, } leftLoc = consumeToken(leftTok); - ParserStatus status = parseList(rightTok, leftLoc, rightLoc, - /*AllowSepAfterLast=*/false, - rightTok == tok::r_paren - ? diag::expected_rparen_expr_list - : diag::expected_rsquare_expr_list, - Kind, - [&] () -> ParserStatus { + return parseList(rightTok, leftLoc, rightLoc, /*AllowSepAfterLast=*/false, + rightTok == tok::r_paren ? diag::expected_rparen_expr_list + : diag::expected_rsquare_expr_list, + Kind, [&] () -> ParserStatus { Identifier FieldName; SourceLoc FieldNameLoc; if (Kind != SyntaxKind::YieldStmt) @@ -3168,7 +3169,7 @@ ParserStatus Parser::parseExprList(tok leftTok, tok rightTok, // context. SubExpr = new(Context) UnresolvedDeclRefExpr(OperName, DeclRefKind::Ordinary, Loc); - } else if (isPostfix && Tok.is(tok::code_complete)) { + } else if (isArgumentList && Tok.is(tok::code_complete)) { // Handle call arguments specially because it may need argument labels. auto CCExpr = new (Context) CodeCompletionExpr(Tok.getLoc()); if (CodeCompletion) @@ -3183,37 +3184,11 @@ ParserStatus Parser::parseExprList(tok leftTok, tok rightTok, } // If we got a subexpression, add it. - if (SubExpr) { - // Update names and locations. - if (!exprLabels.empty()) { - exprLabels.push_back(FieldName); - exprLabelLocs.push_back(FieldNameLoc); - } else if (FieldNameLoc.isValid()) { - exprLabels.resize(exprs.size()); - exprLabels.push_back(FieldName); - - exprLabelLocs.resize(exprs.size()); - exprLabelLocs.push_back(FieldNameLoc); - } - - // Add the subexpression. - exprs.push_back(SubExpr); - } + if (SubExpr) + elts.push_back({FieldNameLoc, FieldName, SubExpr}); return Status; }); - - // If we aren't interested in trailing closures, or there isn't a valid one, - // we're done. - if (!isPostfix || Tok.isNot(tok::l_brace) || - !isValidTrailingClosure(isExprBasic, *this)) - return status; - - // Parse the closure. - status |= - parseTrailingClosures(isExprBasic, SourceRange(leftLoc, rightLoc), - trailingClosures); - return status; } static bool isStartOfLabelledTrailingClosure(Parser &P) { @@ -3244,7 +3219,7 @@ static bool isStartOfLabelledTrailingClosure(Parser &P) { ParserStatus Parser::parseTrailingClosures(bool isExprBasic, SourceRange calleeRange, - SmallVectorImpl &closures) { + SmallVectorImpl &closures) { SourceLoc braceLoc = Tok.getLoc(); // Record the line numbers for the diagnostics below. @@ -3262,7 +3237,7 @@ Parser::parseTrailingClosures(bool isExprBasic, SourceRange calleeRange, result |= closure; - closures.push_back({closure.get()}); + closures.push_back(Argument::unlabeled(closure.get())); // Warn if the trailing closure is separated from its callee by more than // one line. A single-line separation is acceptable for a trailing closure @@ -3271,7 +3246,7 @@ Parser::parseTrailingClosures(bool isExprBasic, SourceRange calleeRange, diagnose(braceLoc, diag::trailing_closure_after_newlines); diagnose(calleeRange.Start, diag::trailing_closure_callee_here); - auto *CE = dyn_cast(closures[0].ClosureExpr); + auto *CE = dyn_cast(closures[0].getExpr()); if (CE && CE->hasAnonymousClosureVars() && CE->getParameters()->size() == 0) { diagnose(braceLoc, diag::brace_stmt_suggest_do) @@ -3308,7 +3283,7 @@ Parser::parseTrailingClosures(bool isExprBasic, SourceRange calleeRange, CodeCompletion->completeLabeledTrailingClosure(CCExpr, Tok.isAtStartOfLine()); consumeToken(tok::code_complete); result.setHasCodeCompletionAndIsError(); - closures.push_back({Identifier(), SourceLoc(), CCExpr}); + closures.emplace_back(SourceLoc(), Identifier(), CCExpr); continue; } @@ -3340,7 +3315,7 @@ Parser::parseTrailingClosures(bool isExprBasic, SourceRange calleeRange, return makeParserError(); result |= closure; - closures.push_back({label, labelLoc, closure.get()}); + closures.emplace_back(labelLoc, label, closure.get()); // Don't diagnose whitespace gaps before labelled closures. } @@ -3367,28 +3342,15 @@ Parser::parseExprObjectLiteral(ObjectLiteralExpr::LiteralKind LitKind, } // Parse the argument list. - SourceLoc lParenLoc, rParenLoc; - SmallVector args; - SmallVector argLabels; - SmallVector argLabelLocs; - SmallVector trailingClosures; - - ParserStatus status = parseExprList(tok::l_paren, tok::r_paren, - /*isPostfix=*/true, isExprBasic, - lParenLoc, args, argLabels, - argLabelLocs, - rParenLoc, - trailingClosures, - SyntaxKind::TupleExprElementList); - if (status.hasCodeCompletion()) + auto argList = parseArgumentList(tok::l_paren, tok::r_paren, isExprBasic); + if (argList.hasCodeCompletion()) return makeParserCodeCompletionResult(); - if (status.isErrorOrHasCompletion()) + if (argList.isParseErrorOrHasCompletion()) return makeParserError(); - return makeParserResult( - ObjectLiteralExpr::create(Context, PoundLoc, LitKind, lParenLoc, args, - argLabels, argLabelLocs, rParenLoc, - trailingClosures, /*implicit=*/false)); + return makeParserResult(ObjectLiteralExpr::create(Context, PoundLoc, LitKind, + argList.get(), + /*implicit*/ false)); } /// Parse and diagnose unknown pound expression @@ -3409,22 +3371,16 @@ ParserResult Parser::parseExprPoundUnknown(SourceLoc LSquareLoc) { SourceLoc NameLoc = consumeIdentifier(Name, /*diagnoseDollarPrefix=*/false); // Parse arguments if exist. - SourceLoc LParenLoc, RParenLoc; - SmallVector argLabelLocs; - SmallVector args; - SmallVector argLabels; - SmallVector trailingClosures; + ArgumentList *ArgList = nullptr; if (Tok.isFollowingLParen()) { // Parse arguments. - ParserStatus status = - parseExprList(tok::l_paren, tok::r_paren, - /*isPostfix=*/true, /*isExprBasic*/ true, LParenLoc, - args, argLabels, argLabelLocs, RParenLoc, - trailingClosures, SyntaxKind::TupleExprElementList); - if (status.hasCodeCompletion()) + auto result = parseArgumentList(tok::l_paren, tok::r_paren, + /*isExprBasic*/ true); + if (result.hasCodeCompletion()) return makeParserCodeCompletionResult(); - if (status.isErrorOrHasCompletion()) + if (result.isParseErrorOrHasCompletion()) return makeParserError(); + ArgList = result.get(); } std::pair NewNameArgPair = @@ -3443,7 +3399,7 @@ ParserResult Parser::parseExprPoundUnknown(SourceLoc LSquareLoc) { // Diagnose legacy object literal. // Didn't have arguments. - if (LParenLoc.isInvalid()) { + if (!ArgList || ArgList->getLParenLoc().isInvalid()) { diagnose(Tok.getLoc(), diag::expected_arg_list_in_object_literal); return makeParserError(); } @@ -3463,8 +3419,8 @@ ParserResult Parser::parseExprPoundUnknown(SourceLoc LSquareLoc) { // Replace the literal name. diag.fixItReplace(NameLoc, NewNameArgPair.first); // Replace the first argument. - if (!argLabelLocs.empty() && argLabelLocs[0].isValid()) - diag.fixItReplace(argLabelLocs[0], NewNameArgPair.second); + if (!ArgList->empty() && ArgList->front().getLabelLoc().isValid()) + diag.fixItReplace(ArgList->front().getLabelLoc(), NewNameArgPair.second); // Remove '#]' if exist. if (RPoundLoc.isValid()) diag.fixItRemove( @@ -3501,26 +3457,17 @@ ParserResult Parser::parseExprCallSuffix(ParserResult fn, bool isExprBasic) { assert(Tok.isFollowingLParen() && "Not a call suffix?"); - SourceLoc lParenLoc, rParenLoc; - SmallVector args; - SmallVector argLabels; - SmallVector argLabelLocs; - SmallVector trailingClosures; - // If there is a code completion token right after the '(', do a special case // callback. if (peekToken().is(tok::code_complete) && CodeCompletion) { - lParenLoc = consumeToken(tok::l_paren); + auto lParenLoc = consumeToken(tok::l_paren); auto CCE = new (Context) CodeCompletionExpr(Tok.getLoc()); - rParenLoc = Tok.getLoc(); - auto Result = makeParserResult(fn, - CallExpr::create(Context, fn.get(), lParenLoc, - { CCE }, - { Identifier() }, - { }, - rParenLoc, - /*trailingClosures=*/{}, - /*implicit=*/false)); + auto rParenLoc = Tok.getLoc(); + auto *argList = ArgumentList::create(Context, lParenLoc, + {Argument::unlabeled(CCE)}, rParenLoc, + /*implicit*/ false); + auto Result = makeParserResult( + fn, CallExpr::create(Context, fn.get(), argList, /*implicit*/ false)); CodeCompletion->completePostfixExprParen(fn.get(), CCE); // Eat the code completion token because we handled it. consumeToken(tok::code_complete); @@ -3529,19 +3476,11 @@ Parser::parseExprCallSuffix(ParserResult fn, bool isExprBasic) { } // Parse the argument list. - ParserStatus status = parseExprList(tok::l_paren, tok::r_paren, - /*isPostfix=*/true, isExprBasic, - lParenLoc, args, argLabels, - argLabelLocs, - rParenLoc, - trailingClosures, - SyntaxKind::TupleExprElementList); + auto argList = parseArgumentList(tok::l_paren, tok::r_paren, isExprBasic); // Form the call. - return makeParserResult(status | fn, - CallExpr::create(Context, fn.get(), lParenLoc, args, - argLabels, argLabelLocs, rParenLoc, - trailingClosures, + return makeParserResult(ParserStatus(argList) | fn, + CallExpr::create(Context, fn.get(), argList.get(), /*implicit=*/false)); } @@ -3749,7 +3688,7 @@ void Parser::validateCollectionElement(ParserResult element) { auto arrayExpr = cast(subscriptExpr->getBase()); - auto startLocOfSubscript = subscriptExpr->getIndex()->getStartLoc(); + auto startLocOfSubscript = subscriptExpr->getArgs()->getStartLoc(); auto endLocOfArray = arrayExpr->getEndLoc(); auto locForEndOfTokenArray = L->getLocForEndOfToken(SourceMgr, endLocOfArray); diff --git a/lib/Parse/ParseIfConfig.cpp b/lib/Parse/ParseIfConfig.cpp index ead8f66571705..38ed8cc8621dc 100644 --- a/lib/Parse/ParseIfConfig.cpp +++ b/lib/Parse/ParseIfConfig.cpp @@ -76,18 +76,18 @@ static bool isValidVersion(const version::Version &Version, llvm_unreachable("unsupported unary operator"); } -static llvm::VersionTuple getCanImportVersion(TupleExpr *te, +static llvm::VersionTuple getCanImportVersion(ArgumentList *args, DiagnosticEngine *D, bool &underlyingVersion) { llvm::VersionTuple result; - if (te->getElements().size() != 2) { + if (args->size() != 2) { if (D) { - D->diagnose(te->getLoc(), diag::canimport_two_parameters); + D->diagnose(args->getLoc(), diag::canimport_two_parameters); } return result; } - auto label = te->getElementName(1); - auto subE = te->getElement(1); + auto label = args->getLabel(1); + auto subE = args->getExpr(1); if (label.str() == "_version") { underlyingVersion = false; } else if (label.str() == "_underlyingVersion") { @@ -114,20 +114,18 @@ static llvm::VersionTuple getCanImportVersion(TupleExpr *te, return result; } -static Expr *getSingleSubExp(Expr *exp, StringRef kindName, +static Expr *getSingleSubExp(ArgumentList *args, StringRef kindName, DiagnosticEngine *D) { - if (auto *pe = dyn_cast(exp)) { - return pe->getSubExpr(); - } + if (auto *unary = args->getUnlabeledUnaryExpr()) + return unary; + if (kindName == "canImport") { - if (auto *te = dyn_cast(exp)) { - bool underlyingVersion; - if (D) { - // Diagnose canImport syntax - (void)getCanImportVersion(te, D, underlyingVersion); - } - return te->getElement(0); + bool underlyingVersion; + if (D) { + // Diagnose canImport syntax + (void)getCanImportVersion(args, D, underlyingVersion); } + return args->getExpr(0); } return nullptr; } @@ -260,7 +258,7 @@ class ValidateIfConfigCondition : return nullptr; } - Expr *Arg = getSingleSubExp(E->getArg(), *KindName, &D); + Expr *Arg = getSingleSubExp(E->getArgs(), *KindName, &D); if (!Arg) { D.diagnose(E->getLoc(), diag::platform_condition_expected_one_argument); return nullptr; @@ -300,9 +298,9 @@ class ValidateIfConfigCondition : "a unary comparison '>=' or '<'; for example, '>=2.2' or '<2.2'"); return nullptr; } - auto versionString = extractExprSource(Ctx.SourceMgr, PUE->getArg()); + auto versionString = extractExprSource(Ctx.SourceMgr, PUE->getOperand()); auto Val = version::Version::parseVersionString( - versionString, PUE->getArg()->getStartLoc(), &D); + versionString, PUE->getOperand()->getStartLoc(), &D); if (!Val.hasValue()) return nullptr; return E; @@ -391,7 +389,7 @@ class ValidateIfConfigCondition : diag::unsupported_conditional_compilation_unary_expression); return nullptr; } - E->setArg(validate(E->getArg())); + E->setOperand(validate(E->getOperand())); return E; } @@ -474,7 +472,7 @@ class EvaluateIfConfigCondition : bool visitCallExpr(CallExpr *E) { auto KindName = getDeclRefStr(E->getFn()); - auto *Arg = getSingleSubExp(E->getArg(), KindName, nullptr); + auto *Arg = getSingleSubExp(E->getArgs(), KindName, nullptr); if (KindName == "_compiler_version") { auto Str = cast(Arg)->getValue(); auto Val = version::Version::parseCompilerVersionString( @@ -484,7 +482,7 @@ class EvaluateIfConfigCondition : } else if ((KindName == "swift") || (KindName == "compiler")) { auto PUE = cast(Arg); auto PrefixName = getDeclRefStr(PUE->getFn()); - auto Str = extractExprSource(Ctx.SourceMgr, PUE->getArg()); + auto Str = extractExprSource(Ctx.SourceMgr, PUE->getOperand()); auto Val = version::Version::parseVersionString( Str, SourceLoc(), nullptr).getValue(); if (KindName == "swift") { @@ -501,8 +499,8 @@ class EvaluateIfConfigCondition : auto Str = extractExprSource(Ctx.SourceMgr, Arg); bool underlyingModule = false; llvm::VersionTuple version; - if (auto *te = dyn_cast(E->getArg())) { - version = getCanImportVersion(te, nullptr, underlyingModule); + if (!E->getArgs()->isUnlabeledUnary()) { + version = getCanImportVersion(E->getArgs(), nullptr, underlyingModule); } return Ctx.canImportModule({ Ctx.getIdentifier(Str) , E->getLoc() }, version, underlyingModule); @@ -514,7 +512,7 @@ class EvaluateIfConfigCondition : } bool visitPrefixUnaryExpr(PrefixUnaryExpr *E) { - return !visit(E->getArg()); + return !visit(E->getOperand()); } bool visitParenExpr(ParenExpr *E) { @@ -563,7 +561,9 @@ class IsVersionIfConfigCondition : KindName == "compiler"; } - bool visitPrefixUnaryExpr(PrefixUnaryExpr *E) { return visit(E->getArg()); } + bool visitPrefixUnaryExpr(PrefixUnaryExpr *E) { + return visit(E->getOperand()); + } bool visitParenExpr(ParenExpr *E) { return visit(E->getSubExpr()); } bool visitExpr(Expr *E) { return false; } }; @@ -594,13 +594,11 @@ static bool isPlatformConditionDisjunction(Expr *E, PlatformConditionKind Kind, } else if (auto *C = dyn_cast(E)) { if (getPlatformConditionKind(getDeclRefStr(C->getFn())) != Kind) return false; - if (auto *ArgP = dyn_cast(C->getArg())) { - if (auto *Arg = ArgP->getSubExpr()) { - auto ArgStr = getDeclRefStr(Arg); - for (auto V : Vals) { - if (ArgStr == V) - return true; - } + if (auto *Arg = C->getArgs()->getUnlabeledUnaryExpr()) { + auto ArgStr = getDeclRefStr(Arg); + for (auto V : Vals) { + if (ArgStr == V) + return true; } } } @@ -625,7 +623,7 @@ static Expr *findAnyLikelySimulatorEnvironmentTest(Expr *Condition) { return nullptr; if (auto *N = dyn_cast(Condition)) { - return findAnyLikelySimulatorEnvironmentTest(N->getArg()); + return findAnyLikelySimulatorEnvironmentTest(N->getOperand()); } else if (auto *P = dyn_cast(Condition)) { return findAnyLikelySimulatorEnvironmentTest(P->getSubExpr()); } diff --git a/lib/Parse/ParsePattern.cpp b/lib/Parse/ParsePattern.cpp index 7b6ab7d613187..0db84a14662d6 100644 --- a/lib/Parse/ParsePattern.cpp +++ b/lib/Parse/ParsePattern.cpp @@ -1052,24 +1052,16 @@ ParserResult Parser::parseTypedPattern() { contextChange.emplace(*this, CurDeclContext, &dummyContext); } - SourceLoc lParenLoc, rParenLoc; - SmallVector args; - SmallVector argLabels; - SmallVector argLabelLocs; - SmallVector trailingClosures; - ParserStatus status = parseExprList(tok::l_paren, tok::r_paren, - /*isPostfix=*/true, - /*isExprBasic=*/false, - lParenLoc, args, argLabels, - argLabelLocs, rParenLoc, - trailingClosures, - SyntaxKind::Unknown); - if (status.isSuccess() && !status.hasCodeCompletion()) { + SmallVector elts; + auto argListResult = parseArgumentList(tok::l_paren, tok::r_paren, + /*isExprBasic*/ false); + if (!argListResult.isParseErrorOrHasCompletion()) { backtrack.cancelBacktrack(); // Suggest replacing ':' with '=' - diagnose(lParenLoc, diag::initializer_as_typed_pattern) - .highlight({Ty.get()->getStartLoc(), rParenLoc}) + auto *args = argListResult.get(); + diagnose(args->getLParenLoc(), diag::initializer_as_typed_pattern) + .highlight({Ty.get()->getStartLoc(), args->getRParenLoc()}) .fixItReplace(colonLoc, " = "); result.setIsParseError(); } diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index 751d21fa6b82a..3be69c0016f50 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -840,21 +840,14 @@ ParserResult Parser::parseStmtYield(SourceLoc tryLoc) { SyntaxParsingContext YieldsCtxt(SyntaxContext, SyntaxKind::YieldList); - SmallVector yieldLabels; - SmallVector yieldLabelLocs; - SmallVector trailingClosures; - - status = parseExprList(tok::l_paren, tok::r_paren, - /*postfix (allow trailing closure)*/ false, - /*expr basic (irrelevant)*/ true, - lpLoc, - yields, yieldLabels, yieldLabelLocs, - rpLoc, - trailingClosures, - SyntaxKind::ExprList); - assert(trailingClosures.empty()); - assert(yieldLabels.empty()); - assert(yieldLabelLocs.empty()); + SmallVector yieldElts; + status = parseExprList(tok::l_paren, tok::r_paren, /*isArgumentList*/ false, + lpLoc, yieldElts, rpLoc, SyntaxKind::ExprList); + for (auto &elt : yieldElts) { + assert(elt.Label.empty()); + assert(elt.LabelLoc.isInvalid()); + yields.push_back(elt.E); + } } else { SourceLoc beginLoc = Tok.getLoc(); From 89276c077fc121e1ff15a34619ede3f332fcb1b2 Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Wed, 1 Sep 2021 18:40:24 +0100 Subject: [PATCH 04/14] [CS] Tighten up check for unresolved member chain With the removal of TupleExpr and ParenExpr argument lists, it's no longer sufficient to check whether a given parent expr has a possible chain sub-expr, as it might be a child that's unrelated to the chain under consideration. For example, for a chain that's an argument to a function call, we don't want to walk up and consider the call expr to be an extension of the chain just because it has a function expr. Tighten up the check by comparing whether the given sub-expr of a possible chain parent matches the current expr in the chain. --- lib/Sema/PreCheckExpr.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/lib/Sema/PreCheckExpr.cpp b/lib/Sema/PreCheckExpr.cpp index 42aa53e1a4406..d3b89f5744274 100644 --- a/lib/Sema/PreCheckExpr.cpp +++ b/lib/Sema/PreCheckExpr.cpp @@ -340,16 +340,12 @@ UnresolvedMemberExpr *TypeChecker::getUnresolvedMemberChainBase(Expr *expr) { return dyn_cast(expr); } -/// Whether this expression is a member of a member chain. -static bool isMemberChainMember(Expr *expr) { - return getMemberChainSubExpr(expr) != nullptr; -} /// Whether this expression sits at the end of a chain of member accesses. static bool isMemberChainTail(Expr *expr, Expr *parent) { assert(expr && "isMemberChainTail called with null expr!"); // If this expression's parent is not itself part of a chain (or, this expr // has no parent expr), this must be the tail of the chain. - return parent == nullptr || !isMemberChainMember(parent); + return !parent || getMemberChainSubExpr(parent) != expr; } static bool isValidForwardReference(ValueDecl *D, DeclContext *DC, From 8c2b88abc0efac26c5d94b8c2c332ece23de0be1 Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Wed, 1 Sep 2021 18:40:25 +0100 Subject: [PATCH 05/14] [CS] Adopt ArgumentList - Explicitly limit favoring logic to only handle unary args, this seems to have always been the case, but needs to be handled explicitly now that argument lists aren't exprs - Update the ConstraintLocator simplification to handle argument lists - Store a mapping of locators to argument lists in the constraint system - Abstract more logic into a getArgumentLocator method which retrieves an argument-to-param locator from an argument anchor expr --- include/swift/Sema/ConstraintSystem.h | 52 +- lib/Sema/CSApply.cpp | 655 +++++++++----------------- lib/Sema/CSDiagnostics.cpp | 530 +++++++++------------ lib/Sema/CSDiagnostics.h | 12 +- lib/Sema/CSGen.cpp | 294 +++++------- lib/Sema/CSSimplify.cpp | 137 +++--- lib/Sema/CSSolver.cpp | 4 +- lib/Sema/ConstraintSystem.cpp | 315 +++++-------- lib/Sema/PreCheckExpr.cpp | 198 ++++---- lib/Sema/TypeCheckConstraints.cpp | 2 +- lib/Sema/TypeCheckExpr.cpp | 102 ++-- test/expr/expressions.swift | 2 +- 12 files changed, 888 insertions(+), 1415 deletions(-) diff --git a/include/swift/Sema/ConstraintSystem.h b/include/swift/Sema/ConstraintSystem.h index 72cfb3981b23a..5efa1a859880e 100644 --- a/include/swift/Sema/ConstraintSystem.h +++ b/include/swift/Sema/ConstraintSystem.h @@ -583,7 +583,7 @@ struct SelectedOverload { /// Provides information about the application of a function argument to a /// parameter. class FunctionArgApplyInfo { - Expr *ArgListExpr; + ArgumentList *ArgList; Expr *ArgExpr; unsigned ArgIdx; Type ArgType; @@ -595,15 +595,15 @@ class FunctionArgApplyInfo { const ValueDecl *Callee; public: - FunctionArgApplyInfo(Expr *argListExpr, Expr *argExpr, unsigned argIdx, + FunctionArgApplyInfo(ArgumentList *argList, Expr *argExpr, unsigned argIdx, Type argType, unsigned paramIdx, Type fnInterfaceType, FunctionType *fnType, const ValueDecl *callee) - : ArgListExpr(argListExpr), ArgExpr(argExpr), ArgIdx(argIdx), - ArgType(argType), ParamIdx(paramIdx), FnInterfaceType(fnInterfaceType), - FnType(fnType), Callee(callee) {} + : ArgList(argList), ArgExpr(argExpr), ArgIdx(argIdx), ArgType(argType), + ParamIdx(paramIdx), FnInterfaceType(fnInterfaceType), FnType(fnType), + Callee(callee) {} /// \returns The list of the arguments used for this application. - Expr *getArgListExpr() const { return ArgListExpr; } + ArgumentList *getArgList() const { return ArgList; } /// \returns The argument being applied. Expr *getArgExpr() const { return ArgExpr; } @@ -625,11 +625,7 @@ class FunctionArgApplyInfo { /// \returns The label for the argument being applied. Identifier getArgLabel() const { - if (auto *te = dyn_cast(ArgListExpr)) - return te->getElementName(ArgIdx); - - assert(isa(ArgListExpr)); - return Identifier(); + return ArgList->getLabel(ArgIdx); } Identifier getParamLabel() const { @@ -649,10 +645,8 @@ class FunctionArgApplyInfo { if (argLabel.empty()) return false; - if (auto *te = dyn_cast(ArgListExpr)) - return llvm::count(te->getElementNames(), argLabel) == 1; - - return false; + SmallVector scratch; + return llvm::count(ArgList->getArgumentLabels(scratch), argLabel) == 1; }; if (useArgLabel()) { @@ -668,11 +662,7 @@ class FunctionArgApplyInfo { /// Whether the argument is a trailing closure. bool isTrailingClosure() const { - if (auto trailingClosureArg = - ArgListExpr->getUnlabeledTrailingClosureIndexOfPackedArgument()) - return ArgIdx >= *trailingClosureArg; - - return false; + return ArgList->isRawTrailingClosureIndex(ArgIdx); } /// \returns The interface type for the function being applied. Note that this @@ -2794,25 +2784,19 @@ class ConstraintSystem { /// we're exploring. SolverState *solverState = nullptr; - struct ArgumentInfo { - ArrayRef Labels; - Optional UnlabeledTrailingClosureIndex; - }; - /// A mapping from the constraint locators for references to various /// names (e.g., member references, normal name references, possible - /// constructions) to the argument labels provided in the call to - /// that locator. - llvm::DenseMap ArgumentInfos; + /// constructions) to the argument lists for the call to that locator. + llvm::DenseMap ArgumentLists; /// Form a locator that can be used to retrieve argument information cached in /// the constraint system for the callee described by the anchor of the /// passed locator. ConstraintLocator *getArgumentInfoLocator(ConstraintLocator *locator); - /// Retrieve the argument info that is associated with a member + /// Retrieve the argument list that is associated with a member /// reference at the given locator. - Optional getArgumentInfo(ConstraintLocator *locator); + ArgumentList *getArgumentList(ConstraintLocator *locator); Optional findSelectedOverloadFor(ConstraintLocator *locator) const { @@ -5197,10 +5181,10 @@ class ConstraintSystem { /// Check whether given AST node represents an argument of an application /// of some sort (call, operator invocation, subscript etc.) - /// and return AST node representing and argument index. E.g. for regular - /// calls `test(42)` passing `42` should return node representing - /// entire call and index `0`. - Optional> isArgumentExpr(Expr *expr); + /// and returns a locator for the argument application. E.g. for regular + /// calls `test(42)` passing `42` should return a locator with the entire call + /// as the anchor, and a path to the argument at index `0`. + ConstraintLocator *getArgumentLocator(Expr *expr); SWIFT_DEBUG_DUMP; SWIFT_DEBUG_DUMPER(dump(Expr *)); diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index ba8d844b062e7..990fdadeb2dcc 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -775,10 +775,8 @@ namespace { // Remaining cases should only come up when we're re-typechecking. // FIXME: really it would be much better if Sema had stricter phase // separation. - } else if (auto dotSyntax = dyn_cast(expr)) { - return dotSyntax->getArg(); - } else if (auto ctorRef = dyn_cast(expr)) { - return ctorRef->getArg(); + } else if (auto selfApply = dyn_cast(expr)) { + return selfApply->getBase(); } else if (auto apply = dyn_cast(expr)) { return apply->getFn(); } else if (auto lookupRef = dyn_cast(expr)) { @@ -1002,8 +1000,7 @@ namespace { auto &context = cs.getASTContext(); auto paramInfo = fnType->getParams(); - SmallVector args; - SmallVector argLabels; + SmallVector args; auto *innerParams = fnDecl.getParameters(); SmallVector innerParamTypes; @@ -1068,10 +1065,11 @@ namespace { paramInfo[i].getParameterFlags())); outerParam->setInterfaceType(outerParamType->mapTypeOutOfContext()); + Identifier label; if (fnDecl.getAbstractFunctionDecl()) - argLabels.push_back(innerParam->getArgumentName()); + label = innerParam->getArgumentName(); - args.push_back(paramRef); + args.emplace_back(SourceLoc(), label, paramRef); } // FIXME: Verify ExtInfo state is correct, not working by accident. @@ -1080,10 +1078,10 @@ namespace { FunctionType::get(innerParamTypes, fnType->getResult(), fnInfo)); cs.cacheType(fnRef); - auto *fnCall = CallExpr::createImplicit(context, fnRef, args, argLabels); + auto *argList = ArgumentList::createImplicit(context, args); + auto *fnCall = CallExpr::createImplicit(context, fnRef, argList); fnCall->setType(fnType->getResult()); cs.cacheType(fnCall); - cs.cacheType(fnCall->getArg()); auto discriminator = AutoClosureExpr::InvalidDiscriminator; @@ -1151,8 +1149,7 @@ namespace { case ValueOwnership::Owned: case ValueOwnership::Shared: - auto selfArgTy = ParenType::get(context, - selfParam.getPlainType(), + auto selfArgTy = ParenType::get(context, selfParam.getPlainType(), selfParam.getParameterFlags()); selfOpenedRef->setType(selfArgTy); cs.cacheType(selfOpenedRef); @@ -1197,10 +1194,7 @@ namespace { } // Pass all the closure parameters to the call. - SmallVector labels; - SmallVector labelLocs; - SmallVector args; - + SmallVector args; for (auto idx : indices(*params)) { auto *param = params->get(idx); auto calleeParamType = calleeParams[idx].getParameterType(); @@ -1234,35 +1228,12 @@ namespace { cs.cacheType(paramRef); } - args.push_back(paramRef); - - labels.push_back(calleeParams[idx].getLabel()); - labelLocs.push_back(SourceLoc()); - } - - Expr *closureArg; - if (args.size() == 1 && - labels[0].empty() && - !calleeParams[0].getParameterFlags().isVariadic()) { - closureArg = new (context) ParenExpr(SourceLoc(), args[0], SourceLoc(), - /*hasTrailingClosure=*/false); - closureArg->setImplicit(); - } else { - closureArg = TupleExpr::create(context, SourceLoc(), args, labels, labelLocs, - SourceLoc(), /*hasTrailingClosure=*/false, - /*implicit=*/true); + args.emplace_back(SourceLoc(), calleeParams[idx].getLabel(), paramRef); } - auto argTy = AnyFunctionType::composeTuple(context, calleeParams, - /*canonical*/false); - closureArg->setType(argTy); - cs.cacheType(closureArg); - // (Self) -> (Args...) -> ... - auto *closureCall = - CallExpr::create(context, selfCall, closureArg, { }, { }, - /*hasTrailingClosure=*/false, - /*implicit=*/true); + auto *argList = ArgumentList::createImplicit(context, args); + auto *closureCall = CallExpr::createImplicit(context, selfCall, argList); closureCall->setType(calleeResultTy); cs.cacheType(closureCall); @@ -1832,8 +1803,9 @@ namespace { ConstraintLocatorBuilder locator, ConstraintLocatorBuilder calleeLocator); - /// Build the function and argument for a `@dynamicCallable` application. - std::pair + /// Build the function and argument list for a `@dynamicCallable` + /// application. + std::pair buildDynamicCallable(ApplyExpr *apply, SelectedOverload selected, FuncDecl *method, AnyFunctionType *methodType, ConstraintLocatorBuilder applyFunctionLoc); @@ -1860,26 +1832,23 @@ namespace { Expr *coerceToType(Expr *expr, Type toType, ConstraintLocatorBuilder locator, Optional typeFromPattern = None); - - /// Coerce the given expression (which is the argument to a call) to - /// the given parameter type. + + /// Coerce the arguments in the provided argument list to their matching + /// parameter types. /// /// This operation cannot fail. /// - /// \param arg The argument expression. + /// \param args The argument list. /// \param funcType The function type. /// \param callee The callee for the function being applied. /// \param apply The ApplyExpr that forms the call. - /// \param argLabels The argument labels provided for the call. /// \param locator Locator used to describe where in this expression we are. /// - /// \returns the coerced expression, which will have type \c ToType. - Expr * - coerceCallArguments(Expr *arg, AnyFunctionType *funcType, - ConcreteDeclRef callee, ApplyExpr *apply, - ArrayRef argLabels, - ConstraintLocatorBuilder locator, - ArrayRef appliedPropertyWrappers); + /// \returns The resulting ArgumentList. + ArgumentList *coerceCallArguments( + ArgumentList *args, AnyFunctionType *funcType, ConcreteDeclRef callee, + ApplyExpr *apply, ConstraintLocatorBuilder locator, + ArrayRef appliedPropertyWrappers); /// Coerce the given 'self' argument (e.g., for the base of a /// member expression) to the given type. @@ -1899,18 +1868,15 @@ namespace { /// Build a new subscript. /// /// \param base The base of the subscript. - /// \param index The index of the subscript. + /// \param args The argument list of the subscript. /// \param locator The locator used to refer to the subscript. /// \param isImplicit Whether this is an implicit subscript. - Expr *buildSubscript(Expr *base, Expr *index, - ArrayRef argLabels, - bool hasTrailingClosure, + Expr *buildSubscript(Expr *base, ArgumentList *args, ConstraintLocatorBuilder locator, bool isImplicit, AccessSemantics semantics, const SelectedOverload &selected) { // Build the new subscript. - auto newSubscript = buildSubscriptHelper(base, index, argLabels, - selected, hasTrailingClosure, + auto newSubscript = buildSubscriptHelper(base, args, selected, locator, isImplicit, semantics); if (selected.choice.getKind() == OverloadChoiceKind::DeclViaDynamic) { @@ -1947,10 +1913,8 @@ namespace { return newSubscript; } - Expr *buildSubscriptHelper(Expr *base, Expr *index, - ArrayRef argLabels, + Expr *buildSubscriptHelper(Expr *base, ArgumentList *args, const SelectedOverload &selected, - bool hasTrailingClosure, ConstraintLocatorBuilder locator, bool isImplicit, AccessSemantics semantics) { auto choice = selected.choice; @@ -1961,10 +1925,11 @@ namespace { auto applicationTy = simplifyType(selected.openedType)->castTo(); - index = cs.coerceToRValue(index); // The index argument should be (keyPath: KeyPath). // Dig the key path expression out of the arguments. - auto indexKP = cast(index)->getElement(0); + auto *indexKP = args->getUnaryExpr(); + assert(indexKP); + indexKP = cs.coerceToRValue(indexKP); auto keyPathExprTy = cs.getType(indexKP); auto keyPathTy = applicationTy->getParams().front().getOldType(); @@ -1988,7 +1953,7 @@ namespace { .diagnose(base->getLoc(), diag::expr_smart_keypath_application_type_mismatch, keyPathExprTy, baseTy) - .highlight(index->getSourceRange()); + .highlight(args->getSourceRange()); } } else { llvm_unreachable("unknown key path class!"); @@ -2031,11 +1996,10 @@ namespace { } if (resultIsLValue) valueTy = LValueType::get(valueTy); - - auto keyPathAp = new (cs.getASTContext()) - KeyPathApplicationExpr(base, index->getStartLoc(), indexKP, - index->getEndLoc(), valueTy, - base->isImplicit() && index->isImplicit()); + + auto keyPathAp = new (cs.getASTContext()) KeyPathApplicationExpr( + base, args->getStartLoc(), indexKP, args->getEndLoc(), valueTy, + base->isImplicit() && args->isImplicit()); cs.setType(keyPathAp, valueTy); return keyPathAp; } @@ -2083,16 +2047,13 @@ namespace { auto fullSubscriptTy = openedFullFnType->getResult() ->castTo(); auto &appliedWrappers = solution.appliedPropertyWrappers[memberLoc.getAnchor()]; - index = coerceCallArguments(index, fullSubscriptTy, subscriptRef, nullptr, - argLabels, - locator.withPathElement( - ConstraintLocator::ApplyArgument), - appliedWrappers); - if (!index) + args = coerceCallArguments( + args, fullSubscriptTy, subscriptRef, nullptr, + locator.withPathElement(ConstraintLocator::ApplyArgument), + appliedWrappers); + if (!args) return nullptr; - auto getType = [&](Expr *E) -> Type { return cs.getType(E); }; - // Handle dynamic lookup. if (choice.getKind() == OverloadChoiceKind::DeclViaDynamic || subscript->getAttrs().hasAttribute()) { @@ -2102,7 +2063,7 @@ namespace { // TODO: diagnose if semantics != AccessSemantics::Ordinary? auto subscriptExpr = DynamicSubscriptExpr::create( - ctx, base, index, subscriptRef, isImplicit, getType); + ctx, base, args, subscriptRef, isImplicit); auto resultTy = simplifyType(selected.openedType) ->castTo() ->getResult(); @@ -2142,7 +2103,7 @@ namespace { // Form the subscript expression. auto subscriptExpr = SubscriptExpr::create( - ctx, base, index, subscriptRef, isImplicit, semantics, getType); + ctx, base, args, subscriptRef, isImplicit, semantics); cs.setType(subscriptExpr, fullSubscriptTy->getResult()); subscriptExpr->setIsSuper(isSuper); cs.setType(subscriptExpr, @@ -2221,9 +2182,9 @@ namespace { /// \param keyPathTy The type of the keypath argument. /// \param dotLoc The location of the '.' preceding member name. /// \param memberLoc The locator to be associated with new argument. - Expr *buildKeyPathDynamicMemberIndexExpr(BoundGenericType *keyPathTy, - SourceLoc dotLoc, - ConstraintLocator *memberLoc) { + Expr *buildKeyPathDynamicMemberArgExpr(BoundGenericType *keyPathTy, + SourceLoc dotLoc, + ConstraintLocator *memberLoc) { auto &ctx = cs.getASTContext(); auto *anchor = getAsExpr(memberLoc->getAnchor()); @@ -2251,9 +2212,8 @@ namespace { switch (overload.choice.getKind()) { case OverloadChoiceKind::DynamicMemberLookup: case OverloadChoiceKind::KeyPathDynamicMemberLookup: { - buildKeyPathSubscriptComponent(overload, dotLoc, /*indexExpr=*/nullptr, - ctx.Id_dynamicMember, componentLoc, - components); + buildKeyPathSubscriptComponent(overload, dotLoc, /*args=*/nullptr, + componentLoc, components); keyPath->resolveComponents(ctx, components); cs.cacheExprTypes(keyPath); return keyPath; @@ -2289,9 +2249,8 @@ namespace { } else if (origComponent.getKind() == ComponentKind::UnresolvedSubscript) { anchor = SubscriptExpr::create( - ctx, dotExpr, origComponent.getIndexExpr(), ConcreteDeclRef(), - /*implicit=*/true, AccessSemantics::Ordinary, - [&](Expr *expr) { return simplifyType(cs.getType(expr)); }); + ctx, dotExpr, origComponent.getSubscriptArgs(), ConcreteDeclRef(), + /*implicit=*/true, AccessSemantics::Ordinary); } else { return nullptr; } @@ -2318,31 +2277,14 @@ namespace { // diagnostics might have a reference to it, so it couldn't // be modified. if (!forKeyPathComponent) { - SmallVector arguments; - if (auto *TE = dyn_cast(SE->getIndex())) { - auto args = TE->getElements(); - arguments.append(args.begin(), args.end()); - } else { - arguments.push_back(SE->getIndex()->getSemanticsProvidingExpr()); - } - - SmallVector trailingClosures; - if (SE->hasTrailingClosure()) { - auto *closure = arguments.back(); - trailingClosures.push_back({closure}); - } - componentExpr = SubscriptExpr::create( - ctx, dotExpr, SE->getStartLoc(), arguments, - SE->getArgumentLabels(), SE->getArgumentLabelLocs(), - SE->getEndLoc(), trailingClosures, + ctx, dotExpr, SE->getArgs(), SE->hasDecl() ? SE->getDecl() : ConcreteDeclRef(), /*implicit=*/true, SE->getAccessSemantics()); } - buildKeyPathSubscriptComponent(overload, SE->getLoc(), SE->getIndex(), - SE->getArgumentLabels(), componentLoc, - components); + buildKeyPathSubscriptComponent(overload, SE->getLoc(), SE->getArgs(), + componentLoc, components); } else { return nullptr; } @@ -2924,14 +2866,13 @@ namespace { auto fnType = simplifyType(selectedOverload->openedType)->castTo(); - auto newArg = coerceCallArguments( - expr->getArg(), fnType, witness, - /*applyExpr=*/nullptr, expr->getArgumentLabels(), + auto newArgs = coerceCallArguments( + expr->getArgs(), fnType, witness, /*applyExpr=*/nullptr, cs.getConstraintLocator(expr, ConstraintLocator::ApplyArgument), /*appliedPropertyWrappers=*/{}); expr->setInitializer(witness); - expr->setArg(newArg); + expr->setArgs(newArgs); return expr; } @@ -3318,10 +3259,10 @@ namespace { llvm_unreachable("Unhandled OverloadChoiceKind in switch."); } - /// Form a type checked expression for the index of a @dynamicMemberLookup - /// subscript index parameter. - Expr *buildDynamicMemberLookupIndexExpr(StringRef name, SourceLoc loc, - Type literalTy) { + /// Form a type checked expression for the argument of a + /// @dynamicMemberLookup subscript index parameter. + Expr *buildDynamicMemberLookupArgExpr(StringRef name, SourceLoc loc, + Type literalTy) { // Build and type check the string literal index value to the specific // string type expected by the subscript. auto &ctx = cs.getASTContext(); @@ -3350,30 +3291,22 @@ namespace { // Build and type check the string literal index value to the specific // string type expected by the subscript. auto fieldName = overload.choice.getName().getBaseIdentifier().str(); - argExpr = buildDynamicMemberLookupIndexExpr(fieldName, nameLoc, - paramTy); + argExpr = buildDynamicMemberLookupArgExpr(fieldName, nameLoc, paramTy); } else { - argExpr = buildKeyPathDynamicMemberIndexExpr( + argExpr = buildKeyPathDynamicMemberArgExpr( paramTy->castTo(), dotLoc, memberLocator); } if (!argExpr) return nullptr; - // Build a tuple so that the argument has a label. - auto tupleTy = - TupleType::get(TupleTypeElt(paramTy, ctx.Id_dynamicMember), ctx); - - Expr *index = - TupleExpr::createImplicit(ctx, argExpr, ctx.Id_dynamicMember); - index->setType(tupleTy); - cs.cacheType(index); - + // Build an argument list. + auto *argList = + ArgumentList::forImplicitSingle(ctx, ctx.Id_dynamicMember, argExpr); // Build and return a subscript that uses this string as the index. - return buildSubscript( - base, index, ctx.Id_dynamicMember, - /*trailingClosure*/ false, cs.getConstraintLocator(expr), - /*isImplicit*/ true, AccessSemantics::Ordinary, overload); + return buildSubscript(base, argList, cs.getConstraintLocator(expr), + /*isImplicit*/ true, AccessSemantics::Ordinary, + overload); } Type getTypeOfDynamicMemberIndex(const SelectedOverload &overload) { @@ -3504,14 +3437,13 @@ namespace { if (overload->choice.getKind() == OverloadChoiceKind::KeyPathDynamicMemberLookup) { return buildDynamicMemberLookupRef( - expr, expr->getBase(), expr->getIndex()->getStartLoc(), SourceLoc(), + expr, expr->getBase(), expr->getArgs()->getStartLoc(), SourceLoc(), *overload, memberLocator); } - return buildSubscript( - expr->getBase(), expr->getIndex(), expr->getArgumentLabels(), - expr->hasTrailingClosure(), cs.getConstraintLocator(expr), - expr->isImplicit(), expr->getAccessSemantics(), *overload); + return buildSubscript(expr->getBase(), expr->getArgs(), + cs.getConstraintLocator(expr), expr->isImplicit(), + expr->getAccessSemantics(), *overload); } /// "Finish" an array expression by filling in the semantic expression. @@ -3608,11 +3540,9 @@ namespace { Expr *visitDynamicSubscriptExpr(DynamicSubscriptExpr *expr) { auto *memberLocator = cs.getConstraintLocator(expr, ConstraintLocator::SubscriptMember); - return buildSubscript(expr->getBase(), expr->getIndex(), - expr->getArgumentLabels(), - expr->hasTrailingClosure(), - cs.getConstraintLocator(expr), - expr->isImplicit(), AccessSemantics::Ordinary, + return buildSubscript(expr->getBase(), expr->getArgs(), + cs.getConstraintLocator(expr), expr->isImplicit(), + AccessSemantics::Ordinary, solution.getOverloadChoice(memberLocator)); } @@ -4506,8 +4436,8 @@ namespace { Expr *argExpr = new (ctx) StringLiteralExpr(msg, E->getLoc(), /*implicit*/true); - Expr *callExpr = CallExpr::createImplicit(ctx, fnRef, { argExpr }, - { Identifier() }); + auto *argList = ArgumentList::forImplicitUnlabeled(ctx, {argExpr}); + Expr *callExpr = CallExpr::createImplicit(ctx, fnRef, argList); auto resultTy = TypeChecker::typeCheckExpression( callExpr, cs.DC, /*contextualInfo=*/{valueType, CTP_CannotFail}); @@ -4890,14 +4820,10 @@ namespace { break; } case KeyPathExpr::Component::Kind::UnresolvedSubscript: { - ArrayRef subscriptLabels; - if (!isDynamicMember) - subscriptLabels = origComponent.getSubscriptLabels(); - - buildKeyPathSubscriptComponent( - solution.getOverloadChoice(calleeLoc), origComponent.getLoc(), - origComponent.getIndexExpr(), subscriptLabels, componentLocator, - resolvedComponents); + buildKeyPathSubscriptComponent(solution.getOverloadChoice(calleeLoc), + origComponent.getLoc(), + origComponent.getSubscriptArgs(), + componentLocator, resolvedComponents); break; } case KeyPathExpr::Component::Kind::OptionalChain: { @@ -5079,7 +5005,8 @@ namespace { cs.cacheType(outerClosure); // let outerApply = "\( outerClosure )( \(E) )" - auto outerApply = CallExpr::createImplicit(ctx, outerClosure, {E}, {}); + auto *argList = ArgumentList::forImplicitUnlabeled(ctx, {E}); + auto outerApply = CallExpr::createImplicit(ctx, outerClosure, argList); outerApply->setType(closureTy); cs.cacheExprTypes(outerApply); @@ -5141,10 +5068,10 @@ namespace { } void buildKeyPathSubscriptComponent( - const SelectedOverload &overload, - SourceLoc componentLoc, Expr *indexExpr, - ArrayRef labels, ConstraintLocator *locator, + const SelectedOverload &overload, SourceLoc componentLoc, + ArgumentList *args, ConstraintLocator *locator, SmallVectorImpl &components) { + auto &ctx = cs.getASTContext(); auto subscript = cast(overload.choice.getDecl()); assert(!subscript->isGetterMutating()); auto memberLoc = cs.getCalleeLocator(locator); @@ -5163,18 +5090,19 @@ namespace { OverloadChoiceKind::KeyPathDynamicMemberLookup; if (forDynamicLookup) { - labels = cs.getASTContext().Id_dynamicMember; - auto indexType = getTypeOfDynamicMemberIndex(overload); + Expr *argExpr = nullptr; if (overload.choice.getKind() == OverloadChoiceKind::KeyPathDynamicMemberLookup) { - indexExpr = buildKeyPathDynamicMemberIndexExpr( + argExpr = buildKeyPathDynamicMemberArgExpr( indexType->castTo(), componentLoc, memberLoc); } else { auto fieldName = overload.choice.getName().getBaseIdentifier().str(); - indexExpr = buildDynamicMemberLookupIndexExpr(fieldName, componentLoc, - indexType); + argExpr = buildDynamicMemberLookupArgExpr(fieldName, componentLoc, + indexType); } + args = ArgumentList::forImplicitSingle(ctx, ctx.Id_dynamicMember, + argExpr); // Record the implicit subscript expr's parameter bindings and matching // direction as `coerceCallArguments` requires them. solution.recordSingleArgMatchingChoice(locator); @@ -5185,9 +5113,8 @@ namespace { auto resolvedTy = subscriptType->getResult(); // Coerce the indices to the type the subscript expects. - auto *newIndexExpr = coerceCallArguments( - indexExpr, subscriptType, ref, - /*applyExpr*/ nullptr, labels, + args = coerceCallArguments( + args, subscriptType, ref, /*applyExpr*/ nullptr, cs.getConstraintLocator(locator, ConstraintLocator::ApplyArgument), /*appliedPropertyWrappers*/ {}); @@ -5196,8 +5123,7 @@ namespace { // index components are hashable and collect their conformances here. SmallVector conformances; - auto hashable = - cs.getASTContext().getProtocol(KnownProtocolKind::Hashable); + auto hashable = ctx.getProtocol(KnownProtocolKind::Hashable); auto fnType = overload.openedType->castTo(); SmallVector newLabels; @@ -5216,10 +5142,8 @@ namespace { conformances.push_back(hashableConformance); } - auto comp = KeyPathExpr::Component::forSubscriptWithPrebuiltIndexExpr( - ref, newIndexExpr, cs.getASTContext().AllocateCopy(newLabels), - resolvedTy, componentLoc, - cs.getASTContext().AllocateCopy(conformances)); + auto comp = KeyPathExpr::Component::forSubscript( + ctx, ref, args, resolvedTy, ctx.AllocateCopy(conformances)); components.push_back(comp); if (shouldForceUnwrapResult(overload.choice, locator)) @@ -5779,13 +5703,9 @@ static bool isMainDispatchQueue(Expr *arg) { return baseNominal->getName().str() == "DispatchQueue"; } - -Expr *ExprRewriter::coerceCallArguments( - Expr *arg, AnyFunctionType *funcType, - ConcreteDeclRef callee, - ApplyExpr *apply, - ArrayRef argLabels, - ConstraintLocatorBuilder locator, +ArgumentList *ExprRewriter::coerceCallArguments( + ArgumentList *args, AnyFunctionType *funcType, ConcreteDeclRef callee, + ApplyExpr *apply, ConstraintLocatorBuilder locator, ArrayRef appliedPropertyWrappers) { assert(locator.last() && locator.last()->is()); @@ -5806,9 +5726,6 @@ Expr *ExprRewriter::coerceCallArguments( // Determine the parameter bindings. ParameterListInfo paramInfo(params, callee.getDecl(), skipCurriedSelf); - SmallVector args; - AnyFunctionType::decomposeTuple(cs.getType(arg), args); - // If this application is an init(wrappedValue:) call that needs an injected // wrapped value placeholder, the first non-defaulted argument must be // wrapped in an OpaqueValueExpr. @@ -5828,16 +5745,12 @@ Expr *ExprRewriter::coerceCallArguments( }; // Quickly test if any further fix-ups for the argument types are necessary. - if (AnyFunctionType::equalParams(args, params) && - !shouldInjectWrappedValuePlaceholder && + auto matches = args->matches(params, [&](Expr *E) { return cs.getType(E); }); + if (matches && !shouldInjectWrappedValuePlaceholder && !paramInfo.anyContextualInfo()) - return arg; - - // Apply labels to arguments. - AnyFunctionType::relabelParams(args, argLabels); + return args; - auto oldTrailingClosureIndex = - arg->getUnlabeledTrailingClosureIndexOfPackedArgument(); + const auto oldTrailingClosureIndex = args->getRawFirstTrailingClosureIndex(); Optional newTrailingClosureIndex; // Determine the parameter bindings that were applied. @@ -5846,52 +5759,12 @@ Expr *ExprRewriter::coerceCallArguments( auto parameterBindings = solution.argumentMatchingChoices.find(locatorPtr) ->second.parameterBindings; - // We should either have parentheses or a tuple. - auto *argTuple = dyn_cast(arg); - auto *argParen = dyn_cast(arg); - // FIXME: Eventually, we want to enforce that we have either argTuple or - // argParen here. - - SourceLoc lParenLoc, rParenLoc; - if (argTuple) { - lParenLoc = argTuple->getLParenLoc(); - rParenLoc = argTuple->getRParenLoc(); - } else if (argParen) { - lParenLoc = argParen->getLParenLoc(); - rParenLoc = argParen->getRParenLoc(); - } - - // Local function to extract the ith argument expression, which papers - // over some of the weirdness with tuples vs. parentheses. - auto getArg = [&](unsigned i) -> Expr * { - if (argTuple) - return argTuple->getElement(i); - assert(i == 0 && "Scalar only has a single argument"); - - if (argParen) - return argParen->getSubExpr(); - - return arg; - }; - - auto getLabelLoc = [&](unsigned i) -> SourceLoc { - if (argTuple) - return argTuple->getElementNameLoc(i); - - assert(i == 0 && "Scalar only has a single argument"); - return SourceLoc(); - }; - - SmallVector newArgs; - SmallVector newLabels; - SmallVector newLabelLocs; - SmallVector newParams; - + SmallVector newArgs; for (unsigned paramIdx = 0, numParams = parameterBindings.size(); paramIdx != numParams; ++paramIdx) { // Extract the parameter. const auto ¶m = params[paramIdx]; - newLabels.push_back(param.getLabel()); + auto paramLabel = param.getLabel(); // Handle variadic parameters. if (param.isVariadic()) { @@ -5902,14 +5775,13 @@ Expr *ExprRewriter::coerceCallArguments( // The first argument of this vararg parameter may have had a label; // save its location. auto &varargIndices = parameterBindings[paramIdx]; + SourceLoc labelLoc; if (!varargIndices.empty()) - newLabelLocs.push_back(getLabelLoc(varargIndices[0])); - else - newLabelLocs.push_back(SourceLoc()); + labelLoc = args->getLabelLoc(varargIndices[0]); // Convert the arguments. for (auto argIdx : varargIndices) { - auto arg = getArg(argIdx); + auto *arg = args->getExpr(argIdx); auto argType = cs.getType(arg); // Update the trailing closure index if needed. @@ -5953,8 +5825,7 @@ Expr *ExprRewriter::coerceCallArguments( /*implicit=*/true, arrayExpr->getType()); cs.cacheType(varargExpansionExpr); - newArgs.push_back(varargExpansionExpr); - newParams.push_back(param); + newArgs.push_back(Argument(labelLoc, paramLabel, varargExpansionExpr)); continue; } @@ -5962,13 +5833,10 @@ Expr *ExprRewriter::coerceCallArguments( if (parameterBindings[paramIdx].empty()) { auto owner = getDefaultArgOwner(callee, paramIdx); auto paramTy = param.getParameterType(); - auto *defArg = new (ctx) - DefaultArgumentExpr(owner, paramIdx, arg->getStartLoc(), paramTy, dc); - + auto *defArg = new (ctx) DefaultArgumentExpr( + owner, paramIdx, args->getStartLoc(), paramTy, dc); cs.cacheType(defArg); - newArgs.push_back(defArg); - newParams.push_back(param); - newLabelLocs.push_back(SourceLoc()); + newArgs.emplace_back(SourceLoc(), param.getLabel(), defArg); continue; } @@ -5977,8 +5845,9 @@ Expr *ExprRewriter::coerceCallArguments( // Extract the argument used to initialize this parameter. assert(parameterBindings[paramIdx].size() == 1); unsigned argIdx = parameterBindings[paramIdx].front(); - auto arg = getArg(argIdx); - auto argType = cs.getType(arg); + auto arg = args->get(argIdx); + auto *argExpr = arg.getExpr(); + auto argType = cs.getType(argExpr); // Update the trailing closure index if needed. if (oldTrailingClosureIndex && *oldTrailingClosureIndex == argIdx) { @@ -5986,8 +5855,9 @@ Expr *ExprRewriter::coerceCallArguments( newTrailingClosureIndex = newArgs.size(); } - // Save the original label location. - newLabelLocs.push_back(getLabelLoc(argIdx)); + // Update the argument label to match the parameter. This may be necessary + // for things like trailing closures and args to property wrapper params. + arg.setLabel(param.getLabel()); // Determine whether the parameter is unsafe Sendable or MainActor, and // record it as such. @@ -5997,14 +5867,13 @@ Expr *ExprRewriter::coerceCallArguments( bool isImplicitSelfCapture = paramInfo.isImplicitSelfCapture(paramIdx); bool inheritsActorContext = paramInfo.inheritsActorContext(paramIdx); applyContextualClosureFlags( - arg, isUnsafeSendable && contextUsesConcurrencyFeatures(dc), + argExpr, isUnsafeSendable && contextUsesConcurrencyFeatures(dc), isMainActor, isImplicitSelfCapture, inheritsActorContext); // If the types exactly match, this is easy. auto paramType = param.getOldType(); if (argType->isEqual(paramType) && !shouldInjectWrappedValuePlaceholder) { newArgs.push_back(arg); - newParams.push_back(param); continue; } @@ -6017,7 +5886,7 @@ Expr *ExprRewriter::coerceCallArguments( // Since it was allowed to pass function types to @autoclosure // parameters in Swift versions < 5, it has to be handled as // a regular function coversion by `coerceToType`. - if (isAutoClosureArgument(arg)) { + if (isAutoClosureArgument(argExpr)) { // In Swift >= 5 mode we only allow `@autoclosure` arguments // to be used by value if parameter would return a function // type (it just needs to get wrapped into autoclosure expr), @@ -6055,20 +5924,21 @@ Expr *ExprRewriter::coerceCallArguments( if (generatorArg->isAutoClosure()) { auto *closureType = generatorInputType->castTo(); - arg = coerceToType( - arg, closureType->getResult(), + argExpr = coerceToType( + argExpr, closureType->getResult(), argLoc.withPathElement(ConstraintLocator::AutoclosureResult)); - arg = cs.buildAutoClosureExpr(arg, closureType, dc); + argExpr = cs.buildAutoClosureExpr(argExpr, closureType, dc); } - arg = coerceToType(arg, generatorInputType, argLoc); + argExpr = coerceToType(argExpr, generatorInputType, argLoc); // Wrap the argument in an applied property wrapper expr, which will // later turn into a call to the property wrapper generator function. - arg = AppliedPropertyWrapperExpr::create(ctx, callee, paramDecl, - arg->getStartLoc(), - wrapperType, arg, valueKind); - cs.cacheExprTypes(arg); + argExpr = AppliedPropertyWrapperExpr::create(ctx, callee, paramDecl, + argExpr->getStartLoc(), + wrapperType, argExpr, + valueKind); + cs.cacheExprTypes(argExpr); } if (argRequiresAutoClosureExpr(param, argType)) { @@ -6082,8 +5952,8 @@ Expr *ExprRewriter::coerceCallArguments( auto argLoc = getArgLocator(argIdx, paramIdx, param.getParameterFlags()); - arg = coerceToType( - arg, closureType->getResult(), + argExpr = coerceToType( + argExpr, closureType->getResult(), argLoc.withPathElement(ConstraintLocator::AutoclosureResult)); if (shouldInjectWrappedValuePlaceholder) { @@ -6094,18 +5964,18 @@ Expr *ExprRewriter::coerceCallArguments( bool isDefaultWrappedValue = target->propertyWrapperHasInitialWrappedValue(); auto *placeholder = injectWrappedValuePlaceholder( - cs.buildAutoClosureExpr(arg, closureType, dc, + cs.buildAutoClosureExpr(argExpr, closureType, dc, isDefaultWrappedValue), /*isAutoClosure=*/true); - arg = CallExpr::createImplicitEmpty(ctx, placeholder); - arg->setType(closureType->getResult()); - cs.cacheType(arg); + argExpr = CallExpr::createImplicitEmpty(ctx, placeholder); + argExpr->setType(closureType->getResult()); + cs.cacheType(argExpr); } - convertedArg = cs.buildAutoClosureExpr(arg, closureType, dc); + convertedArg = cs.buildAutoClosureExpr(argExpr, closureType, dc); } else { convertedArg = coerceToType( - arg, paramType, + argExpr, paramType, getArgLocator(argIdx, paramIdx, param.getParameterFlags())); } @@ -6116,66 +5986,19 @@ Expr *ExprRewriter::coerceCallArguments( if (!convertedArg) return nullptr; - newArgs.push_back(convertedArg); - - // Make an effort to preserve the sugared type of the argument in the - // case where there was no conversion, instead of using the parameter - // type. - newParams.emplace_back(cs.getType(convertedArg)->getInOutObjectType(), - param.getLabel(), - param.getParameterFlags()); - } - - assert(newArgs.size() == newParams.size()); - assert(newArgs.size() == newLabels.size()); - assert(newArgs.size() == newLabelLocs.size()); - assert(oldTrailingClosureIndex.hasValue() == - newTrailingClosureIndex.hasValue()); - assert(!newTrailingClosureIndex || *newTrailingClosureIndex < newArgs.size()); - - // This is silly. SILGen gets confused if a 'self' parameter is wrapped - // in a ParenExpr sometimes. - if (!argTuple && !argParen && - (params[0].getValueOwnership() == ValueOwnership::Default || - params[0].getValueOwnership() == ValueOwnership::InOut)) { - assert(newArgs.size() == 1); - assert(!newTrailingClosureIndex); - return newArgs[0]; - } - - // Rebuild the argument list, sharing as much structure as possible. - auto paramType = AnyFunctionType::composeTuple(ctx, newParams, - /*canonicalVararg=*/false); - if (isa(paramType.getPointer())) { - if (argParen) { - // We already had a ParenExpr, so replace it's sub-expression. - argParen->setSubExpr(newArgs[0]); - } else { - bool isImplicit = arg->isImplicit(); - arg = new (ctx) ParenExpr( - lParenLoc, newArgs[0], rParenLoc, - static_cast(newTrailingClosureIndex)); - arg->setImplicit(isImplicit); - } - } else { - assert(isa(paramType.getPointer())); - - if (argTuple && newArgs.size() == argTuple->getNumElements()) { - // The existing TupleExpr has the right number of elements, - // replace them. - for (unsigned i = 0, e = newArgs.size(); i != e; ++i) { - argTuple->setElement(i, newArgs[i]); - } - } else { - // Build a new TupleExpr, re-using source location information. - arg = TupleExpr::create(ctx, lParenLoc, rParenLoc, newArgs, newLabels, - newLabelLocs, newTrailingClosureIndex, - /*implicit=*/arg->isImplicit()); - } + arg.setExpr(convertedArg); + newArgs.push_back(arg); } - - arg->setType(paramType); - return cs.cacheType(arg); + auto *result = ArgumentList::create( + ctx, args->getLParenLoc(), newArgs, args->getRParenLoc(), + newTrailingClosureIndex, args->hasMultipleTrailingClosures(), + args->isImplicit()); +#ifndef NDEBUG + auto origArgs = result->getOriginalArguments(); + assert(origArgs.getFirstTrailingClosureIndex() == oldTrailingClosureIndex); + assert(origArgs.size() == args->size()); +#endif + return result; } static bool isClosureLiteralExpr(Expr *expr) { @@ -6902,15 +6725,12 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType, // Load the value for conversion. argExpr = cs.coerceToRValue(argExpr); - auto *implicitInit = - CallExpr::createImplicit(ctx, TypeExpr::createImplicit(toType, ctx), - /*args=*/{argExpr}, - /*argLabels=*/{Identifier()}); + auto *argList = ArgumentList::forImplicitUnlabeled(ctx, {argExpr}); + auto *implicitInit = CallExpr::createImplicit( + ctx, TypeExpr::createImplicit(toType, ctx), argList); cs.cacheExprTypes(implicitInit->getFn()); cs.setType(argExpr, fromType); - cs.setType(implicitInit->getArg(), - ParenType::get(cs.getASTContext(), fromType)); auto *callLocator = cs.getConstraintLocator( implicitInit, LocatorPathElt::ImplicitConversion(conversionKind)); @@ -7529,7 +7349,7 @@ static Expr *buildCallAsFunctionMethodRef( // Create direct reference to `callAsFunction` method. auto *fn = apply->getFn(); - auto *arg = apply->getArg(); + auto *args = apply->getArgs(); // HACK: Temporarily push the fn expr onto the expr stack to make sure we // don't try to prematurely close an existential when applying the curried @@ -7541,7 +7361,7 @@ static Expr *buildCallAsFunctionMethodRef( }; auto *declRef = rewriter.buildMemberRef( - fn, /*dotLoc*/ SourceLoc(), selected, DeclNameLoc(arg->getStartLoc()), + fn, /*dotLoc*/ SourceLoc(), selected, DeclNameLoc(args->getStartLoc()), calleeLoc, calleeLoc, /*implicit*/ true, AccessSemantics::Ordinary); if (!declRef) return nullptr; @@ -7550,17 +7370,13 @@ static Expr *buildCallAsFunctionMethodRef( } // Resolve `@dynamicCallable` applications. -std::pair -ExprRewriter::buildDynamicCallable(ApplyExpr *apply, SelectedOverload selected, - FuncDecl *method, - AnyFunctionType *methodType, - ConstraintLocatorBuilder loc) { +std::pair ExprRewriter::buildDynamicCallable( + ApplyExpr *apply, SelectedOverload selected, FuncDecl *method, + AnyFunctionType *methodType, ConstraintLocatorBuilder loc) { auto &ctx = cs.getASTContext(); auto *fn = apply->getFn(); - TupleExpr *arg = dyn_cast(apply->getArg()); - if (auto parenExpr = dyn_cast(apply->getArg())) - arg = TupleExpr::createImplicit(ctx, parenExpr->getSubExpr(), {}); + auto *args = apply->getArgs(); // Get resolved `dynamicallyCall` method and verify it. assert(isValidDynamicCallableMethod(method, methodType)); @@ -7588,12 +7404,12 @@ ExprRewriter::buildDynamicCallable(ApplyExpr *apply, SelectedOverload selected, // Construct argument to the method (either an array or dictionary // expression). - Expr *argument = nullptr; + Expr *argExpr = nullptr; if (!useKwargsMethod) { - argument = ArrayExpr::create(ctx, SourceLoc(), arg->getElements(), - {}, SourceLoc()); - cs.setType(argument, argumentType); - finishArrayExpr(cast(argument)); + argExpr = ArrayExpr::create(ctx, SourceLoc(), args->getArgExprs(), {}, + SourceLoc()); + cs.setType(argExpr, argumentType); + finishArrayExpr(cast(argExpr)); } else { auto dictLitProto = ctx.getProtocol(KnownProtocolKind::ExpressibleByDictionaryLiteral); @@ -7605,34 +7421,29 @@ ExprRewriter::buildDynamicCallable(ApplyExpr *apply, SelectedOverload selected, conformance.getTypeWitnessByName(argumentType, ctx.Id_Value); SmallVector names; SmallVector dictElements; - for (unsigned i = 0, n = arg->getNumElements(); i < n; ++i) { + for (auto arg : *args) { Expr *labelExpr = - new (ctx) StringLiteralExpr(arg->getElementName(i).get(), - arg->getElementNameLoc(i), + new (ctx) StringLiteralExpr(arg.getLabel().get(), arg.getLabelLoc(), /*Implicit*/ true); cs.setType(labelExpr, keyType); handleStringLiteralExpr(cast(labelExpr)); - Expr *valueExpr = coerceToType(arg->getElement(i), valueType, loc); + Expr *valueExpr = coerceToType(arg.getExpr(), valueType, loc); assert(valueExpr && "Failed to coerce?"); Expr *pair = TupleExpr::createImplicit(ctx, {labelExpr, valueExpr}, {}); auto eltTypes = { TupleTypeElt(keyType), TupleTypeElt(valueType) }; cs.setType(pair, TupleType::get(eltTypes, ctx)); dictElements.push_back(pair); } - argument = DictionaryExpr::create(ctx, SourceLoc(), dictElements, {}, - SourceLoc()); - cs.setType(argument, argumentType); - finishDictionaryExpr(cast(argument)); + argExpr = DictionaryExpr::create(ctx, SourceLoc(), dictElements, {}, + SourceLoc()); + cs.setType(argExpr, argumentType); + finishDictionaryExpr(cast(argExpr)); } - argument->setImplicit(); + argExpr->setImplicit(); - // Build the argument list expr. - argument = TupleExpr::createImplicit(ctx, {argument}, {argumentLabel}); - cs.setType(argument, - TupleType::get({TupleTypeElt(argumentType, argumentLabel)}, ctx)); - - return std::make_pair(member, argument); + auto *argList = ArgumentList::forImplicitSingle(ctx, argumentLabel, argExpr); + return std::make_pair(member, argList); } Expr *ExprRewriter::finishApply(ApplyExpr *apply, Type openedType, @@ -7640,7 +7451,7 @@ Expr *ExprRewriter::finishApply(ApplyExpr *apply, Type openedType, ConstraintLocatorBuilder calleeLocator) { auto &ctx = cs.getASTContext(); - auto *arg = apply->getArg(); + auto args = apply->getArgs(); auto *fn = apply->getFn(); auto finishApplyOfDeclWithSpecialTypeCheckingSemantics @@ -7650,41 +7461,30 @@ Expr *ExprRewriter::finishApply(ApplyExpr *apply, Type openedType, switch (TypeChecker::getDeclTypeCheckingSemantics(declRef.getDecl())) { case DeclTypeCheckingSemantics::TypeOf: { // Resolve into a DynamicTypeExpr. - auto arg = apply->getArg(); - - SmallVector argLabelsScratch; + auto args = apply->getArgs(); auto &appliedWrappers = solution.appliedPropertyWrappers[calleeLocator.getAnchor()]; auto fnType = cs.getType(fn)->getAs(); - arg = coerceCallArguments(arg, fnType, declRef, - apply, - apply->getArgumentLabels(argLabelsScratch), - locator.withPathElement( - ConstraintLocator::ApplyArgument), - appliedWrappers); - if (!arg) { + args = coerceCallArguments( + args, fnType, declRef, apply, + locator.withPathElement(ConstraintLocator::ApplyArgument), + appliedWrappers); + if (!args) return nullptr; - } - - if (auto tuple = dyn_cast(arg)) - arg = tuple->getElements()[0]; auto replacement = new (ctx) - DynamicTypeExpr(apply->getFn()->getLoc(), - apply->getArg()->getStartLoc(), - arg, - apply->getArg()->getEndLoc(), - Type()); + DynamicTypeExpr(apply->getFn()->getLoc(), args->getStartLoc(), + args->getExpr(0), args->getEndLoc(), Type()); cs.setType(replacement, simplifyType(openedType)); return replacement; } case DeclTypeCheckingSemantics::WithoutActuallyEscaping: { // Resolve into a MakeTemporarilyEscapableExpr. - auto arg = cast(apply->getArg()); - assert(arg->getNumElements() == 2 && "should have two arguments"); - auto nonescaping = arg->getElements()[0]; - auto body = arg->getElements()[1]; + auto *args = apply->getArgs(); + assert(args->size() == 2 && "should have two arguments"); + auto *nonescaping = args->getExpr(0); + auto *body = args->getExpr(1); auto bodyTy = cs.getType(body)->getWithoutSpecifierType(); auto bodyFnTy = bodyTy->castTo(); auto escapableParams = bodyFnTy->getParams(); @@ -7700,22 +7500,17 @@ Expr *ExprRewriter::finishApply(ApplyExpr *apply, Type openedType, OpaqueValueExpr(apply->getFn()->getSourceRange(), Type()); cs.setType(escapable, escapableParams[0].getOldType()); - auto getType = [&](Expr *E) -> Type { return cs.getType(E); }; - - auto callSubExpr = CallExpr::createImplicit(ctx, body, - {escapable}, {}, getType); + auto *argList = ArgumentList::forImplicitUnlabeled(ctx, {escapable}); + auto callSubExpr = CallExpr::createImplicit(ctx, body, argList); cs.cacheSubExprTypes(callSubExpr); - cs.setType(callSubExpr->getArg(), - AnyFunctionType::composeTuple(ctx, - escapableParams, false)); cs.setType(callSubExpr, resultType); auto replacement = new (ctx) MakeTemporarilyEscapableExpr(apply->getFn()->getLoc(), - apply->getArg()->getStartLoc(), + apply->getArgs()->getStartLoc(), nonescaping, callSubExpr, - apply->getArg()->getEndLoc(), + apply->getArgs()->getEndLoc(), escapable, apply); cs.setType(replacement, resultType); @@ -7724,11 +7519,11 @@ Expr *ExprRewriter::finishApply(ApplyExpr *apply, Type openedType, case DeclTypeCheckingSemantics::OpenExistential: { // Resolve into an OpenExistentialExpr. - auto arg = cast(apply->getArg()); - assert(arg->getNumElements() == 2 && "should have two arguments"); + auto *args = apply->getArgs(); + assert(args->size() == 2 && "should have two arguments"); - auto existential = cs.coerceToRValue(arg->getElements()[0]); - auto body = cs.coerceToRValue(arg->getElements()[1]); + auto *existential = cs.coerceToRValue(args->getExpr(0)); + auto *body = cs.coerceToRValue(args->getExpr(1)); auto bodyFnTy = cs.getType(body)->castTo(); auto openedTy = getBaseType(bodyFnTy, /*wantsRValue*/ false); @@ -7756,9 +7551,8 @@ Expr *ExprRewriter::finishApply(ApplyExpr *apply, Type openedType, new (ctx) OpaqueValueExpr(apply->getSourceRange(), openedTy); cs.setType(opaqueValue, openedTy); - auto getType = [&](Expr *E) -> Type { return cs.getType(E); }; - - auto callSubExpr = CallExpr::createImplicit(ctx, body, {opaqueValue}, {}, getType); + auto *argList = ArgumentList::forImplicitUnlabeled(ctx, {opaqueValue}); + auto callSubExpr = CallExpr::createImplicit(ctx, body, argList); cs.cacheSubExprTypes(callSubExpr); cs.setType(callSubExpr, resultTy); @@ -7804,8 +7598,8 @@ Expr *ExprRewriter::finishApply(ApplyExpr *apply, Type openedType, if (method && methodType) { // Handle a call to a @dynamicCallable method. if (isValidDynamicCallableMethod(method, methodType)) - std::tie(fn, arg) = buildDynamicCallable( - apply, *selected, method, methodType, applyFunctionLoc); + std::tie(fn, args) = buildDynamicCallable(apply, *selected, method, + methodType, applyFunctionLoc); } } @@ -7856,19 +7650,16 @@ Expr *ExprRewriter::finishApply(ApplyExpr *apply, Type openedType, // For function application, convert the argument to the input type of // the function. - SmallVector argLabelsScratch; if (auto fnType = cs.getType(fn)->getAs()) { auto &appliedWrappers = solution.appliedPropertyWrappers[calleeLocator.getAnchor()]; - arg = coerceCallArguments(arg, fnType, callee, apply, - apply->getArgumentLabels(argLabelsScratch), - locator.withPathElement( - ConstraintLocator::ApplyArgument), - appliedWrappers); - if (!arg) { + args = coerceCallArguments( + args, fnType, callee, apply, + locator.withPathElement(ConstraintLocator::ApplyArgument), + appliedWrappers); + if (!args) return nullptr; - } - apply->setArg(arg); + apply->setArgs(args); cs.setType(apply, fnType->getResult()); solution.setExprTypes(apply); @@ -7909,8 +7700,10 @@ Expr *ExprRewriter::finishApply(ApplyExpr *apply, Type openedType, // If we're "constructing" a tuple type, it's simply a conversion. if (auto tupleTy = ty->getAs()) { - // FIXME: Need an AST to represent this properly. - return coerceToType(apply->getArg(), tupleTy, locator); + auto *packed = apply->getArgs()->packIntoImplicitTupleOrParen( + ctx, [&](Expr *E) { return cs.getType(E); }); + cs.cacheType(packed); + return coerceToType(packed, tupleTy, cs.getConstraintLocator(packed)); } // We're constructing a value of nominal type. Look for the constructor or @@ -7946,8 +7739,6 @@ Expr *ExprRewriter::finishApply(ApplyExpr *apply, Type openedType, // Return the precedence-yielding parent of 'expr', along with the index of // 'expr' as the child of that parent. The precedence-yielding parent is the // nearest ancestor of 'expr' which imposes a minimum precedence on 'expr'. -// Right now that just means skipping over TupleExpr instances that only exist -// to hold arguments to binary operators. static std::pair getPrecedenceParentAndIndex( Expr *expr, llvm::function_ref getParent) { auto *parent = getParent(expr); @@ -7972,15 +7763,12 @@ static std::pair getPrecedenceParentAndIndex( auto elemIt = std::find(tupleElems.begin(), tupleElems.end(), expr); assert(elemIt != tupleElems.end() && "expr not found in parent TupleExpr"); unsigned index = elemIt - tupleElems.begin(); - - // Was this tuple just constructed for a binop? - if (auto *gparent = getParent(tuple)) { - if (isa(gparent)) - return { gparent, index }; - } - - // Must be a tuple literal, function arg list, collection, etc. return { tuple, index }; + } else if (auto *BE = dyn_cast(parent)) { + if (BE->getLHS() == expr) + return {parent, 0}; + if (BE->getRHS() == expr) + return {parent, 1}; } else if (auto ifExpr = dyn_cast(parent)) { unsigned index; if (expr == ifExpr->getCondExpr()) { @@ -8043,6 +7831,19 @@ bool swift::exprNeedsParensOutsideFollowingOperator( if (!parent) return false; + // If this is a call argument, no parens are needed. + if (auto *args = parent->getArgs()) { + if (!args->isImplicit() && args->findArgumentExpr(expr)) + return false; + } + + // If this is a key-path, no parens needed if it's an arg of one of the + // components. + if (auto *KP = dyn_cast(parent)) { + if (KP->findComponentWithSubscriptArg(expr)) + return false; + } + if (isa(parent) || isa(parent)) { if (!parent->isImplicit()) return false; diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp index 88454bedbcbb3..6af06f31d4c22 100644 --- a/lib/Sema/CSDiagnostics.cpp +++ b/lib/Sema/CSDiagnostics.cpp @@ -110,18 +110,9 @@ Expr *FailureDiagnostic::findParentExpr(const Expr *subExpr) const { return cs.getParentExpr(const_cast(subExpr)); } -Expr * -FailureDiagnostic::getArgumentListExprFor(ConstraintLocator *locator) const { - auto path = locator->getPath(); - auto iter = path.begin(); - if (!locator->findFirst(iter)) - return nullptr; - - // Form a new locator that ends at the ApplyArgument element, then simplify - // to get the argument list. - auto newPath = ArrayRef(path.begin(), iter + 1); - auto argListLoc = getConstraintLocator(locator->getAnchor(), newPath); - return getAsExpr(simplifyLocatorToAnchor(argListLoc)); +ArgumentList * +FailureDiagnostic::getArgumentListFor(ConstraintLocator *locator) const { + return getConstraintSystem().getArgumentList(locator); } Expr *FailureDiagnostic::getBaseExprFor(const Expr *anchor) const { @@ -833,28 +824,21 @@ bool GenericArgumentsMismatchFailure::diagnoseAsError() { } bool LabelingFailure::diagnoseAsError() { - auto *argExpr = getArgumentListExprFor(getLocator()); - if (!argExpr) + auto *args = getArgumentListFor(getLocator()); + if (!args) return false; - return diagnoseArgumentLabelError(getASTContext(), argExpr, CorrectLabels, + return diagnoseArgumentLabelError(getASTContext(), args, CorrectLabels, isExpr(getRawAnchor())); } bool LabelingFailure::diagnoseAsNote() { - auto *argExpr = getArgumentListExprFor(getLocator()); - if (!argExpr) + auto *args = getArgumentListFor(getLocator()); + if (!args) return false; - SmallVector argLabels; - if (isa(argExpr)) { - argLabels.push_back(Identifier()); - } else if (auto *tuple = dyn_cast(argExpr)) { - argLabels.append(tuple->getElementNames().begin(), - tuple->getElementNames().end()); - } else { - return false; - } + SmallVector scratch; + auto argLabels = args->getArgumentLabels(scratch); auto stringifyLabels = [](ArrayRef labels) -> std::string { std::string str; @@ -1559,7 +1543,6 @@ bool RValueTreatedAsLValueFailure::diagnoseAsError() { } if (auto callExpr = dyn_cast(diagExpr)) { - Expr *argExpr = callExpr->getArg(); loc = callExpr->getFn()->getLoc(); auto *locator = getLocator(); @@ -1570,61 +1553,34 @@ bool RValueTreatedAsLValueFailure::diagnoseAsError() { locator = getConstraintLocator(getRawAnchor(), path.drop_back()); } - if (isa(callExpr) || isa(callExpr)) { - subElementDiagID = diag::cannot_apply_lvalue_unop_to_subelement; - rvalueDiagID = diag::cannot_apply_lvalue_unop_to_rvalue; - diagExpr = argExpr; - } else if (isa(callExpr)) { - subElementDiagID = diag::cannot_apply_lvalue_binop_to_subelement; - rvalueDiagID = diag::cannot_apply_lvalue_binop_to_rvalue; - diagExpr = castToExpr(simplifyLocatorToAnchor(locator)); - } else if (auto argElt = - locator - ->getLastElementAs()) { - subElementDiagID = diag::cannot_pass_rvalue_inout_subelement; - rvalueDiagID = diag::cannot_pass_rvalue_inout; - if (auto argTuple = dyn_cast(argExpr)) - diagExpr = argTuple->getElement(argElt->getArgIdx()); - else if (auto parens = dyn_cast(argExpr)) - diagExpr = parens->getSubExpr(); + if (auto argInfo = getFunctionArgApplyInfo(locator)) { + if (isa(callExpr) || isa(callExpr)) { + subElementDiagID = diag::cannot_apply_lvalue_unop_to_subelement; + rvalueDiagID = diag::cannot_apply_lvalue_unop_to_rvalue; + } else if (isa(callExpr)) { + subElementDiagID = diag::cannot_apply_lvalue_binop_to_subelement; + rvalueDiagID = diag::cannot_apply_lvalue_binop_to_rvalue; + } else { + subElementDiagID = diag::cannot_pass_rvalue_inout_subelement; + rvalueDiagID = diag::cannot_pass_rvalue_inout; + } + diagExpr = argInfo->getArgExpr(); } else { subElementDiagID = diag::assignment_lhs_is_apply_expression; } - } else if (auto inoutExpr = dyn_cast(diagExpr)) { - if (auto *parentExpr = findParentExpr(inoutExpr)) { - if (auto *call = - dyn_cast_or_null(findParentExpr(parentExpr))) { - // Since this `inout` expression is an argument to a call/operator - // let's figure out whether this is an impliict conversion from - // array to an unsafe pointer type and diagnose it. - unsigned argIdx = 0; - if (auto *TE = dyn_cast(parentExpr)) { - for (unsigned n = TE->getNumElements(); argIdx != n; ++argIdx) { - if (TE->getElement(argIdx) == inoutExpr) - break; - } - } - - auto *argLoc = getConstraintLocator( - call, {ConstraintLocator::ApplyArgument, - LocatorPathElt::ApplyArgToParam(argIdx, argIdx, - ParameterTypeFlags())}); - - if (auto info = getFunctionArgApplyInfo(argLoc)) { - auto paramType = info->getParamType(); - auto argType = getType(inoutExpr)->getWithoutSpecifierType(); - - PointerTypeKind ptr; - if (isArrayType(argType) && - paramType->getAnyPointerElementType(ptr) && - (ptr == PTK_UnsafePointer || ptr == PTK_UnsafeRawPointer)) { - emitDiagnosticAt(inoutExpr->getLoc(), - diag::extra_address_of_unsafepointer, paramType) - .highlight(inoutExpr->getSourceRange()) - .fixItRemove(inoutExpr->getStartLoc()); - return true; - } - } + } else if (auto *inoutExpr = dyn_cast(diagExpr)) { + if (auto info = getFunctionArgApplyInfo(getLocator())) { + auto paramType = info->getParamType(); + auto argType = getType(inoutExpr)->getWithoutSpecifierType(); + + PointerTypeKind ptr; + if (isArrayType(argType) && paramType->getAnyPointerElementType(ptr) && + (ptr == PTK_UnsafePointer || ptr == PTK_UnsafeRawPointer)) { + emitDiagnosticAt(inoutExpr->getLoc(), + diag::extra_address_of_unsafepointer, paramType) + .highlight(inoutExpr->getSourceRange()) + .fixItRemove(inoutExpr->getStartLoc()); + return true; } } @@ -1755,7 +1711,9 @@ bool TrailingClosureAmbiguityFailure::diagnoseAsNote() { auto *callExpr = dyn_cast_or_null(expr); if (!callExpr) return false; - if (!callExpr->hasTrailingClosure()) + + // FIXME: We ought to handle multiple trailing closures here (SR-15054) + if (!callExpr->getArgs()->hasSingleTrailingClosure()) return false; if (callExpr->getFn() != anchor) return false; @@ -1823,10 +1781,10 @@ bool AssignmentFailure::diagnoseAsError() { if (choice.hasValue()) { auto getKeyPathArgument = [](SubscriptExpr *expr) { - auto *TE = dyn_cast(expr->getIndex()); - assert(TE->getNumElements() == 1); - assert(TE->getElementName(0).str() == "keyPath"); - return TE->getElement(0); + auto *args = expr->getArgs(); + assert(args->isUnary()); + assert(args->getLabel(0).str() == "keyPath"); + return args->getExpr(0); }; if (!choice->isDecl()) { @@ -2078,10 +2036,9 @@ AssignmentFailure::resolveImmutableBase(Expr *expr) const { // This must be a keypath application assert(member->getKind() == OverloadChoiceKind::KeyPathApplication); - auto *argType = getType(SE->getIndex())->castTo(); - assert(argType->getNumElements() == 1); - - auto indexType = resolveType(argType->getElementType(0)); + auto *unaryArg = SE->getArgs()->getUnaryExpr(); + assert(unaryArg); + auto indexType = getType(unaryArg); // In Swift versions lower than 5, this check will fail as read only // key paths can masquerade as writable for compatibilty reasons. @@ -2209,11 +2166,11 @@ Diag AssignmentFailure::findDeclDiagonstic(ASTContext &ctx, if (auto *subscript = dyn_cast(destExpr)) { auto diagID = diag::assignment_subscript_has_immutable_base; // If the destination is a subscript with a 'dynamicLookup:' label and if - // the tuple is implicit, then this was actually a @dynamicMemberLookup + // the subscript is implicit, then this was actually a @dynamicMemberLookup // access. Emit a more specific diagnostic. - if (subscript->getIndex()->isImplicit() && - subscript->getArgumentLabels().size() == 1 && - subscript->getArgumentLabels().front() == ctx.Id_dynamicMember) + auto *args = subscript->getArgs(); + if (subscript->isImplicit() && args->isUnary() && + args->getLabel(0) == ctx.Id_dynamicMember) diagID = diag::assignment_dynamic_property_has_immutable_base; return diagID; @@ -2606,13 +2563,20 @@ bool ContextualFailure::diagnoseConversionToNil() const { CTP = CTP_Initialization; } } - - // `nil` is passed as an argument to a parameter which doesn't - // expect it e.g. `foo(a: nil)`, `s[x: nil]` or `\S.[x: nil]`. - // FIXME: Find a more robust way of checking this. - if (isa(enclosingExpr) || isa(enclosingExpr) || - isa(enclosingExpr)) + } else if (isa(parentExpr)) { + // This is something like `\S.[x: nil]`. + CTP = CTP_CallArgument; + } else if (auto *args = parentExpr->getArgs()) { + // Check if `nil` is passed as an argument to a parameter which doesn't + // expect it e.g. `foo(a: nil)` or `s[x: nil]`. + if (args->findArgumentExpr(castToExpr(anchor))) { CTP = CTP_CallArgument; + } else { + // If the 'nil' isn't an argument, it'll be in the fn e.g `nil(5)`, + // which can't be inferred without a contextual type. + emitDiagnostic(diag::unresolved_nil_literal); + return true; + } } else if (isa(parentExpr)) { // `nil` is passed as a left-hand side of the coercion // operator e.g. `nil as Foo` @@ -2756,19 +2720,12 @@ bool ContextualFailure::diagnoseConversionToBool() const { // diagnostics if someone attempts to use an optional or integer as a boolean // condition. SourceLoc notOperatorLoc; - if (Expr *parent = findParentExpr(anchor)) { - if (isa(parent) && parent->isImplicit()) { - if ((parent = findParentExpr(parent))) { - auto parentOperatorApplication = dyn_cast(parent); - if (parentOperatorApplication) { - auto operatorRefExpr = - dyn_cast(parentOperatorApplication->getFn()); - if (operatorRefExpr && operatorRefExpr->getDecl()->getBaseName() == - getASTContext().Id_NegationOperator) { - notOperatorLoc = operatorRefExpr->getLoc(); - } - } - } + if (auto *parent = findParentExpr(anchor)) { + if (auto *parentOpCall = dyn_cast(parent)) { + auto &ctx = getASTContext(); + auto opRef = dyn_cast(parentOpCall->getFn()); + if (opRef && opRef->getDecl()->getBaseName() == ctx.Id_NegationOperator) + notOperatorLoc = opRef->getLoc(); } } @@ -2922,10 +2879,7 @@ bool ContextualFailure::tryIntegerCastFixIts( return nullptr; if (!isa(CE->getFn())) return nullptr; - auto *parenE = dyn_cast(CE->getArg()); - if (!parenE) - return nullptr; - return parenE->getSubExpr(); + return CE->getArgs()->getUnlabeledUnaryExpr(); }; if (auto *expr = getAsExpr(anchor)) { @@ -3461,7 +3415,7 @@ bool InvalidProjectedValueArgument::diagnoseAsError() { if (!param->hasAttachedPropertyWrapper()) { param->diagnose(diag::property_wrapper_param_no_wrapper, param->getName()); } else if (!param->hasImplicitPropertyWrapper() && - param->getAttachedPropertyWrappers().front()->getArg()) { + param->getAttachedPropertyWrappers().front()->hasArgs()) { param->diagnose(diag::property_wrapper_param_attr_arg); } else { Type backingType; @@ -3499,21 +3453,21 @@ bool SubscriptMisuseFailure::diagnoseAsError() { diag.highlight(memberRange).highlight(nameLoc.getSourceRange()); if (auto *parentExpr = dyn_cast_or_null(findParentExpr(memberExpr))) { - auto *argExpr = parentExpr->getArg(); + auto *args = parentExpr->getArgs(); auto toCharSourceRange = Lexer::getCharSourceRangeFromSourceRange; - auto lastArgSymbol = toCharSourceRange(sourceMgr, argExpr->getEndLoc()); + auto lastArgSymbol = toCharSourceRange(sourceMgr, args->getEndLoc()); - diag.fixItReplace(SourceRange(argExpr->getStartLoc()), + diag.fixItReplace(SourceRange(args->getStartLoc()), getTokenText(tok::l_square)); diag.fixItRemove(nameLoc.getSourceRange()); diag.fixItRemove(SourceRange(memberExpr->getDotLoc())); if (sourceMgr.extractText(lastArgSymbol) == getTokenText(tok::r_paren)) - diag.fixItReplace(SourceRange(argExpr->getEndLoc()), + diag.fixItReplace(SourceRange(args->getEndLoc()), getTokenText(tok::r_square)); else - diag.fixItInsertAfter(argExpr->getEndLoc(), getTokenText(tok::r_square)); + diag.fixItInsertAfter(args->getEndLoc(), getTokenText(tok::r_square)); } else { diag.fixItReplace(SourceRange(memberExpr->getDotLoc(), memberExpr->getLoc()), "[<#index#>]"); } @@ -3804,10 +3758,10 @@ bool MissingMemberFailure::diagnoseForSubscriptMemberWithTupleBase() const { if (!tupleType || tupleType->getNumElements() == 0) return false; - auto *index = SE->getIndex(); - if (SE->getNumArguments() == 1) { + auto *args = SE->getArgs(); + if (auto *argExpr = args->getUnaryExpr()) { auto *literal = - dyn_cast(index->getSemanticsProvidingExpr()); + dyn_cast(argExpr->getSemanticsProvidingExpr()); llvm::Regex NumericRegex("^[0-9]+$"); // Literal expressions may have other types of representations e.g. 0x01, @@ -3827,7 +3781,7 @@ bool MissingMemberFailure::diagnoseForSubscriptMemberWithTupleBase() const { emitDiagnostic( diag::could_not_find_subscript_member_tuple_did_you_mean_use_dot, baseType, literal->getDigitsText()) - .fixItReplace(index->getSourceRange(), OS.str()); + .fixItReplace(args->getSourceRange(), OS.str()); return true; } } @@ -3836,7 +3790,7 @@ bool MissingMemberFailure::diagnoseForSubscriptMemberWithTupleBase() const { // string literal expression which value matches a tuple element label, // let's suggest tuple label access. auto stringLiteral = - dyn_cast(index->getSemanticsProvidingExpr()); + dyn_cast(argExpr->getSemanticsProvidingExpr()); if (stringLiteral && !stringLiteral->getValue().empty() && llvm::any_of(tupleType->getElements(), [&](TupleTypeElt element) { return element.getName().is(stringLiteral->getValue()); @@ -3848,7 +3802,7 @@ bool MissingMemberFailure::diagnoseForSubscriptMemberWithTupleBase() const { emitDiagnostic( diag::could_not_find_subscript_member_tuple_did_you_mean_use_dot, baseType, stringLiteral->getValue()) - .fixItReplace(index->getSourceRange(), OS.str()); + .fixItReplace(args->getSourceRange(), OS.str()); return true; } } @@ -3952,15 +3906,13 @@ bool AllowTypeOrInstanceMemberFailure::diagnoseAsError() { } auto isCallArgument = [this](Expr *expr) { - auto argExpr = findParentExpr(expr); - if (!argExpr) - return false; auto possibleApplyExpr = findParentExpr(expr); - return isa_and_nonnull(possibleApplyExpr); + if (!possibleApplyExpr) + return false; + auto *args = possibleApplyExpr->getArgs(); + return args && args->findArgumentExpr(expr); }; - auto *initCall = findParentExpr(findParentExpr(ctorRef)); - auto isMutable = [&DC](ValueDecl *decl) { if (auto *storage = dyn_cast(decl)) return storage->isSettable(DC) && storage->isSetterAccessibleFrom(DC); @@ -3968,6 +3920,7 @@ bool AllowTypeOrInstanceMemberFailure::diagnoseAsError() { return true; }; + auto *initCall = findParentExpr(ctorRef); auto *baseLoc = getConstraintLocator(ctorRef->getBase()); if (auto selection = getCalleeOverloadChoiceIfAvailable(baseLoc)) { OverloadChoice choice = selection->choice; @@ -4031,10 +3984,10 @@ bool AllowTypeOrInstanceMemberFailure::diagnoseAsError() { if (auto callExpr = dyn_cast(maybeCallExpr)) { auto fnExpr = callExpr->getFn(); auto fnType = getType(fnExpr)->getRValueType(); - auto arg = callExpr->getArg(); + auto *args = callExpr->getArgs(); if (fnType->is()) { - emitDiagnosticAt(arg->getStartLoc(), + emitDiagnosticAt(args->getStartLoc(), diag::missing_init_on_metatype_initialization) .highlight(fnExpr->getSourceRange()); return true; @@ -4256,7 +4209,7 @@ bool InitOnProtocolMetatypeFailure::diagnoseAsError() { SourceLoc ImplicitInitOnNonConstMetatypeFailure::getLoc() const { if (auto *apply = getAsExpr(getRawAnchor())) - return apply->getArg()->getStartLoc(); + return apply->getArgs()->getStartLoc(); return FailureDiagnostic::getLoc(); } @@ -4276,6 +4229,12 @@ ASTNode MissingArgumentsFailure::getAnchor() const { return anchor; } +SourceLoc MissingArgumentsFailure::getLoc() const { + if (auto *argList = getArgumentListFor(getLocator())) + return argList->getLoc(); + return FailureDiagnostic::getLoc(); +} + bool MissingArgumentsFailure::diagnoseAsError() { auto *locator = getLocator(); @@ -4358,17 +4317,12 @@ bool MissingArgumentsFailure::diagnoseAsError() { auto diag = emitDiagnostic(diag::missing_arguments_in_call, arguments.str()); - Expr *fnExpr = nullptr; - Expr *argExpr = nullptr; - unsigned numArguments = 0; - Optional firstTrailingClosure = None; - - std::tie(fnExpr, argExpr, numArguments, firstTrailingClosure) = - getCallInfo(getRawAnchor()); + auto callInfo = getCallInfo(anchor); + auto *args = callInfo ? callInfo->second : nullptr; // TODO(diagnostics): We should be able to suggest this fix-it // unconditionally. - if (argExpr && numArguments == 0) { + if (args && args->empty()) { SmallString<32> scratch; llvm::raw_svector_ostream fixIt(scratch); interleave( @@ -4378,8 +4332,7 @@ bool MissingArgumentsFailure::diagnoseAsError() { }, [&] { fixIt << ", "; }); - auto *tuple = cast(argExpr); - diag.fixItInsertAfter(tuple->getLParenLoc(), fixIt.str()); + diag.fixItInsertAfter(args->getLParenLoc(), fixIt.str()); } diag.flush(); @@ -4426,17 +4379,12 @@ bool MissingArgumentsFailure::diagnoseSingleMissingArgument() const { auto position = argument.paramIdx; auto label = argument.param.getLabel(); - Expr *fnExpr = nullptr; - Expr *argExpr = nullptr; - unsigned numArgs = 0; - Optional firstTrailingClosure = None; - - std::tie(fnExpr, argExpr, numArgs, firstTrailingClosure) = - getCallInfo(anchor); - - if (!argExpr) { + auto callInfo = getCallInfo(anchor); + if (!callInfo) return false; - } + + auto *fnExpr = callInfo->first; + auto *args = callInfo->second; // Will the parameter accept a trailing closure? Type paramType = resolveType(argument.param.getPlainType()); @@ -4444,8 +4392,9 @@ bool MissingArgumentsFailure::diagnoseSingleMissingArgument() const { ->lookThroughAllOptionalTypes()->is(); // Determine whether we're inserting as a trailing closure. - bool insertingTrailingClosure = - firstTrailingClosure && position > *firstTrailingClosure; + auto firstTrailingClosureIdx = args->getRawFirstTrailingClosureIndex(); + auto insertingTrailingClosure = + firstTrailingClosureIdx && position > *firstTrailingClosureIdx; SmallString<32> insertBuf; llvm::raw_svector_ostream insertText(insertBuf); @@ -4457,13 +4406,14 @@ bool MissingArgumentsFailure::diagnoseSingleMissingArgument() const { forFixIt(insertText, argument.param); - if (position == 0 && numArgs > 0 && - (!firstTrailingClosure || position < *firstTrailingClosure)) + if (position == 0 && !args->empty() && + !args->isRawTrailingClosureIndex(position)) { insertText << ", "; + } SourceLoc insertLoc; - if (position >= numArgs && insertingTrailingClosure) { + if (position >= args->size() && insertingTrailingClosure) { // Add a trailing closure to the end. // fn { closure }: @@ -4472,9 +4422,8 @@ bool MissingArgumentsFailure::diagnoseSingleMissingArgument() const { // fn() {closure} label: [argMissing] // fn(argX) { closure }: // fn(argX) { closure } label: [argMissing] - insertLoc = Lexer::getLocForEndOfToken( - ctx.SourceMgr, argExpr->getEndLoc()); - } else if (auto *TE = dyn_cast(argExpr)) { + insertLoc = Lexer::getLocForEndOfToken(ctx.SourceMgr, args->getEndLoc()); + } else if (!args->isUnlabeledUnary()) { // fn(argX, argY): // fn([argMissing, ]argX, argY) // fn(argX[, argMissing], argY) @@ -4483,20 +4432,19 @@ bool MissingArgumentsFailure::diagnoseSingleMissingArgument() const { // fn(argX[, argMissing]) { closure } // fn(argX, argY): // fn(argX, argY[, argMissing]) - if (numArgs == 0) { - insertLoc = TE->getRParenLoc(); + if (args->empty()) { + insertLoc = args->getRParenLoc(); } else if (position != 0) { - auto argPos = std::min(TE->getNumElements(), position) - 1; + auto argPos = std::min(args->size(), position) - 1; insertLoc = Lexer::getLocForEndOfToken( - ctx.SourceMgr, TE->getElement(argPos)->getEndLoc()); + ctx.SourceMgr, args->getExpr(argPos)->getEndLoc()); } else { - insertLoc = TE->getElementNameLoc(0); + insertLoc = args->getLabelLoc(0); if (insertLoc.isInvalid()) - insertLoc = TE->getElement(0)->getStartLoc(); + insertLoc = args->getExpr(0)->getStartLoc(); } } else { - auto *PE = cast(argExpr); - if (PE->getRParenLoc().isValid()) { + if (args->getRParenLoc().isValid()) { // fn(): // fn([argMissing]) // fn(argX): @@ -4506,16 +4454,16 @@ bool MissingArgumentsFailure::diagnoseSingleMissingArgument() const { // fn([argMissing]) {closure} if (position == 0) { insertLoc = Lexer::getLocForEndOfToken(ctx.SourceMgr, - PE->getLParenLoc()); + args->getLParenLoc()); } else { insertLoc = Lexer::getLocForEndOfToken( - ctx.SourceMgr, PE->getSubExpr()->getEndLoc()); + ctx.SourceMgr, args->getExpr(0)->getEndLoc()); } } else { // fn { closure }: // fn[(argMissing)] { closure } assert(!isExpr(anchor) && "bracket less subscript"); - assert(firstTrailingClosure && + assert(args->hasAnyTrailingClosures() && "paren less ParenExpr without trailing closure"); insertBuf.insert(insertBuf.begin(), '('); insertBuf.insert(insertBuf.end(), ')'); @@ -4666,17 +4614,11 @@ bool MissingArgumentsFailure::diagnoseInvalidTupleDestructuring() const { if (SynthesizedArgs.size() < 2) return false; - auto anchor = getAnchor(); - - Expr *argExpr = nullptr; - // Something like `foo(x: (1, 2))` - if (auto *TE = getAsExpr(anchor)) { - if (TE->getNumElements() == 1) - argExpr = TE->getElement(0); - } else { // or `foo((1, 2))` - argExpr = castToExpr(anchor)->getSubExpr(); - } + auto *args = getArgumentListFor(locator); + if (!args) + return false; + auto *argExpr = args->getUnaryExpr(); if (!(argExpr && getType(argExpr)->getRValueType()->is())) return false; @@ -4759,46 +4701,34 @@ bool MissingArgumentsFailure::isMisplacedMissingArgument( hasFixFor(FixKind::AddMissingArguments, callLocator))) return false; - Expr *argExpr = nullptr; - if (auto *call = getAsExpr(anchor)) { - argExpr = call->getArg(); - } else if (auto *subscript = getAsExpr(anchor)) { - argExpr = subscript->getIndex(); - } else { + auto *anchorExpr = getAsExpr(anchor); + if (!anchorExpr) return false; - } - Expr *argument = nullptr; - if (auto *PE = dyn_cast(argExpr)) { - argument = PE->getSubExpr(); - } else { - auto *tuple = cast(argExpr); - if (tuple->getNumElements() != 1) - return false; - argument = tuple->getElement(0); - } + auto *argList = anchorExpr->getArgs(); + if (!argList) + return false; - auto argType = solution.simplifyType(solution.getType(argument)); + auto *unaryArg = argList->getUnaryExpr(); + if (!unaryArg) + return false; + + auto argType = solution.simplifyType(solution.getType(unaryArg)); auto paramType = fnType->getParams()[1].getPlainType(); return TypeChecker::isConvertibleTo(argType, paramType, solution.getDC()); } -std::tuple> +Optional> MissingArgumentsFailure::getCallInfo(ASTNode anchor) const { if (auto *call = getAsExpr(anchor)) { - return std::make_tuple(call->getFn(), call->getArg(), - call->getNumArguments(), - call->getUnlabeledTrailingClosureIndex()); + return std::make_pair(call->getFn(), call->getArgs()); } else if (auto *SE = getAsExpr(anchor)) { - return std::make_tuple(SE, SE->getIndex(), SE->getNumArguments(), - SE->getUnlabeledTrailingClosureIndex()); + return std::make_pair((Expr *)SE, SE->getArgs()); } else if (auto *OLE = getAsExpr(anchor)) { - return std::make_tuple(OLE, OLE->getArg(), OLE->getNumArguments(), - OLE->getUnlabeledTrailingClosureIndex()); + return std::make_pair((Expr *)OLE, OLE->getArgs()); } - - return std::make_tuple(nullptr, nullptr, 0, None); + return None; } void MissingArgumentsFailure::forFixIt( @@ -4965,32 +4895,28 @@ bool ClosureParamDestructuringFailure::diagnoseAsError() { bool OutOfOrderArgumentFailure::diagnoseAsError() { auto anchor = getRawAnchor(); - auto *argExpr = isExpr(anchor) - ? castToExpr(anchor) - : getArgumentListExprFor(getLocator()); - if (!argExpr) + auto *args = getArgumentListFor(getLocator()); + if (!args) return false; - auto *tuple = cast(argExpr); - - Identifier first = tuple->getElementName(ArgIdx); - Identifier second = tuple->getElementName(PrevArgIdx); + Identifier first = args->getLabel(ArgIdx); + Identifier second = args->getLabel(PrevArgIdx); // Build a mapping from arguments to parameters. - SmallVector argBindings(tuple->getNumElements()); + SmallVector argBindings(args->size()); for (unsigned paramIdx = 0; paramIdx != Bindings.size(); ++paramIdx) { for (auto argIdx : Bindings[paramIdx]) argBindings[argIdx] = paramIdx; } auto argRange = [&](unsigned argIdx, Identifier label) -> SourceRange { - auto range = tuple->getElement(argIdx)->getSourceRange(); + auto range = args->getExpr(argIdx)->getSourceRange(); if (!label.empty()) - range.Start = tuple->getElementNameLoc(argIdx); + range.Start = args->getLabelLoc(argIdx); unsigned paramIdx = argBindings[argIdx]; if (Bindings[paramIdx].size() > 1) - range.End = tuple->getElement(Bindings[paramIdx].back())->getEndLoc(); + range.End = args->getExpr(Bindings[paramIdx].back())->getEndLoc(); return range; }; @@ -5005,7 +4931,7 @@ bool OutOfOrderArgumentFailure::diagnoseAsError() { // list, which can happen when we're splicing together an argument list // from multiple sources. auto &SM = getASTContext().SourceMgr; - auto argsRange = tuple->getSourceRange(); + auto argsRange = args->getSourceRange(); if (!SM.rangeContains(argsRange, firstRange) || !SM.rangeContains(argsRange, secondRange)) return; @@ -5023,11 +4949,11 @@ bool OutOfOrderArgumentFailure::diagnoseAsError() { SourceLoc removalStartLoc; // For the first argument, start is always next token after `(`. if (ArgIdx == 0) { - removalStartLoc = tuple->getLParenLoc(); + removalStartLoc = args->getLParenLoc(); } else { // For all other arguments, start is the next token past // the previous argument. - removalStartLoc = tuple->getElement(ArgIdx - 1)->getEndLoc(); + removalStartLoc = args->getExpr(ArgIdx - 1)->getEndLoc(); } SourceRange removalRange{Lexer::getLocForEndOfToken(SM, removalStartLoc), @@ -5035,8 +4961,8 @@ bool OutOfOrderArgumentFailure::diagnoseAsError() { // Move requires postfix comma only if argument is moved in-between // other arguments. - bool requiresComma = !isExpr(anchor) && - PrevArgIdx != tuple->getNumElements() - 1; + bool requiresComma = + !isExpr(anchor) && PrevArgIdx != args->size() - 1; diag.fixItRemove(removalRange); diag.fixItInsert(secondRange.Start, @@ -5067,6 +4993,12 @@ bool OutOfOrderArgumentFailure::diagnoseAsError() { return true; } +SourceLoc ExtraneousArgumentsFailure::getLoc() const { + if (auto *argList = getArgumentListFor(getLocator())) + return argList->getLoc(); + return FailureDiagnostic::getLoc(); +} + bool ExtraneousArgumentsFailure::diagnoseAsError() { // Simplified anchor would point directly to the // argument in case of contextual mismatch. @@ -5160,10 +5092,10 @@ bool ExtraneousArgumentsFailure::diagnoseAsError() { } if (ContextualType->getNumParams() == 0) { - if (auto argExpr = getArgumentListExprFor(getLocator())) { + if (auto *args = getArgumentListFor(getLocator())) { emitDiagnostic(diag::extra_argument_to_nullary_call) - .highlight(argExpr->getSourceRange()) - .fixItRemove(argExpr->getSourceRange()); + .highlight(args->getSourceRange()) + .fixItRemove(args->getSourceRange()); return true; } } @@ -5182,12 +5114,10 @@ bool ExtraneousArgumentsFailure::diagnoseAsError() { [&] { OS << ", "; }); bool areTrailingClosures = false; - if (auto *argExpr = getArgumentListExprFor(getLocator())) { - if (auto i = argExpr->getUnlabeledTrailingClosureIndexOfPackedArgument()) { - areTrailingClosures = llvm::all_of(ExtraArgs, [&](auto &pair) { - return pair.first >= i; - }); - } + if (auto *argList = getArgumentListFor(getLocator())) { + areTrailingClosures = llvm::all_of(ExtraArgs, [&](auto &pair) { + return argList->isRawTrailingClosureIndex(pair.first); + }); } emitDiagnostic(diag::extra_arguments_in_call, areTrailingClosures, OS.str()); @@ -5224,12 +5154,12 @@ bool ExtraneousArgumentsFailure::diagnoseSingleExtraArgument() const { auto *TE = dyn_cast(call->getFn()); if (TE && getType(TE)->getMetatypeInstanceType()->isVoid()) { emitDiagnosticAt(call->getLoc(), diag::extra_argument_to_nullary_call) - .highlight(call->getArg()->getSourceRange()); + .highlight(call->getArgs()->getSourceRange()); return true; } } - auto *arguments = getArgumentListExprFor(locator); + auto *arguments = getArgumentListFor(locator); if (!arguments) return false; @@ -5237,37 +5167,26 @@ bool ExtraneousArgumentsFailure::diagnoseSingleExtraArgument() const { auto index = e.first; auto argument = e.second; - auto tuple = dyn_cast(arguments); - auto argExpr = tuple ? tuple->getElement(index) - : cast(arguments)->getSubExpr(); - - auto trailingClosureIdx = - arguments->getUnlabeledTrailingClosureIndexOfPackedArgument(); - auto isTrailingClosure = trailingClosureIdx && index >= *trailingClosureIdx; - + auto *argExpr = arguments->getExpr(index); auto loc = argExpr->getLoc(); - if (isTrailingClosure) { + if (arguments->isRawTrailingClosureIndex(index)) { emitDiagnosticAt(loc, diag::extra_trailing_closure_in_call) .highlight(argExpr->getSourceRange()); } else if (ContextualType->getNumParams() == 0) { - auto *PE = dyn_cast(arguments); - Expr *subExpr = nullptr; - if (PE) - subExpr = PE->getSubExpr(); - + auto *subExpr = arguments->getUnlabeledUnaryExpr(); if (subExpr && argument.getPlainType()->isVoid()) { emitDiagnosticAt(loc, diag::extra_argument_to_nullary_call) .fixItRemove(subExpr->getSourceRange()); } else { emitDiagnosticAt(loc, diag::extra_argument_to_nullary_call) - .highlight(argExpr->getSourceRange()); + .highlight(arguments->getSourceRange()); } } else if (argument.hasLabel()) { emitDiagnosticAt(loc, diag::extra_argument_named, argument.getLabel()) - .highlight(argExpr->getSourceRange()); + .highlight(arguments->getSourceRange()); } else { emitDiagnosticAt(loc, diag::extra_argument_positional) - .highlight(argExpr->getSourceRange()); + .highlight(arguments->getSourceRange()); } return true; } @@ -6060,8 +5979,8 @@ bool InvalidTupleSplatWithSingleParameterFailure::diagnoseAsError() { auto *choice = selectedOverload->choice.getDecl(); - auto *argExpr = getArgumentListExprFor(getLocator()); - if (!argExpr) + auto *args = getArgumentListFor(getLocator()); + if (!args) return false; using Substitution = std::pair; @@ -6099,36 +6018,35 @@ bool InvalidTupleSplatWithSingleParameterFailure::diagnoseAsError() { auto diagnostic = name.isSpecial() - ? emitDiagnosticAt(argExpr->getLoc(), + ? emitDiagnosticAt(args->getLoc(), diag::single_tuple_parameter_mismatch_special, choice->getDescriptiveKind(), paramTy, subsStr) : emitDiagnosticAt( - argExpr->getLoc(), diag::single_tuple_parameter_mismatch_normal, + args->getLoc(), diag::single_tuple_parameter_mismatch_normal, choice->getDescriptiveKind(), name, paramTy, subsStr); - auto newLeftParenLoc = argExpr->getStartLoc(); - if (auto *TE = dyn_cast(argExpr)) { - auto firstArgLabel = TE->getElementName(0); - // Cover situations like: - // - // func foo(x: (Int, Int)) {} - // foo(x: 0, 1) - // - // Where left paren should be suggested after the label, - // since the label belongs to the parameter itself. - if (!firstArgLabel.empty()) { - auto paramTuple = resolveType(ParamType)->castTo(); - // If the label of the first argument matches the one required - // by the parameter it would be omitted from the fixed parameter type. - if (!paramTuple->getElement(0).hasName()) - newLeftParenLoc = Lexer::getLocForEndOfToken(getASTContext().SourceMgr, - TE->getElementNameLoc(0)); - } - } + auto newLeftParenLoc = args->getStartLoc(); + auto firstArgLabel = args->getLabel(0); - diagnostic.highlight(argExpr->getSourceRange()) + // Cover situations like: + // + // func foo(x: (Int, Int)) {} + // foo(x: 0, 1) + // + // Where left paren should be suggested after the label, + // since the label belongs to the parameter itself. + if (!firstArgLabel.empty()) { + auto paramTuple = resolveType(ParamType)->castTo(); + // If the label of the first argument matches the one required + // by the parameter it would be omitted from the fixed parameter type. + if (!paramTuple->getElement(0).hasName()) + newLeftParenLoc = Lexer::getLocForEndOfToken(getASTContext().SourceMgr, + args->getLabelLoc(0)); + } + + diagnostic.highlight(args->getSourceRange()) .fixItInsertAfter(newLeftParenLoc, "(") - .fixItInsert(argExpr->getEndLoc(), ")"); + .fixItInsert(args->getEndLoc(), ")"); return true; } @@ -6506,13 +6424,18 @@ bool ArgumentMismatchFailure::diagnosePropertyWrapperMismatch() const { // Verify that this is an implicit call to a property wrapper initializer // in a form of `init(wrappedValue:)` or deprecated `init(initialValue:)`. auto *call = getAsExpr(getRawAnchor()); - if (!(call && call->isImplicit() && isa(call->getFn()) && - call->getNumArguments() == 1 && - (call->getArgumentLabels().front() == getASTContext().Id_wrappedValue || - call->getArgumentLabels().front() == getASTContext().Id_initialValue))) + if (!(call && call->isImplicit() && isa(call->getFn()))) + return false; + + auto *args = call->getArgs(); + auto *argExpr = args->getUnaryExpr(); + if (!argExpr) + return false; + + if (args->getLabel(0) != getASTContext().Id_wrappedValue && + args->getLabel(0) != getASTContext().Id_initialValue) return false; - auto argExpr = cast(call->getArg())->getElement(0); // If this is an attempt to initialize property wrapper with opaque value // of error type, let's just ignore that problem since original mismatch // has been diagnosed already. @@ -6619,12 +6542,9 @@ bool ExtraneousCallFailure::diagnoseAsError() { auto removeParensFixIt = [&](InFlightDiagnostic &diagnostic) { auto *argLoc = getConstraintLocator(getRawAnchor(), ConstraintLocator::ApplyArgument); - - if (auto *TE = getAsExpr(simplifyLocatorToAnchor(argLoc))) { - if (TE->getNumElements() == 0) { - diagnostic.fixItRemove(TE->getSourceRange()); - } - } + auto *argList = getArgumentListFor(argLoc); + if (argList && argList->empty()) + diagnostic.fixItRemove(argList->getSourceRange()); }; if (auto overload = getCalleeOverloadChoiceIfAvailable(locator)) { @@ -6644,10 +6564,11 @@ bool ExtraneousCallFailure::diagnoseAsError() { auto *call = castToExpr(getRawAnchor()); if (getType(baseExpr)->isAnyObject()) { + auto argsTy = call->getArgs()->composeTupleOrParenType( + getASTContext(), [&](Expr *E) { return getType(E); }); emitDiagnostic(diag::cannot_call_with_params, UDE->getName().getBaseName().userFacingName(), - getType(call->getArg())->getString(), - isa(baseExpr)); + argsTy.getString(), isa(baseExpr)); return true; } } @@ -7373,12 +7294,7 @@ void TrailingClosureRequiresExplicitLabel::fixIt( InFlightDiagnostic &diagnostic, const FunctionArgApplyInfo &info) const { auto &ctx = getASTContext(); - // Dig out source locations. - SourceLoc existingRParenLoc; - SourceLoc leadingCommaLoc; - auto anchor = getRawAnchor(); - auto *arg = info.getArgListExpr(); Expr *fn = nullptr; if (auto *applyExpr = getAsExpr(anchor)) { @@ -7393,15 +7309,13 @@ void TrailingClosureRequiresExplicitLabel::fixIt( auto *trailingClosure = info.getArgExpr(); - if (auto tupleExpr = dyn_cast(arg)) { - existingRParenLoc = tupleExpr->getRParenLoc(); - assert(tupleExpr->getNumElements() >= 2 && "Should be a ParenExpr?"); + auto *argList = info.getArgList(); + auto existingRParenLoc = argList->getRParenLoc(); + + SourceLoc leadingCommaLoc; + if (argList->size() >= 2) { leadingCommaLoc = Lexer::getLocForEndOfToken( - ctx.SourceMgr, - tupleExpr->getElements()[tupleExpr->getNumElements() - 2]->getEndLoc()); - } else { - auto parenExpr = cast(arg); - existingRParenLoc = parenExpr->getRParenLoc(); + ctx.SourceMgr, argList->getExpr(argList->size() - 2)->getEndLoc()); } // Figure out the text to be inserted before the trailing closure. diff --git a/lib/Sema/CSDiagnostics.h b/lib/Sema/CSDiagnostics.h index 8c5b8e121fc97..273f6ff92c67e 100644 --- a/lib/Sema/CSDiagnostics.h +++ b/lib/Sema/CSDiagnostics.h @@ -210,7 +210,7 @@ class FailureDiagnostic { /// within an argument application, returns the argument list for that /// application. If the locator is not for an argument application, or /// the argument list cannot be found, returns \c nullptr. - Expr *getArgumentListExprFor(ConstraintLocator *locator) const; + ArgumentList *getArgumentListFor(ConstraintLocator *locator) const; /// \returns A new type with all of the type variables associated with /// generic parameters substituted back into being generic parameter type. @@ -1389,6 +1389,8 @@ class MissingArgumentsFailure final : public FailureDiagnostic { assert(!SynthesizedArgs.empty() && "No missing arguments?!"); } + SourceLoc getLoc() const override; + ASTNode getAnchor() const override; bool diagnoseAsError() override; @@ -1412,10 +1414,8 @@ class MissingArgumentsFailure final : public FailureDiagnostic { bool isPropertyWrapperInitialization() const; /// Gather information associated with expression that represents - /// a call - function, arguments, # of arguments and the position of - /// the first trailing closure. - std::tuple> - getCallInfo(ASTNode anchor) const; + /// a call - function and argument list. + Optional> getCallInfo(ASTNode anchor) const; /// Transform given argument into format suitable for a fix-it /// text e.g. `[