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..bbf8240f0943b --- /dev/null +++ b/include/swift/AST/ArgumentList.h @@ -0,0 +1,575 @@ +//===--- 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/ADT/STLExtras.h" +#include "llvm/Support/TrailingObjects.h" + +namespace swift { +/// 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 + /// either no trailing closures, or the trailing closure info is present in + /// the original args. + unsigned RawFirstTrailingClosureIndex : 16; + + /// Whether an original set of arguments are available. + bool HasOriginalArgs : 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, + ArgumentList *originalArgs, bool isImplicit, bool hasLabels, + bool hasLabelLocs) + : LParenLoc(lParenLoc), RParenLoc(rParenLoc), NumArgs(numArgs), + HasOriginalArgs(originalArgs), IsImplicit(isImplicit), + HasLabels(hasLabels), HasLabelLocs(hasLabelLocs) { + assert(LParenLoc.isValid() == RParenLoc.isValid()); + assert(!(firstTrailingClosureIndex && originalArgs) && + "Cannot have trailing closure info if original args present"); + assert(!(originalArgs && originalArgs->getStoredOriginalArgs()) && + "Cannot chain original argument lists"); + assert(NumArgs == numArgs && "Num args truncated"); + assert(!firstTrailingClosureIndex || *firstTrailingClosureIndex < numArgs && + "Invalid trailing closure index"); + RawFirstTrailingClosureIndex = + firstTrailingClosureIndex.getValueOr(numArgs); + } + + 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; + } + size_t numTrailingObjects(OverloadToken) const { + return HasOriginalArgs ? 1 : 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}; + } + + ArgumentList *getStoredOriginalArgs() const { + if (!HasOriginalArgs) + return nullptr; + return *getTrailingObjects(); + } + +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. + /// \param isImplicit Whether this is an implicitly generated argument list. + /// \param originalArgs An original argument list prior to being rewritten by + /// the expression type-checker. Note \p firstTrailingClosureIndex must be + /// \c None if an original argument list is available. + /// \param arena The arena to allocate the ArgumentList in. + static ArgumentList * + create(ASTContext &ctx, SourceLoc lParenLoc, ArrayRef args, + SourceLoc rParenLoc, Optional firstTrailingClosureIndex, + bool isImplicit, ArgumentList *originalArgs = nullptr, + AllocationArena arena = AllocationArena::Permanent); + + /// Create a new explicit parsed 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. + static ArgumentList * + createParsed(ASTContext &ctx, SourceLoc lParenLoc, ArrayRef args, + SourceLoc rParenLoc, + Optional firstTrailingClosureIndex); + + /// Create a new type-checked ArgumentList from an original set of arguments. + /// + /// \param originalArgs An original argument list prior to being rewritten by + /// the type-checker. + /// \param newArgs The new set of arguments for the call. + static ArgumentList *createTypeChecked(ASTContext &ctx, + ArgumentList *originalArgs, + ArrayRef newArgs); + + /// 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)); + } + + // MARK: Iterator Logic + + unsigned size() const { return NumArgs; } + bool empty() const { return size() == 0; } + + class iterator final + : public llvm::indexed_accessor_iterator { + public: + iterator(const ArgumentList *argList, unsigned idx) + : indexed_accessor_iterator(argList, idx) {} + + Argument operator*() const { + assert(getBase()); + return getBase()->get(getIndex()); + } + Argument operator[](unsigned i) const { + assert(getBase()); + return getBase()->get(getIndex() + i); + } + }; + + 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); } + + // MARK: Trailing Closure Queries + // + // Trailing closure queries cannot be done on a type-checked argument list, + // instead they must be done on the original argument list prior to rewriting + // in CSApply. This can be obtained by querying the \c getOriginalArgs method. + // + // This restriction is due to the fact that trailing closures in type-checked + // argument lists can have an awkward representation. They may be: + // - Nested within variadic expansion exprs, and may not be the first element + // of that expansion. + // - In a position *before* default argument expressions, or even explicitly + // written non-trailing arguments in certain backward scanning argument + // matching cases. + + /// Returns the index of the first trailing closure in the argument list, or + /// \c None if there are no trailing closures. + /// + /// Note for a type-checked argument list, this must be queried on + /// \c getOriginalArgs instead. + Optional getFirstTrailingClosureIndex() const { + assert(!HasOriginalArgs && "Query original args instead"); + if (RawFirstTrailingClosureIndex == NumArgs) + return None; + return RawFirstTrailingClosureIndex; + } + + /// The number of trailing closures in the argument list. + /// + /// Note for a type-checked argument list, this must be queried on + /// \c getOriginalArgs instead. + unsigned getNumTrailingClosures() const { + assert(!HasOriginalArgs && "Query original args instead"); + if (!getFirstTrailingClosureIndex()) + return 0; + return size() - *getFirstTrailingClosureIndex(); + } + + /// Whether any unlabeled or labeled trailing closures are present. + bool hasAnyTrailingClosures() const { + return getOriginalArgs()->getFirstTrailingClosureIndex().hasValue(); + } + + /// Whether a given index is for an unlabeled trailing closure, which is the + /// first trailing closure in the argument list. + /// + /// Note for a type-checked argument list, this must be queried on + /// \c getOriginalArgs instead. + bool isUnlabeledTrailingClosureIndex(unsigned i) const { + assert(!HasOriginalArgs && "Query original args instead"); + return hasAnyTrailingClosures() && *getFirstTrailingClosureIndex() == i; + } + + /// Whether a given index is for a labeled trailing closure in an argument + /// list with multiple trailing closures. + /// + /// Note for a type-checked argument list, this must be queried on + /// \c getOriginalArgs instead. + bool isLabeledTrailingClosureIndex(unsigned i) const { + assert(!HasOriginalArgs && "Query original args instead"); + if (!hasAnyTrailingClosures()) + return false; + return i > *getFirstTrailingClosureIndex() && i < size(); + } + + /// Whether a given index is for a labeled or unlabeled trailing closure. + /// + /// Note for a type-checked argument list, this must be queried on + /// \c getOriginalArgs instead. + bool isTrailingClosureIndex(unsigned i) const { + assert(!HasOriginalArgs && "Query original args instead"); + if (!hasAnyTrailingClosures()) + return false; + return i >= *getFirstTrailingClosureIndex() && i < size(); + } + + /// Returns the range of arguments excluding any trailing closures. + /// + /// Note for a type-checked argument list, this must be queried on + /// \c getOriginalArgs instead. + iterator_range getNonTrailingArgs() const { + assert(!HasOriginalArgs && "Query original args instead"); + auto idx = getFirstTrailingClosureIndex(); + if (!idx.hasValue()) + return *this; + + return {begin(), iterator(this, *idx)}; + } + + /// Returns the range of trailing closure arguments. + /// + /// Note for a type-checked argument list, this must be queried on + /// \c getOriginalArgs instead. + iterator_range getTrailingClosures() const { + assert(!HasOriginalArgs && "Query original args instead"); + auto idx = getFirstTrailingClosureIndex(); + if (!idx.hasValue()) + return {end(), end()}; + + return {iterator(this, *idx), end()}; + } + + /// Retrieve the first trailing closure argument in the argument list, or + /// \c None if there are no trailing closures. + /// + /// Note for a type-checked argument list, this must be queried on + /// \c getOriginalArgs instead. + Optional getFirstTrailingClosure() const { + assert(!HasOriginalArgs && "Query original args instead"); + auto idx = getFirstTrailingClosureIndex(); + if (!idx.hasValue()) + return None; + return get(*idx); + } + + /// Retrieve the source range of any trailing closure arguments, or an empty + /// range if there are no trailing closures. + /// + /// Note for a type-checked argument list, this must be queried on + /// \c getOriginalArgs instead. + SourceRange getTrailingSourceRange() const { + assert(!HasOriginalArgs && "Query original args instead"); + auto firstClosure = getFirstTrailingClosure(); + if (!firstClosure) + return SourceRange(); + + return SourceRange(firstClosure->getStartLoc(), back().getEndLoc()); + } + + // MARK: Misc Queries + + /// 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; + + /// Returns the argument list prior to being rewritten by the expression + /// type-checker. If the argument list either hasn't been type-checked yet, + /// or was implicitly generated as type-checked, it returns itself. + /// + /// Note that returned argument list will still have rewritten argument + /// expressions with types. However the order of the arguments will reflect + /// the call-site as written by the user, default arguments will be stripped, + /// and variadic arguments will be expanded. + ArgumentList *getOriginalArgs() { + if (auto *originalArgs = getStoredOriginalArgs()) + return originalArgs; + return this; + } + + /// Returns the argument list prior to being rewritten by the expression + /// type-checker. If the argument list either hasn't been type-checked yet, + /// or was implicitly generated as type-checked, it returns itself. + /// + /// Note that returned argument list will still have rewritten argument + /// expressions with types. However the order of the arguments will reflect + /// the call-site as written by the user, default arguments will be stripped, + /// and variadic arguments will be expanded. + const ArgumentList *getOriginalArgs() const { + if (auto *originalArgs = getStoredOriginalArgs()) + return originalArgs; + return this; + } + + ArgumentList *walk(ASTWalker &walker); + + SWIFT_DEBUG_DUMP; + void dump(raw_ostream &OS, unsigned Indent = 0) const; +}; + +} // end namespace swift + +#endif 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/include/swift/IDE/Utils.h b/include/swift/IDE/Utils.h index 944168ebeb02b..2e8aeb694c324 100644 --- a/include/swift/IDE/Utils.h +++ b/include/swift/IDE/Utils.h @@ -244,9 +244,9 @@ class NameMatcher: public ASTWalker { std::vector ResolvedLocs; ArrayRef TokensToCheck; - /// The \c Expr argument of a parent \c CustomAttr (if one exists) and + /// The \c ArgumentList of a parent \c CustomAttr (if one exists) and /// the \c SourceLoc of the type name it applies to. - llvm::Optional> CustomAttrArg; + llvm::Optional> CustomAttrArgList; unsigned InactiveConfigRegionNestings = 0; unsigned SelectorNestings = 0; @@ -265,12 +265,13 @@ class NameMatcher: public ASTWalker { bool shouldSkip(SourceRange Range); bool shouldSkip(CharSourceRange Range); bool tryResolve(ASTWalker::ParentTy Node, SourceLoc NameLoc); - bool tryResolve(ASTWalker::ParentTy Node, DeclNameLoc NameLoc, Expr *Arg); + bool tryResolve(ASTWalker::ParentTy Node, DeclNameLoc NameLoc, + ArgumentList *Args); bool tryResolve(ASTWalker::ParentTy Node, SourceLoc NameLoc, LabelRangeType RangeType, ArrayRef LabelLocs, Optional FirstTrailingLabel); bool handleCustomAttrs(Decl *D); - Expr *getApplicableArgFor(Expr* E); + ArgumentList *getApplicableArgsFor(Expr* E); std::pair walkToExprPre(Expr *E) override; Expr* walkToExprPost(Expr *E) override; @@ -283,6 +284,9 @@ class NameMatcher: public ASTWalker { std::pair walkToPatternPre(Pattern *P) override; bool shouldWalkIntoGenericParams() override { return true; } + std::pair + walkToArgumentListPre(ArgumentList *ArgList) override; + // FIXME: Remove this bool shouldWalkAccessorsTheOldWay() override { return true; } @@ -568,13 +572,14 @@ struct CallArgInfo { }; std::vector -getCallArgInfo(SourceManager &SM, Expr *Arg, LabelRangeEndAt EndKind); +getCallArgInfo(SourceManager &SM, ArgumentList *Args, LabelRangeEndAt EndKind); // Get the ranges of argument labels from an Arg, either tuple or paren, and // the index of the first trailing closure argument, if any. This includes empty // ranges for any unlabelled arguments, including the first trailing closure. std::pair, Optional> -getCallArgLabelRanges(SourceManager &SM, Expr *Arg, LabelRangeEndAt EndKind); +getCallArgLabelRanges(SourceManager &SM, ArgumentList *Args, + LabelRangeEndAt EndKind); /// Whether a decl is defined from clang source. bool isFromClang(const Decl *D); 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/include/swift/Sema/ConstraintSystem.h b/include/swift/Sema/ConstraintSystem.h index 72cfb3981b23a..c711dcc6e6b0c 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->isTrailingClosureIndex(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/include/swift/Sema/IDETypeChecking.h b/include/swift/Sema/IDETypeChecking.h index a4ede7727c54a..7cef59c04974d 100644 --- a/include/swift/Sema/IDETypeChecking.h +++ b/include/swift/Sema/IDETypeChecking.h @@ -233,50 +233,6 @@ namespace swift { std::vector &VariableTypeInfos, llvm::raw_ostream &OS); - /// FIXME: All of the below goes away once CallExpr directly stores its - /// arguments. - - /// Return value for getOriginalArgumentList(). - struct OriginalArgumentList { - SmallVector args; - SmallVector labels; - SmallVector labelLocs; - SourceLoc lParenLoc; - SourceLoc rParenLoc; - Optional unlabeledTrailingClosureIdx; - - /// The number of trailing closures in the argument list. - unsigned getNumTrailingClosures() const { - if (!unlabeledTrailingClosureIdx) - return 0; - return args.size() - *unlabeledTrailingClosureIdx; - } - - /// Whether any unlabeled or labeled trailing closures are present. - bool hasAnyTrailingClosures() const { - return unlabeledTrailingClosureIdx.hasValue(); - } - - /// Whether the given index is for an unlabeled trailing closure. - bool isUnlabeledTrailingClosureIdx(unsigned i) const { - return unlabeledTrailingClosureIdx && *unlabeledTrailingClosureIdx == i; - } - - /// Whether the given index is for a labeled trailing closure in an - /// argument list with multiple trailing closures. - bool isLabeledTrailingClosureIdx(unsigned i) const { - if (!unlabeledTrailingClosureIdx) - return false; - return i > *unlabeledTrailingClosureIdx && i < args.size(); - } - }; - - /// 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 we want to work on the original argument list as - /// written by the user; this performs the reverse transformation. - OriginalArgumentList getOriginalArgumentList(Expr *expr); - /// Returns the root type and result type of the keypath type in a keypath /// dynamic member lookup subscript, or \c None if it cannot be determined. /// 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 eed46cbb9542f..80571d99b0a64 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) @@ -1907,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) << ')'; } @@ -2022,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) << ')'; @@ -2042,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="; @@ -2096,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) { @@ -2115,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) { @@ -2495,12 +2489,61 @@ 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) << '('; + 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) { @@ -2509,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) << ')'; } @@ -2746,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"; @@ -2768,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) << ')'; } @@ -2857,6 +2894,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/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 a2adbee92cd57..1c651297be25b 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; } @@ -1367,6 +1340,20 @@ class Traversal : public ASTVisitorgetExpr(Idx)); + if (!E) return nullptr; + ArgList->setExpr(Idx, E); + } + return Walker.walkToArgumentListPost(ArgList); + } }; } // end anonymous namespace @@ -1912,3 +1899,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..29093198d9f8e --- /dev/null +++ b/lib/AST/ArgumentList.cpp @@ -0,0 +1,304 @@ +//===--- 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(); +} + +ArgumentList *ArgumentList::create(ASTContext &ctx, SourceLoc lParenLoc, + ArrayRef args, SourceLoc rParenLoc, + Optional firstTrailingClosureIndex, + bool isImplicit, ArgumentList *originalArgs, + AllocationArena arena) { + 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(), originalArgs ? 1 : 0); + auto *mem = ctx.Allocate(numBytes, alignof(ArgumentList), arena); + auto *argList = new (mem) + ArgumentList(lParenLoc, rParenLoc, args.size(), firstTrailingClosureIndex, + originalArgs, 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()); + } + if (originalArgs) { + *argList->getTrailingObjects() = originalArgs; + } + return argList; +} + +ArgumentList * +ArgumentList::createParsed(ASTContext &ctx, SourceLoc lParenLoc, + ArrayRef args, SourceLoc rParenLoc, + Optional firstTrailingClosureIndex) { + return create(ctx, lParenLoc, args, rParenLoc, firstTrailingClosureIndex, + /*implicit*/ false); +} + +ArgumentList *ArgumentList::createTypeChecked(ASTContext &ctx, + ArgumentList *originalArgs, + ArrayRef newArgs) { + return create(ctx, originalArgs->getLParenLoc(), newArgs, + originalArgs->getRParenLoc(), /*trailingClosureIdx*/ None, + originalArgs->isImplicit(), originalArgs); +} + +ArgumentList *ArgumentList::createImplicit(ASTContext &ctx, SourceLoc lParenLoc, + ArrayRef args, + SourceLoc rParenLoc, + AllocationArena arena) { + return create(ctx, lParenLoc, args, rParenLoc, + /*firstTrailingClosureIdx*/ None, /*implicit*/ true, + /*originalArgs*/ nullptr, 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() || RParenLoc.isInvalid()) { + // Scan backward for the first valid source loc. We use getOriginalArgs to + // filter out default arguments and get accurate trailing closure info. + for (auto arg : llvm::reverse(*getOriginalArgs())) { + end = arg.getEndLoc(); + if (end.isValid()) + 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; +} 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/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 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/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp index 5b91a36f1a9e9..0877a804af3ec 100644 --- a/lib/ClangImporter/ImportDecl.cpp +++ b/lib/ClangImporter/ImportDecl.cpp @@ -492,8 +492,9 @@ synthesizeEnumRawValueConstructorBody(AbstractFunctionDecl *afd, reinterpretCastRef->setType( FunctionType::get({FunctionType::Param(rawTy)}, enumTy, info)); + auto *argList = ArgumentList::forImplicitUnlabeled(ctx, {paramRef}); auto reinterpreted = CallExpr::createImplicit(ctx, reinterpretCastRef, - { paramRef }, { Identifier() }); + argList); reinterpreted->setType(enumTy); reinterpreted->setThrows(false); @@ -574,8 +575,9 @@ synthesizeEnumRawValueGetterBody(AbstractFunctionDecl *afd, void *context) { reinterpretCastRef->setType( FunctionType::get({FunctionType::Param(enumTy)}, rawTy, info)); + auto *argList = ArgumentList::forImplicitUnlabeled(ctx, {selfRef}); auto reinterpreted = CallExpr::createImplicit(ctx, reinterpretCastRef, - { selfRef }, { Identifier() }); + argList); reinterpreted->setType(rawTy); reinterpreted->setThrows(false); @@ -940,9 +942,9 @@ synthesizeUnionFieldGetterBody(AbstractFunctionDecl *afd, void *context) { FunctionType::get(AnyFunctionType::Param(selfDecl->getInterfaceType()), importedFieldDecl->getInterfaceType(), info)); + auto *argList = ArgumentList::forImplicitUnlabeled(ctx, {selfRef}); auto reinterpreted = CallExpr::createImplicit(ctx, reinterpretCastRefExpr, - { selfRef }, - { Identifier() }); + argList); reinterpreted->setType(importedFieldDecl->getInterfaceType()); reinterpreted->setThrows(false); auto ret = new (ctx) ReturnStmt(SourceLoc(), reinterpreted); @@ -987,9 +989,10 @@ synthesizeUnionFieldSetterBody(AbstractFunctionDecl *afd, void *context) { AnyFunctionType::Param(inoutSelfDecl->getInterfaceType(), Identifier(), ParameterTypeFlags().withInOut(true)), ctx.TheRawPointerType, addressOfInfo)); + + auto *selfPtrArgs = ArgumentList::forImplicitUnlabeled(ctx, {inoutSelf}); auto selfPointer = CallExpr::createImplicit(ctx, addressofFnRefExpr, - { inoutSelf }, - { Identifier() }); + selfPtrArgs); selfPointer->setType(ctx.TheRawPointerType); selfPointer->setThrows(false); @@ -1007,9 +1010,11 @@ synthesizeUnionFieldSetterBody(AbstractFunctionDecl *afd, void *context) { {AnyFunctionType::Param(newValueDecl->getInterfaceType()), AnyFunctionType::Param(ctx.TheRawPointerType)}, TupleType::getEmpty(ctx), initializeInfo)); + + auto *initArgs = + ArgumentList::forImplicitUnlabeled(ctx, {newValueRef, selfPointer}); auto initialize = CallExpr::createImplicit(ctx, initializeFnRefExpr, - { newValueRef, selfPointer }, - { Identifier(), Identifier() }); + initArgs); initialize->setType(TupleType::getEmpty(ctx)); initialize->setThrows(false); @@ -7653,9 +7658,9 @@ createAccessorImplCallExpr(FuncDecl *accessorImpl, accessorImplDotCallExpr->setType(accessorImpl->getMethodInterfaceType()); accessorImplDotCallExpr->setThrows(false); + auto *argList = ArgumentList::forImplicitUnlabeled(ctx, {keyRefExpr}); auto *accessorImplCallExpr = - CallExpr::createImplicit(ctx, accessorImplDotCallExpr, - { keyRefExpr }, { Identifier() }); + CallExpr::createImplicit(ctx, accessorImplDotCallExpr, argList); accessorImplCallExpr->setType(accessorImpl->getResultInterfaceType()); accessorImplCallExpr->setThrows(false); return accessorImplCallExpr; @@ -9705,8 +9710,8 @@ synthesizeConstantGetterBody(AbstractFunctionDecl *afd, void *voidContext) { // (rawValue: T) -> ... initTy = initTy->castTo()->getResult(); - auto initCall = CallExpr::createImplicit(ctx, initRef, { expr }, - { ctx.Id_rawValue }); + auto *argList = ArgumentList::forImplicitSingle(ctx, ctx.Id_rawValue, expr); + auto initCall = CallExpr::createImplicit(ctx, initRef, argList); initCall->setType(initTy); initCall->setThrows(false); diff --git a/lib/IDE/ExprContextAnalysis.cpp b/lib/IDE/ExprContextAnalysis.cpp index 35cbc3efce163..465d884fa5845 100644 --- a/lib/IDE/ExprContextAnalysis.cpp +++ b/lib/IDE/ExprContextAnalysis.cpp @@ -212,62 +212,33 @@ class CCExprRemover: public ASTWalker, public ExprVisitor CCExprRemover(ASTContext &Ctx) : Ctx(Ctx) {} Expr *visitCallExpr(CallExpr *E) { - SourceLoc lParenLoc, rParenLoc; - SmallVector argLabels; - SmallVector argLabelLocs; - SmallVector args; - SmallVector trailingClosures; - bool removing = false; - - if (auto paren = dyn_cast(E->getArg())) { - if (isa(paren->getSubExpr())) { - lParenLoc = paren->getLParenLoc(); - rParenLoc = paren->getRParenLoc(); - removing = true; - } - } else if (auto tuple = dyn_cast(E->getArg())) { - lParenLoc = tuple->getLParenLoc(); - rParenLoc = tuple->getRParenLoc(); - - assert((!E->getUnlabeledTrailingClosureIndex().hasValue() || - (tuple->getNumElements() == E->getArgumentLabels().size() && - tuple->getNumElements() == E->getArgumentLabelLocs().size())) && - "CallExpr with trailing closure must have the same number of " - "argument labels"); - assert(tuple->getNumElements() == E->getArgumentLabels().size()); - assert(tuple->getNumElements() == E->getArgumentLabelLocs().size() || - E->getArgumentLabelLocs().size() == 0); - - bool hasArgumentLabelLocs = E->getArgumentLabelLocs().size() > 0; - - for (unsigned i = 0, e = tuple->getNumElements(); i != e; ++i) { - if (isa(tuple->getElement(i))) { - removing = true; - continue; - } - - if (!E->getUnlabeledTrailingClosureIndex().hasValue() || - i < *E->getUnlabeledTrailingClosureIndex()) { - // Normal arguments. - argLabels.push_back(E->getArgumentLabels()[i]); - if (hasArgumentLabelLocs) - argLabelLocs.push_back(E->getArgumentLabelLocs()[i]); - args.push_back(tuple->getElement(i)); - } else { - // Trailing closure arguments. - trailingClosures.emplace_back(E->getArgumentLabels()[i], - E->getArgumentLabelLocs()[i], - tuple->getElement(i)); - } + auto *args = E->getArgs()->getOriginalArgs(); + + Optional newTrailingClosureIdx; + SmallVector newArgs; + for (auto idx : indices(*args)) { + // Update the trailing closure index if we have one. + if (args->hasAnyTrailingClosures() && + idx == *args->getFirstTrailingClosureIndex()) { + newTrailingClosureIdx = newArgs.size(); } + auto arg = args->get(idx); + if (!isa(arg.getExpr())) + newArgs.push_back(arg); } - if (removing) { - Removed = true; - return CallExpr::create(Ctx, E->getFn(), lParenLoc, args, argLabels, - argLabelLocs, rParenLoc, trailingClosures, - E->isImplicit()); - } - return E; + if (newArgs.size() == args->size()) + return E; + + // If we ended up removing the last trailing closure, drop the index. + if (newTrailingClosureIdx && *newTrailingClosureIdx == newArgs.size()) + newTrailingClosureIdx = None; + + Removed = true; + + auto *argList = ArgumentList::create( + Ctx, args->getLParenLoc(), newArgs, args->getRParenLoc(), + newTrailingClosureIdx, E->isImplicit()); + return CallExpr::create(Ctx, E->getFn(), argList, E->isImplicit()); } Expr *visitExpr(Expr *E) { @@ -656,12 +627,12 @@ static bool collectPossibleCalleesForApply( } else if (auto *DSCE = dyn_cast(fnExpr)) { if (auto *DRE = dyn_cast(DSCE->getFn())) { collectPossibleCalleesByQualifiedLookup( - DC, DSCE->getArg(), DeclNameRef(DRE->getDecl()->getName()), + DC, DSCE->getBase(), DeclNameRef(DRE->getDecl()->getName()), candidates); } } else if (auto CRCE = dyn_cast(fnExpr)) { collectPossibleCalleesByQualifiedLookup( - DC, CRCE->getArg(), DeclNameRef::createConstructor(), candidates); + DC, CRCE->getBase(), DeclNameRef::createConstructor(), candidates); } else if (auto TE = dyn_cast(fnExpr)) { collectPossibleCalleesByQualifiedLookup( DC, TE, DeclNameRef::createConstructor(), candidates); @@ -730,49 +701,38 @@ static bool collectPossibleCalleesForSubscript( return !candidates.empty(); } -/// Get index of \p CCExpr in \p Args. \p Args is usually a \c TupleExpr -/// or \c ParenExpr. +/// Get index of \p CCExpr in \p Args. /// \returns \c true if success, \c false if \p CCExpr is not a part of \p Args. -static bool getPositionInArgs(DeclContext &DC, Expr *Args, Expr *CCExpr, +static bool getPositionInArgs(DeclContext &DC, ArgumentList *Args, Expr *CCExpr, unsigned &Position, bool &HasName) { - if (isa(Args)) { - HasName = false; - Position = 0; + auto &SM = DC.getASTContext().SourceMgr; + for (auto idx : indices(*Args)) { + auto arg = Args->get(idx); + if (SM.isBeforeInBuffer(arg.getExpr()->getEndLoc(), CCExpr->getStartLoc())) + continue; + HasName = arg.getLabelLoc().isValid(); + Position = idx; return true; } + return false; +} - auto *tuple = dyn_cast(Args); - if (!tuple) - return false; - +/// Get index of \p CCExpr in \p TE. +/// \returns \c true if success, \c false if \p CCExpr is not a part of \p Args. +static bool getPositionInTuple(DeclContext &DC, TupleExpr *TE, Expr *CCExpr, + unsigned &Position, bool &HasName) { auto &SM = DC.getASTContext().SourceMgr; - for (unsigned i = 0, n = tuple->getNumElements(); i != n; ++i) { - if (SM.isBeforeInBuffer(tuple->getElement(i)->getEndLoc(), + for (auto idx : indices(TE->getElements())) { + if (SM.isBeforeInBuffer(TE->getElement(idx)->getEndLoc(), CCExpr->getStartLoc())) continue; - HasName = tuple->getElementNameLoc(i).isValid(); - Position = i; + HasName = TE->getElementNameLoc(idx).isValid(); + Position = idx; return true; } return false; } -/// For function call arguments \p Args, return the argument at \p Position -/// computed by \c getPositionInArgs -static Expr *getArgAtPosition(Expr *Args, unsigned Position) { - if (isa(Args)) { - assert(Position == 0); - return Args; - } - - if (auto *tuple = dyn_cast(Args)) { - return tuple->getElement(Position); - } else { - llvm_unreachable("Unable to retrieve arg at position returned by " - "getPositionInArgs?"); - } -} - /// Get index of \p CCExpr in \p Params. Note that the position in \p Params may /// be different than the position in \p Args if there are defaulted arguments /// in \p Params which don't occur in \p Args. @@ -780,17 +740,8 @@ static Expr *getArgAtPosition(Expr *Args, unsigned Position) { /// \returns the position index number on success, \c None if \p CCExpr is not /// a part of \p Args. static Optional -getPositionInParams(DeclContext &DC, Expr *Args, Expr *CCExpr, +getPositionInParams(DeclContext &DC, const ArgumentList *Args, Expr *CCExpr, ArrayRef Params, bool Lenient) { - if (isa(Args)) { - return 0; - } - - auto *tuple = dyn_cast(Args); - if (!tuple) { - return None; - } - auto &SM = DC.getASTContext().SourceMgr; unsigned PosInParams = 0; unsigned PosInArgs = 0; @@ -800,11 +751,11 @@ getPositionInParams(DeclContext &DC, Expr *Args, Expr *CCExpr, // For each argument, we try to find a matching parameter either by matching // argument labels, in which case PosInParams may be advanced by more than 1, // or by advancing PosInParams and PosInArgs both by 1. - for (; PosInArgs < tuple->getNumElements(); ++PosInArgs) { - if (!SM.isBeforeInBuffer(tuple->getElement(PosInArgs)->getEndLoc(), + for (; PosInArgs < Args->size(); ++PosInArgs) { + if (!SM.isBeforeInBuffer(Args->getExpr(PosInArgs)->getEndLoc(), CCExpr->getStartLoc())) { // The arg is after the code completion position. Stop. - if (LastParamWasVariadic && tuple->getElementName(PosInArgs).empty()) { + if (LastParamWasVariadic && Args->getLabel(PosInArgs).empty()) { // If the last parameter was variadic and this argument stands by itself // without a label, assume that it belongs to the previous vararg // list. @@ -813,7 +764,7 @@ getPositionInParams(DeclContext &DC, Expr *Args, Expr *CCExpr, break; } - auto ArgName = tuple->getElementName(PosInArgs); + auto ArgName = Args->getLabel(PosInArgs); // If the last parameter we matched was variadic, we claim all following // unlabeled arguments for that variadic parameter -> advance PosInArgs but // not PosInParams. @@ -838,9 +789,7 @@ getPositionInParams(DeclContext &DC, Expr *Args, Expr *CCExpr, } } - bool IsTrailingClosure = - PosInArgs >= tuple->getNumElements() - tuple->getNumTrailingElements(); - if (!AdvancedPosInParams && IsTrailingClosure) { + if (!AdvancedPosInParams && Args->isTrailingClosureIndex(PosInArgs)) { // If the argument is a trailing closure, it can't match non-function // parameters. Advance to the next function parameter. for (unsigned i = PosInParams; i < Params.size(); ++i) { @@ -864,7 +813,7 @@ getPositionInParams(DeclContext &DC, Expr *Args, Expr *CCExpr, } } } - if (PosInArgs < tuple->getNumElements() && PosInParams < Params.size()) { + if (PosInArgs < Args->size() && PosInParams < Params.size()) { // We didn't search until the end, so we found a position in Params. Success return PosInParams; } else { @@ -902,15 +851,15 @@ class ExprContextAnalyzer { bool analyzeApplyExpr(Expr *E) { // Collect parameter lists for possible func decls. SmallVector Candidates; - Expr *Args = nullptr; + ArgumentList *Args = nullptr; if (auto *applyExpr = dyn_cast(E)) { if (!collectPossibleCalleesForApply(*DC, applyExpr, Candidates)) return false; - Args = applyExpr->getArg(); + Args = applyExpr->getArgs(); } else if (auto *subscriptExpr = dyn_cast(E)) { if (!collectPossibleCalleesForSubscript(*DC, subscriptExpr, Candidates)) return false; - Args = subscriptExpr->getIndex(); + Args = subscriptExpr->getArgs(); } else { llvm_unreachable("unexpected expression kind"); } @@ -944,8 +893,8 @@ class ExprContextAnalyzer { // // Varargs are represented by a VarargExpansionExpr that contains an // ArrayExpr on the call side. - if (auto Vararg = dyn_cast( - getArgAtPosition(Args, PositionInArgs))) { + if (auto Vararg = + dyn_cast(Args->getExpr(PositionInArgs))) { if (auto Array = dyn_cast_or_null(Vararg->getSubExpr())) { if (Array->getNumElements() > 0 && !isa(Array->getElement(0))) { @@ -962,9 +911,10 @@ class ExprContextAnalyzer { llvm::SmallVector, 2> posInParams; { bool found = false; + auto *originalArgs = Args->getOriginalArgs(); for (auto &typeAndDecl : Candidates) { Optional pos = getPositionInParams( - *DC, Args, ParsedExpr, typeAndDecl.Type->getParams(), + *DC, originalArgs, ParsedExpr, typeAndDecl.Type->getParams(), /*lenient=*/false); posInParams.push_back(pos); found |= pos.hasValue(); @@ -974,7 +924,7 @@ class ExprContextAnalyzer { // non-matching argument labels mis-typed. for (auto i : indices(Candidates)) { posInParams[i] = getPositionInParams( - *DC, Args, ParsedExpr, Candidates[i].Type->getParams(), + *DC, originalArgs, ParsedExpr, Candidates[i].Type->getParams(), /*lenient=*/true); } } @@ -1152,7 +1102,8 @@ class ExprContextAnalyzer { unsigned Position = 0; bool HasName; - if (getPositionInArgs(*DC, Parent, ParsedExpr, Position, HasName)) { + if (getPositionInTuple(*DC, cast(Parent), ParsedExpr, Position, + HasName)) { // The expected type may have fewer number of elements. if (Position < tupleT->getNumElements()) recordPossibleType(tupleT->getElementType(Position)); @@ -1361,14 +1312,14 @@ class ExprContextAnalyzer { // Iff the cursor is in argument position. auto call = cast(E); auto fnRange = call->getFn()->getSourceRange(); - auto argsRange = call->getArg()->getSourceRange(); + auto argsRange = call->getArgs()->getSourceRange(); auto exprRange = ParsedExpr->getSourceRange(); return !SM.rangeContains(fnRange, exprRange) && SM.rangeContains(argsRange, exprRange); } case ExprKind::Subscript: { // Iff the cursor is in index position. - auto argsRange = cast(E)->getIndex()->getSourceRange(); + auto argsRange = cast(E)->getArgs()->getSourceRange(); return SM.rangeContains(argsRange, ParsedExpr->getSourceRange()); } case ExprKind::Binary: diff --git a/lib/IDE/Formatting.cpp b/lib/IDE/Formatting.cpp index 5ac16c39173a4..35998e860d5eb 100644 --- a/lib/IDE/Formatting.cpp +++ b/lib/IDE/Formatting.cpp @@ -366,7 +366,7 @@ static Expr *getContextExprOf(SourceManager &SM, Expr *E) { if (auto *B = OBE->getSubExpr()) return getContextExprOf(SM, B); } else if (auto *PUE = dyn_cast(E)) { - if (auto *B = PUE->getArg()) + if (auto *B = PUE->getOperand()) return getContextExprOf(SM, B); } return E; @@ -387,7 +387,7 @@ static Expr *getContextExprOf(SourceManager &SM, Expr *E) { /// .count /// \endcode static SourceLoc getContextLocForArgs(SourceManager &SM, Expr *E) { - assert(isa(E) || isa(E) || isa(E)); + assert(E->getArgs() || isa(E)); Expr *Base = getContextExprOf(SM, E); if (auto *UDE = dyn_cast(Base)) return UDE->getDotLoc(); @@ -467,8 +467,8 @@ class RangeWalker: protected ASTWalker { if (!Repr->walk(*this)) return false; } - if (auto *Arg = customAttr->getArg()) { - if (!Arg->walk(*this)) + if (auto *Args = customAttr->getArgs()) { + if (!Args->walk(*this)) return false; } } @@ -646,38 +646,28 @@ class RangeWalker: protected ASTWalker { return Stop; } else if (isa(E) || isa(E)) { SourceLoc ContextLoc = getContextLocForArgs(SM, E); - Expr *Arg; - if (auto *CE = dyn_cast(E)) { - Arg = CE->getArg(); + auto *Args = E->getArgs(); + + auto lParenLoc = Args->getLParenLoc(); + auto rParenLoc = Args->getRParenLoc(); + + if (isa(E)) { + if (!handleSquares(lParenLoc, rParenLoc, ContextLoc)) + return Stop; } else { - Arg = cast(E)->getIndex(); + if (!handleParens(lParenLoc, rParenLoc, ContextLoc)) + return Stop; } - if (auto *PE = dyn_cast_or_null(Arg)) { - if (isa(E)) { - if (!handleSquares(PE->getLParenLoc(), PE->getRParenLoc(), ContextLoc)) - return Stop; - } else { - if (!handleParens(PE->getLParenLoc(), PE->getRParenLoc(), ContextLoc)) - return Stop; - } - if (PE->hasTrailingClosure()) { - if (auto CE = findTrailingClosureFromArgument(PE->getSubExpr())) + if (Args->hasAnyTrailingClosures()) { + if (auto *unaryArg = Args->getUnaryExpr()) { + if (auto CE = findTrailingClosureFromArgument(unaryArg)) { if (!handleBraceStmt(CE->getBody(), ContextLoc)) return Stop; - } - } else if (auto *TE = dyn_cast_or_null(Arg)) { - if (isa(E)) { - if (!handleSquares(TE->getLParenLoc(), TE->getRParenLoc(), ContextLoc)) - return Stop; + } } else { - if (!handleParens(TE->getLParenLoc(), TE->getRParenLoc(), ContextLoc)) - return Stop; - } - if (TE->hasAnyTrailingClosures()) { - SourceRange Range(TE->getTrailingElements().front()->getStartLoc(), - TE->getEndLoc()); - handleImplicitRange(Range, ContextLoc); + handleImplicitRange(Args->getOriginalArgs()->getTrailingSourceRange(), + ContextLoc); } } } @@ -1364,8 +1354,8 @@ class FormatWalker : public ASTWalker { if (!Repr->walk(*this)) return false; } - if (auto *Arg = customAttr->getArg()) { - if (!Arg->walk(*this)) + if (auto *Args = customAttr->getArgs()) { + if (!Args->walk(*this)) return false; } } @@ -1429,6 +1419,25 @@ class FormatWalker : public ASTWalker { return {Action.shouldVisitChildren(), S}; } + std::pair + walkToArgumentListPre(ArgumentList *Args) override { + SourceLoc ContextLoc; + if (auto *E = Parent.getAsExpr()) { + // Retrieve the context loc from the parent call. Note that we don't + // perform this if we're walking the ArgumentList directly for e.g an + // interpolated string literal. + if (E->getArgs() == Args) + ContextLoc = getContextLocForArgs(SM, E); + } + + auto Action = HandlePre(Args, Args->isImplicit()); + if (Action.shouldGenerateIndentContext()) { + if (auto Ctx = getIndentContextFrom(Args, Action.Trailing, ContextLoc)) + InnermostCtx = Ctx; + } + return {Action.shouldVisitChildren(), Args}; + } + std::pair walkToExprPre(Expr *E) override { if (E->getKind() == ExprKind::StringLiteral && SM.isBeforeInBuffer(E->getStartLoc(), TargetLocation) && @@ -1463,20 +1472,18 @@ class FormatWalker : public ASTWalker { SourceLoc PrevStringStart = ISL->getStartLoc(); ISL->forEachSegment(SF.getASTContext(), [&](bool IsInterpolation, CallExpr *CE) { - if (auto *Arg = CE->getArg()) { - if (IsInterpolation) { - // Handle the preceeding string segment. - CharSourceRange StringRange(SM, PrevStringStart, CE->getStartLoc()); - if (StringRange.contains(TargetLocation)) { - StringLiteralRange = - Lexer::getCharSourceRangeFromSourceRange(SM, E->getSourceRange()); - return; - } - // Walk into the interpolation segment. - Arg->walk(*this); - } else { - PrevStringStart = CE->getStartLoc(); + if (IsInterpolation) { + // Handle the preceeding string segment. + CharSourceRange StringRange(SM, PrevStringStart, CE->getStartLoc()); + if (StringRange.contains(TargetLocation)) { + StringLiteralRange = + Lexer::getCharSourceRangeFromSourceRange(SM, E->getSourceRange()); + return; } + // Walk into the interpolation segment. + CE->getArgs()->walk(*this); + } else { + PrevStringStart = CE->getStartLoc(); } }); // Handle the trailing string segment. @@ -2410,17 +2417,11 @@ class FormatWalker : public ASTWalker { // All handled expressions may claim a trailing target. - if (auto *TE = dyn_cast(E)) { - if (TrailingTarget && TE->hasTrailingClosure()) - return None; + if (auto *TE = dyn_cast(E)) return getIndentContextFrom(TE); - } - if (auto *PE = dyn_cast(E)) { - if (TrailingTarget && PE->hasTrailingClosure()) - return None; + if (auto *PE = dyn_cast(E)) return getIndentContextFrom(PE); - } if (auto *DE = dyn_cast(E)) { SourceLoc L = DE->getLBracketLoc(); @@ -2481,60 +2482,6 @@ class FormatWalker : public ASTWalker { if (auto *CE = dyn_cast(E)) return getIndentContextFrom(CE); - if (isa(E) || isa(E)) { - SourceLoc ContextLoc = getContextLocForArgs(SM, E); - Expr *Arg; - if (auto *CE = dyn_cast(E)) { - Arg = CE->getArg(); - } else { - Arg = cast(E)->getIndex(); - } - - auto getIndentContextFromTrailingClosure = - [&](Expr *arg) -> Optional { - if (auto CE = findTrailingClosureFromArgument(arg)) { - SourceRange Range = CE->getSourceRange(); - if (Range.isValid() && (TrailingTarget || overlapsTarget(Range))) { - if (auto CLE = dyn_cast(arg)) - return getIndentContextFrom(CLE, ContextLoc); - return getIndentContextFrom(CE, ContextLoc); - } - } - return None; - }; - - if (auto *PE = dyn_cast_or_null(Arg)) { - if (auto Ctx = getIndentContextFrom(PE, ContextLoc)) - return Ctx; - if (PE->hasTrailingClosure()) { - if (auto Ctx = getIndentContextFromTrailingClosure(PE->getSubExpr())) - return Ctx; - } - } else if (auto *TE = dyn_cast_or_null(Arg)) { - if (auto Ctx = getIndentContextFrom(TE, ContextLoc)) - return Ctx; - - if (TE->hasAnyTrailingClosures()) { - Expr *Unlabeled = TE->getTrailingElements().front(); - SourceRange ClosuresRange(Unlabeled->getStartLoc(), TE->getEndLoc()); - - if (overlapsTarget(ClosuresRange) || TrailingTarget) { - SourceRange ContextToEnd(ContextLoc, ClosuresRange.End); - ContextLoc = CtxOverride.propagateContext(SM, ContextLoc, - IndentContext::LineStart, - ClosuresRange.Start, - SourceLoc()); - if (!TrailingTarget) { - return IndentContext { - ContextLoc, - !OutdentChecker::hasOutdent(SM, ContextToEnd, E) - }; - } - } - } - } - } - return None; } @@ -2671,7 +2618,7 @@ class FormatWalker : public ASTWalker { } ListAligner Aligner(SM, TargetLocation, ContextLoc, L, R); - auto NumElems = TE->getNumElements() - TE->getNumTrailingElements(); + auto NumElems = TE->getNumElements(); for (auto I : range(NumElems)) { SourceRange ElemRange = TE->getElementNameLoc(I); if (Expr *Elem = TE->getElement(I)) @@ -2709,17 +2656,92 @@ class FormatWalker : public ASTWalker { } ListAligner Aligner(SM, TargetLocation, ContextLoc, L, R); - if (!PE->hasTrailingClosure()) { - Expr *Elem = PE->getSubExpr(); - SourceRange Range = Elem->getSourceRange(); - Aligner.updateAlignment(Range, Elem); + Expr *Elem = PE->getSubExpr(); + SourceRange Range = Elem->getSourceRange(); + Aligner.updateAlignment(Range, Elem); + + if (isTargetContext(Range)) { + Aligner.setAlignmentIfNeeded(CtxOverride); + return IndentContext { + Range.Start, + !OutdentChecker::hasOutdent(SM, Elem) + }; + } + return Aligner.getContextAndSetAlignment(CtxOverride); + } + + Optional + getIndentContextFromTrailingClosure(ArgumentList *Args, + Optional TrailingTarget, + SourceLoc ContextLoc) { + if (!Args->hasAnyTrailingClosures()) + return None; + + if (auto *arg = Args->getUnaryExpr()) { + auto *CE = findTrailingClosureFromArgument(arg); + if (!CE) + return None; + + auto Range = CE->getSourceRange(); + if (Range.isInvalid() || (!TrailingTarget && !overlapsTarget(Range))) + return None; + + if (auto *CLE = dyn_cast(arg)) + return getIndentContextFrom(CLE, ContextLoc); + + return getIndentContextFrom(CE, ContextLoc); + } + auto ClosuresRange = Args->getOriginalArgs()->getTrailingSourceRange(); + if (!overlapsTarget(ClosuresRange) && !TrailingTarget) + return None; + + SourceRange ContextToEnd(ContextLoc, ClosuresRange.End); + ContextLoc = + CtxOverride.propagateContext(SM, ContextLoc, IndentContext::LineStart, + ClosuresRange.Start, SourceLoc()); + if (TrailingTarget) + return None; + + auto *ParentE = Parent.getAsExpr(); + assert(ParentE && "Trailing closures can only occur in expr contexts"); + return IndentContext{ + ContextLoc, !OutdentChecker::hasOutdent(SM, ContextToEnd, ParentE)}; + } + + Optional + getIndentContextFrom(ArgumentList *Args, + Optional TrailingTarget, + SourceLoc ContextLoc = SourceLoc()) { + if (ContextLoc.isValid()) + NodesToSkip.insert(static_cast(Args)); + SourceLoc L = Args->getLParenLoc(); + SourceLoc R = getLocIfKind(SM, Args->getRParenLoc(), + {tok::r_paren, tok::r_square}); + if (L.isInvalid() || !overlapsTarget(L, R)) { + return getIndentContextFromTrailingClosure(Args, TrailingTarget, + ContextLoc); + } + + if (ContextLoc.isValid()) { + ContextLoc = CtxOverride.propagateContext(SM, ContextLoc, + IndentContext::LineStart, L, R); + } else { + ContextLoc = L; + } + + ListAligner Aligner(SM, TargetLocation, ContextLoc, L, R); + for (auto Arg : Args->getOriginalArgs()->getNonTrailingArgs()) { + SourceRange ElemRange = Arg.getLabelLoc(); + auto *Elem = Arg.getExpr(); + assert(Elem); + widenOrSet(ElemRange, Elem->getSourceRange()); + assert(ElemRange.isValid()); - if (isTargetContext(Range)) { + Aligner.updateAlignment(ElemRange, Args); + if (isTargetContext(ElemRange)) { Aligner.setAlignmentIfNeeded(CtxOverride); - return IndentContext { - Range.Start, - !OutdentChecker::hasOutdent(SM, Elem) - }; + return IndentContext{ElemRange.Start, + !OutdentChecker::hasOutdent(SM, ElemRange, Args)}; } } return Aligner.getContextAndSetAlignment(CtxOverride); diff --git a/lib/IDE/Refactoring.cpp b/lib/IDE/Refactoring.cpp index c2681580488c1..0dc634d62b357 100644 --- a/lib/IDE/Refactoring.cpp +++ b/lib/IDE/Refactoring.cpp @@ -3709,24 +3709,12 @@ static CallExpr *findTrailingClosureTarget( return nullptr; CallExpr *CE = cast(contexts.back().get()); - if (CE->getUnlabeledTrailingClosureIndex().hasValue()) - // Call expression already has a trailing closure. + // The last argument is a non-trailing closure? + auto *Args = CE->getArgs(); + if (Args->empty() || Args->hasAnyTrailingClosures()) return nullptr; - // The last argument is a closure? - Expr *Args = CE->getArg(); - if (!Args) - return nullptr; - Expr *LastArg; - if (auto *PE = dyn_cast(Args)) { - LastArg = PE->getSubExpr(); - } else { - auto *TE = cast(Args); - if (TE->getNumElements() == 0) - return nullptr; - LastArg = TE->getElements().back(); - } - + auto *LastArg = Args->back().getExpr(); if (auto *ICE = dyn_cast(LastArg)) LastArg = ICE->getSyntacticSubExpr(); @@ -3745,45 +3733,41 @@ bool RefactoringActionTrailingClosure::performChange() { auto *CE = findTrailingClosureTarget(SM, CursorInfo); if (!CE) return true; - Expr *Arg = CE->getArg(); - Expr *ClosureArg = nullptr; - Expr *PrevArg = nullptr; + auto *ArgList = CE->getArgs()->getOriginalArgs(); + auto LParenLoc = ArgList->getLParenLoc(); + auto RParenLoc = ArgList->getRParenLoc(); - OriginalArgumentList ArgList = getOriginalArgumentList(Arg); + if (LParenLoc.isInvalid() || RParenLoc.isInvalid()) + return true; - auto NumArgs = ArgList.args.size(); + auto NumArgs = ArgList->size(); if (NumArgs == 0) return true; - ClosureArg = ArgList.args[NumArgs - 1]; - if (NumArgs > 1) - PrevArg = ArgList.args[NumArgs - 2]; + auto *ClosureArg = ArgList->getExpr(NumArgs - 1); if (auto *ICE = dyn_cast(ClosureArg)) ClosureArg = ICE->getSyntacticSubExpr(); - if (ArgList.lParenLoc.isInvalid() || ArgList.rParenLoc.isInvalid()) - return true; - // Replace: // * Open paren with ' ' if the closure is sole argument. // * Comma with ') ' otherwise. - if (PrevArg) { + if (NumArgs > 1) { + auto *PrevArg = ArgList->getExpr(NumArgs - 2); CharSourceRange PreRange( SM, Lexer::getLocForEndOfToken(SM, PrevArg->getEndLoc()), ClosureArg->getStartLoc()); EditConsumer.accept(SM, PreRange, ") "); } else { - CharSourceRange PreRange( - SM, ArgList.lParenLoc, ClosureArg->getStartLoc()); + CharSourceRange PreRange(SM, LParenLoc, ClosureArg->getStartLoc()); EditConsumer.accept(SM, PreRange, " "); } // Remove original closing paren. CharSourceRange PostRange( SM, Lexer::getLocForEndOfToken(SM, ClosureArg->getEndLoc()), - Lexer::getLocForEndOfToken(SM, ArgList.rParenLoc)); + Lexer::getLocForEndOfToken(SM, RParenLoc)); EditConsumer.remove(SM, PostRange); return false; } @@ -3912,40 +3896,6 @@ Decl *singleSwitchSubject(const SwitchStmt *Switch) { return nullptr; } -// Wrapper to make dealing with single elements easier (ie. for Paren|TupleExpr -// arguments) -template -class PtrArrayRef { - bool IsSingle = false; - union Storage { - ArrayRef ManyElements; - T SingleElement; - } Storage = {ArrayRef()}; - -public: - PtrArrayRef() {} - PtrArrayRef(T Element) : IsSingle(true) { Storage.SingleElement = Element; } - PtrArrayRef(ArrayRef Ref) : IsSingle(Ref.size() == 1), Storage({Ref}) { - if (IsSingle) - Storage.SingleElement = Ref[0]; - } - - ArrayRef ref() { - if (IsSingle) - return ArrayRef(Storage.SingleElement); - return Storage.ManyElements; - } -}; - -PtrArrayRef callArgs(const ApplyExpr *AE) { - if (auto *PE = dyn_cast(AE->getArg())) { - return PtrArrayRef(PE->getSubExpr()); - } else if (auto *TE = dyn_cast(AE->getArg())) { - return PtrArrayRef(TE->getElements()); - } - return PtrArrayRef(); -} - /// A more aggressive variant of \c Expr::getReferencedDecl that also looks /// through autoclosures created to pass the \c self parameter to a member funcs ValueDecl *getReferencedDecl(const Expr *Fn) { @@ -4048,21 +3998,22 @@ FuncDecl *isOperator(const BinaryExpr *BE) { /// completion(nil, MyError.Bad) // Result = [MyError.Bad], IsError = true /// } class HandlerResult { - PtrArrayRef Results; + SmallVector Args; bool IsError = false; public: HandlerResult() {} - HandlerResult(ArrayRef Results) - : Results(PtrArrayRef(Results)) {} + HandlerResult(ArrayRef ArgsRef) + : Args(ArgsRef.begin(), ArgsRef.end()) {} - HandlerResult(Expr *Result, bool IsError) - : Results(PtrArrayRef(Result)), IsError(IsError) {} + HandlerResult(Argument Arg, bool IsError) : IsError(IsError) { + Args.push_back(Arg); + } bool isError() { return IsError; } - ArrayRef args() { return Results.ref(); } + ArrayRef args() { return Args; } }; /// The type of the handler, ie. whether it takes regular parameters or a @@ -4269,7 +4220,7 @@ struct AsyncHandlerDesc { // Only param handlers with an error can pass both an error AND a result. return false; } - auto Args = callArgs(CE).ref(); + auto Args = CE->getArgs()->getArgExprs(); if (!isa(Args.back())) { // We've got an error parameter. If any of the success params is not nil, // the call is ambiguous. @@ -4290,8 +4241,9 @@ struct AsyncHandlerDesc { /// determines whether the success or error parameters are passed. HandlerResult extractResultArgs(const CallExpr *CE, bool ReturnErrorArgsIfAmbiguous) const { - auto ArgList = callArgs(CE); - auto Args = ArgList.ref(); + auto *ArgList = CE->getArgs(); + SmallVector Scratch(ArgList->begin(), ArgList->end()); + auto Args = llvm::makeArrayRef(Scratch); if (Type == HandlerType::PARAMS) { bool IsErrorResult; @@ -4300,7 +4252,8 @@ struct AsyncHandlerDesc { } else { // If there's an error parameter and the user isn't passing nil to it, // assume this is the error path. - IsErrorResult = (HasError && !isa(Args.back())); + IsErrorResult = + (HasError && !isa(Args.back().getExpr())); } if (IsErrorResult) return HandlerResult(Args.back(), true); @@ -4314,7 +4267,7 @@ struct AsyncHandlerDesc { if (Args.size() != 1) return HandlerResult(Args); - auto *ResultCE = dyn_cast(Args[0]); + auto *ResultCE = dyn_cast(Args[0].getExpr()); if (!ResultCE) return HandlerResult(Args); @@ -4327,7 +4280,7 @@ struct AsyncHandlerDesc { if (!D) return HandlerResult(Args); - auto ResultArgList = callArgs(ResultCE); + auto ResultArgList = ResultCE->getArgs(); auto isFailure = D->getNameStr() == StringRef("failure"); // We can drop the arg altogether if it's just Void. @@ -4335,7 +4288,7 @@ struct AsyncHandlerDesc { return HandlerResult(); // Otherwise the arg gets the .success() or .failure() call dropped. - return HandlerResult(ResultArgList.ref()[0], isFailure); + return HandlerResult(ResultArgList->get(0), isFailure); } llvm_unreachable("Unhandled result type"); @@ -4606,7 +4559,7 @@ struct CallbackCondition { auto *Callee = PrefixOp->getCalledValue(); if (Callee && Callee->isOperator() && Callee->getBaseName() == "!") { CondType = ConditionType::IS_FALSE; - E = PrefixOp->getArg()->getSemanticsProvidingExpr(); + E = PrefixOp->getOperand()->getSemanticsProvidingExpr(); } } @@ -6704,7 +6657,7 @@ class AsyncConverter : private SourceEntityWalker { // declaration doesn't exist anymore, which is the case if it's in // Placeholders but not in Unwraps (if it's in Placeholders and Unwraps // an optional Error has simply been promoted to a non-optional Error). - if (auto DRE = dyn_cast(Result.args().back())) { + if (auto *DRE = dyn_cast(Result.args().back().getExpr())) { if (Placeholders.count(DRE->getDecl()) && !Unwraps.count(DRE->getDecl())) { return true; @@ -6767,7 +6720,7 @@ class AsyncConverter : private SourceEntityWalker { "retrieved its error representation"); assert(Result.args().size() == 1 && "There should only be one error parameter"); - Expr *ErrorExpr = Result.args().back(); + Expr *ErrorExpr = Result.args().back().getExpr(); if (isErrorAlreadyHandled(Result)) { // The error has already been handled, interpret the call as a success // call. @@ -6839,12 +6792,12 @@ class AsyncConverter : private SourceEntityWalker { OS << tok::kw_throw; } - ArrayRef Args = Result.args(); + auto Args = Result.args(); if (!Args.empty()) { if (AddedReturnOrThrow) OS << ' '; - unsigned I = 0; - addTupleOf(Args, OS, [&](Expr *Elt) { + + addTupleOf(Args, OS, [&](Argument Arg) { // Special case: If the completion handler is a params handler that // takes an error, we could pass arguments to it without unwrapping // them. E.g. @@ -6864,20 +6817,20 @@ class AsyncConverter : private SourceEntityWalker { // which correctly yields // return res // Synthesize the force unwrap so that we get the expected results. + auto *E = Arg.getExpr(); if (TopHandler.getHandlerType() == HandlerType::PARAMS && TopHandler.HasError) { if (auto DRE = - dyn_cast(Elt->getSemanticsProvidingExpr())) { + dyn_cast(E->getSemanticsProvidingExpr())) { auto D = DRE->getDecl(); if (Unwraps.count(D)) { - Elt = new (getASTContext()) ForceValueExpr(Elt, SourceLoc()); + E = new (getASTContext()) ForceValueExpr(E, SourceLoc()); } } } // Can't just add the range as we need to perform replacements - convertNode(Elt, /*StartOverride=*/CE->getArgumentLabelLoc(I), + convertNode(E, /*StartOverride=*/Arg.getLabelLoc(), /*ConvertCalls=*/false); - I++; }); } } @@ -6906,7 +6859,7 @@ class AsyncConverter : private SourceEntityWalker { HandlerResult Result) { assert(Scopes.back().isWrappedInContination()); - std::vector Args; + std::vector Args; StringRef ResumeArgumentLabel; switch (TopHandler.getHandlerType()) { case HandlerType::PARAMS: { @@ -6919,7 +6872,7 @@ class AsyncConverter : private SourceEntityWalker { break; } case HandlerType::RESULT: { - Args = callArgs(CE).ref(); + Args = {CE->getArgs()->begin(), CE->getArgs()->end()}; ResumeArgumentLabel = "with"; break; } @@ -6960,9 +6913,10 @@ class AsyncConverter : private SourceEntityWalker { unsigned ArgIndex = 0; for (auto Arg : Args) { + auto *ArgExpr = Arg.getExpr(); Identifier ArgName; - if (isExpressionOptional(Arg) && TopHandler.HasError) { - ArgName = GetSuitableNameForGuardUnwrap(Arg, ArgIndex); + if (isExpressionOptional(ArgExpr) && TopHandler.HasError) { + ArgName = GetSuitableNameForGuardUnwrap(ArgExpr, ArgIndex); Scopes.back().Names.insert(ArgName); OS << tok::kw_guard << ' ' << tok::kw_let << ' ' << ArgName << ' ' << tok::equal << ' '; @@ -6972,15 +6926,15 @@ class AsyncConverter : private SourceEntityWalker { // e.g. 'guard let result1 = value.map { $0 + 1 } else { ... }' // doesn't compile. Adding parentheses makes the code compile. auto HasTrailingClosure = false; - if (auto *CE = dyn_cast(Arg)) { - if (CE->getUnlabeledTrailingClosureIndex().hasValue()) + if (auto *CE = dyn_cast(ArgExpr)) { + if (CE->getArgs()->hasAnyTrailingClosures()) HasTrailingClosure = true; } if (HasTrailingClosure) OS << tok::l_paren; - convertNode(Arg, /*StartOverride=*/CE->getArgumentLabelLoc(ArgIndex), + convertNode(ArgExpr, /*StartOverride=*/Arg.getLabelLoc(), /*ConvertCalls=*/false); if (HasTrailingClosure) @@ -7005,13 +6959,13 @@ class AsyncConverter : private SourceEntityWalker { << ResumeArgumentLabel << tok::colon << ' '; ArgIndex = 0; - addTupleOf(Args, OS, [&](Expr *Elt) { + addTupleOf(Args, OS, [&](Argument Arg) { Identifier ArgName = ArgNames[ArgIndex]; if (!ArgName.empty()) { OS << ArgName; } else { // Can't just add the range as we need to perform replacements - convertNode(Elt, /*StartOverride=*/CE->getArgumentLabelLoc(ArgIndex), + convertNode(Arg.getExpr(), /*StartOverride=*/Arg.getLabelLoc(), /*ConvertCalls=*/false); } ArgIndex++; @@ -7048,17 +7002,17 @@ class AsyncConverter : private SourceEntityWalker { const AsyncHandlerParamDesc &HandlerDesc) { llvm::SaveAndRestore RestoreHoisting(Hoisting, true); - auto ArgList = callArgs(CE); - if (HandlerDesc.Index >= ArgList.ref().size()) { + auto *ArgList = CE->getArgs(); + if (HandlerDesc.Index >= ArgList->size()) { DiagEngine.diagnose(CE->getStartLoc(), diag::missing_callback_arg); return; } Expr *CallbackArg = - lookThroughFunctionConversionExpr(ArgList.ref()[HandlerDesc.Index]); + lookThroughFunctionConversionExpr(ArgList->getExpr(HandlerDesc.Index)); if (ClosureExpr *Callback = extractCallback(CallbackArg)) { // The user is using a closure for the completion handler - addHoistedClosureCallback(CE, HandlerDesc, Callback, ArgList); + addHoistedClosureCallback(CE, HandlerDesc, Callback); return; } if (auto CallbackDecl = getReferencedDecl(CallbackArg)) { @@ -7072,8 +7026,8 @@ class AsyncConverter : private SourceEntityWalker { OS << tok::kw_return << " "; } InlinePatternsToPrint InlinePatterns; - addAwaitCall(CE, ArgList.ref(), ClassifiedBlock(), {}, InlinePatterns, - HandlerDesc, /*AddDeclarations*/ false); + addAwaitCall(CE, ClassifiedBlock(), {}, InlinePatterns, HandlerDesc, + /*AddDeclarations*/ false); return; } // We are not removing the completion handler, so we can call it once the @@ -7090,9 +7044,8 @@ class AsyncConverter : private SourceEntityWalker { addHoistedNamedCallback( CalledFunc, CompletionHandler, HandlerName, [&] { InlinePatternsToPrint InlinePatterns; - addAwaitCall(CE, ArgList.ref(), ClassifiedBlock(), {}, - InlinePatterns, HandlerDesc, - /*AddDeclarations*/ false); + addAwaitCall(CE, ClassifiedBlock(), {}, InlinePatterns, + HandlerDesc, /*AddDeclarations*/ false); }); return; } @@ -7107,8 +7060,7 @@ class AsyncConverter : private SourceEntityWalker { /// are the arguments being passed in \p CE. void addHoistedClosureCallback(const CallExpr *CE, const AsyncHandlerParamDesc &HandlerDesc, - const ClosureExpr *Callback, - PtrArrayRef ArgList) { + const ClosureExpr *Callback) { ArrayRef CallbackParams = Callback->getParameters()->getArray(); auto CallbackBody = Callback->getBody(); @@ -7163,8 +7115,8 @@ class AsyncConverter : private SourceEntityWalker { addFallbackVars(CallbackParams, Blocks); addDo(); - addAwaitCall(CE, ArgList.ref(), Blocks.SuccessBlock, SuccessParams, - InlinePatterns, HandlerDesc, /*AddDeclarations*/ false); + addAwaitCall(CE, Blocks.SuccessBlock, SuccessParams, InlinePatterns, + HandlerDesc, /*AddDeclarations*/ false); addFallbackCatch(ErrParam); OS << "\n"; convertNodes(NodesToPrint::inBraceStmt(CallbackBody)); @@ -7183,7 +7135,8 @@ class AsyncConverter : private SourceEntityWalker { HandlerCall, /*ReturnErrorArgsIfAmbiguous=*/true); if (Res.args().size() == 1) { // Skip if we have the param itself or the name it's bound to - auto *SingleDecl = Res.args()[0]->getReferencedDecl().getDecl(); + auto *ArgExpr = Res.args()[0].getExpr(); + auto *SingleDecl = ArgExpr->getReferencedDecl().getDecl(); auto ErrName = Blocks.ErrorBlock.boundName(ErrParam); RequireDo = SingleDecl != ErrParam && !(Res.isError() && SingleDecl && @@ -7213,8 +7166,8 @@ class AsyncConverter : private SourceEntityWalker { preparePlaceholdersAndUnwraps(HandlerDesc, SuccessParams, ErrParam, /*Success=*/true); - addAwaitCall(CE, ArgList.ref(), Blocks.SuccessBlock, SuccessParams, - InlinePatterns, HandlerDesc, /*AddDeclarations=*/true); + addAwaitCall(CE, Blocks.SuccessBlock, SuccessParams, InlinePatterns, + HandlerDesc, /*AddDeclarations=*/true); printOutOfLineBindingPatterns(Blocks.SuccessBlock, InlinePatterns); convertNodes(Blocks.SuccessBlock.nodesToPrint()); clearNames(SuccessParams); @@ -7367,7 +7320,6 @@ class AsyncConverter : private SourceEntityWalker { /// into variables. /// /// \param CE The call expr to convert. - /// \param Args The arguments of the call expr. /// \param SuccessBlock The nodes present in the success block following the /// call. /// \param SuccessParams The success parameters, which will be printed as @@ -7377,12 +7329,13 @@ class AsyncConverter : private SourceEntityWalker { /// \param HandlerDesc A description of the completion handler. /// \param AddDeclarations Whether or not to add \c let or \c var keywords to /// the return value bindings. - void addAwaitCall(const CallExpr *CE, ArrayRef Args, - const ClassifiedBlock &SuccessBlock, + void addAwaitCall(const CallExpr *CE, const ClassifiedBlock &SuccessBlock, ArrayRef SuccessParams, const InlinePatternsToPrint &InlinePatterns, const AsyncHandlerParamDesc &HandlerDesc, bool AddDeclarations) { + auto *Args = CE->getArgs(); + // Print the bindings to match the completion handler success parameters, // making sure to omit in the case of a Void return. if (!SuccessParams.empty() && !HandlerDesc.willAsyncReturnVoid()) { @@ -7454,9 +7407,11 @@ class AsyncConverter : private SourceEntityWalker { ArrayRef AlternativeParams; if (HandlerDesc.Alternative) AlternativeParams = HandlerDesc.Alternative->getParameters()->getArray(); - ArrayRef ArgLabels = CE->getArgumentLabels(); - for (size_t I = 0, E = Args.size(); I < E; ++I) { - if (I == HandlerDesc.Index || isa(Args[I])) + + for (auto I : indices(*Args)) { + auto Arg = Args->get(I); + auto *ArgExpr = Arg.getExpr(); + if (I == HandlerDesc.Index || isa(ArgExpr)) continue; if (ConvertedArgIndex > 0) @@ -7467,7 +7422,7 @@ class AsyncConverter : private SourceEntityWalker { while (ConvertedArgIndex < AlternativeParams.size() && AlternativeParams[ConvertedArgIndex]->isDefaultArgument() && AlternativeParams[ConvertedArgIndex]->getArgumentName() != - ArgLabels[I]) { + Arg.getLabel()) { ConvertedArgIndex++; } @@ -7476,7 +7431,7 @@ class AsyncConverter : private SourceEntityWalker { auto Name = AlternativeParams[ConvertedArgIndex]->getArgumentName(); if (!Name.empty()) OS << Name << ": "; - convertNode(Args[I], /*StartOverride=*/{}, /*ConvertCalls=*/false); + convertNode(ArgExpr, /*StartOverride=*/{}, /*ConvertCalls=*/false); ConvertedArgIndex++; continue; @@ -7487,7 +7442,7 @@ class AsyncConverter : private SourceEntityWalker { // Can't just add the range as we need to perform replacements. Also // make sure to include the argument label (if any) - convertNode(Args[I], /*StartOverride=*/CE->getArgumentLabelLoc(I), + convertNode(ArgExpr, /*StartOverride=*/Arg.getLabelLoc(), /*ConvertCalls=*/false); ConvertedArgIndex++; } diff --git a/lib/IDE/SourceEntityWalker.cpp b/lib/IDE/SourceEntityWalker.cpp index 56a1781b72650..6f01f79263ab8 100644 --- a/lib/IDE/SourceEntityWalker.cpp +++ b/lib/IDE/SourceEntityWalker.cpp @@ -65,6 +65,9 @@ class SemaAnnotator : public ASTWalker { std::pair walkToStmtPre(Stmt *S) override; Stmt *walkToStmtPost(Stmt *S) override; + std::pair + walkToArgumentListPre(ArgumentList *ArgList) override; + std::pair walkToPatternPre(Pattern *P) override; Pattern *walkToPatternPost(Pattern *P) override; @@ -83,7 +86,7 @@ class SemaAnnotator : public ASTWalker { bool passCallAsFunctionReference(ValueDecl *D, SourceLoc Loc, ReferenceMetaData Data); - bool passCallArgNames(Expr *Fn, TupleExpr *TupleE); + bool passCallArgNames(Expr *Fn, ArgumentList *ArgList); bool shouldIgnore(Decl *D); @@ -262,6 +265,25 @@ static SemaReferenceKind getReferenceKind(Expr *Parent, Expr *E) { return SemaReferenceKind::DeclRef; } +std::pair +SemaAnnotator::walkToArgumentListPre(ArgumentList *ArgList) { + auto doStopTraversal = [&]() -> std::pair { + Cancelled = true; + return {false, nullptr}; + }; + + // Don't consider the argument labels for an implicit ArgumentList. + if (ArgList->isImplicit()) + return {true, ArgList}; + + // FIXME: What about SubscriptExpr and KeyPathExpr arg labels? (SR-15063) + if (auto CallE = dyn_cast_or_null(Parent.getAsExpr())) { + if (!passCallArgNames(CallE->getFn(), ArgList)) + return doStopTraversal(); + } + return {true, ArgList}; +} + std::pair SemaAnnotator::walkToExprPre(Expr *E) { assert(E); @@ -396,7 +418,7 @@ std::pair SemaAnnotator::walkToExprPre(Expr *E) { return doStopTraversal(); } - if (!SE->getIndex()->walk(*this)) + if (!SE->getArgs()->walk(*this)) return doStopTraversal(); if (SubscrD) { @@ -448,12 +470,6 @@ std::pair SemaAnnotator::walkToExprPre(Expr *E) { // We already visited the children. return doSkipChildren(); - - } else if (auto TupleE = dyn_cast(E)) { - if (auto CallE = dyn_cast_or_null(Parent.getAsExpr())) { - if (!passCallArgNames(CallE->getFn(), TupleE)) - return doStopTraversal(); - } } else if (auto IOE = dyn_cast(E)) { llvm::SaveAndRestore> C(this->OpAccess, AccessKind::ReadWrite); @@ -642,15 +658,15 @@ bool SemaAnnotator::handleCustomAttributes(Decl *D) { } if (auto *SemaInit = customAttr->getSemanticInit()) { if (!SemaInit->isImplicit()) { - assert(customAttr->getArg()); + assert(customAttr->hasArgs()); if (!SemaInit->walk(*this)) return false; // Don't walk this again via the associated PatternBindingDecl's // initializer ExprsToSkip.insert(SemaInit); } - } else if (auto *Arg = customAttr->getArg()) { - if (!Arg->walk(*this)) + } else if (auto *Args = customAttr->getArgs()) { + if (!Args->walk(*this)) return false; } } @@ -784,19 +800,17 @@ bool SemaAnnotator::passReference(ModuleEntity Mod, return Continue; } -bool SemaAnnotator::passCallArgNames(Expr *Fn, TupleExpr *TupleE) { +bool SemaAnnotator::passCallArgNames(Expr *Fn, ArgumentList *ArgList) { ValueDecl *D = extractDecl(Fn); if (!D) return true; // continue. - ArrayRef ArgNames = TupleE->getElementNames(); - ArrayRef ArgLocs = TupleE->getElementNameLocs(); - for (auto i : indices(ArgNames)) { - Identifier Name = ArgNames[i]; + for (auto Arg : *ArgList) { + Identifier Name = Arg.getLabel(); if (Name.empty()) continue; - SourceLoc Loc = ArgLocs[i]; + SourceLoc Loc = Arg.getLabelLoc(); if (Loc.isInvalid()) continue; diff --git a/lib/IDE/SwiftSourceDocInfo.cpp b/lib/IDE/SwiftSourceDocInfo.cpp index b0637d40e8985..8d19c3ecea784 100644 --- a/lib/IDE/SwiftSourceDocInfo.cpp +++ b/lib/IDE/SwiftSourceDocInfo.cpp @@ -177,19 +177,19 @@ bool NameMatcher::handleCustomAttrs(Decl *D) { for (auto *customAttr : D->getAttrs().getAttributes()) { if (shouldSkip(customAttr->getRangeWithAt())) continue; - auto *Arg = customAttr->getArg(); + auto *Args = customAttr->getArgs(); if (auto *Repr = customAttr->getTypeRepr()) { // Note the associated call arguments of the semantic initializer call // in case we're resolving an explicit initializer call within the // CustomAttr's type, e.g. on `Wrapper` in `@Wrapper(wrappedValue: 10)`. - SWIFT_DEFER { CustomAttrArg = None; }; - if (Arg && !Arg->isImplicit()) - CustomAttrArg = Located(Arg, Repr->getLoc()); + SWIFT_DEFER { CustomAttrArgList = None; }; + if (Args && !Args->isImplicit()) + CustomAttrArgList = Located(Args, Repr->getLoc()); if (!Repr->walk(*this)) return false; } - if (Arg && !Arg->isImplicit()) { - if (!Arg->walk(*this)) + if (Args && !customAttr->isImplicit()) { + if (!Args->walk(*this)) return false; } } @@ -282,11 +282,11 @@ Stmt *NameMatcher::walkToStmtPost(Stmt *S) { return S; } -Expr *NameMatcher::getApplicableArgFor(Expr *E) { +ArgumentList *NameMatcher::getApplicableArgsFor(Expr *E) { if (ParentCalls.empty()) return nullptr; auto &Last = ParentCalls.back(); - return Last.ApplicableTo == E ? Last.Call->getArg() : nullptr; + return Last.ApplicableTo == E ? Last.Call->getArgs() : nullptr; } static Expr *extractNameExpr(Expr *Fn) { @@ -308,6 +308,34 @@ static Expr *extractNameExpr(Expr *Fn) { return nullptr; } +std::pair +NameMatcher::walkToArgumentListPre(ArgumentList *ArgList) { + auto Labels = getCallArgLabelRanges(getSourceMgr(), ArgList, + LabelRangeEndAt::BeforeElemStart); + tryResolve(Parent, ArgList->getStartLoc(), LabelRangeType::CallArg, + Labels.first, Labels.second); + if (isDone()) + return {false, ArgList}; + + // Handle arg label locations (the index reports property occurrences on them + // for memberwise inits). + for (auto Arg : *ArgList) { + auto Name = Arg.getLabel(); + auto *E = Arg.getExpr(); + if (!Name.empty()) { + tryResolve(Parent, Arg.getLabelLoc()); + if (isDone()) + return {false, ArgList}; + } + if (!E->walk(*this)) + return {false, ArgList}; + } + // We already visited the children. + if (!walkToArgumentListPost(ArgList)) + return {false, nullptr}; + return {false, ArgList}; +} + std::pair NameMatcher::walkToExprPre(Expr *E) { if (shouldSkip(E)) return std::make_pair(false, isDone()? nullptr : E); @@ -333,16 +361,19 @@ std::pair NameMatcher::walkToExprPre(Expr *E) { switch (E->getKind()) { case ExprKind::UnresolvedMember: { auto UME = cast(E); - tryResolve(ASTWalker::ParentTy(E), UME->getNameLoc(), getApplicableArgFor(E)); + tryResolve(ASTWalker::ParentTy(E), UME->getNameLoc(), + getApplicableArgsFor(E)); } break; case ExprKind::DeclRef: { auto DRE = cast(E); - tryResolve(ASTWalker::ParentTy(E), DRE->getNameLoc(), getApplicableArgFor(E)); + tryResolve(ASTWalker::ParentTy(E), DRE->getNameLoc(), + getApplicableArgsFor(E)); break; } case ExprKind::UnresolvedDeclRef: { auto UDRE = cast(E); - tryResolve(ASTWalker::ParentTy(E), UDRE->getNameLoc(), getApplicableArgFor(E)); + tryResolve(ASTWalker::ParentTy(E), UDRE->getNameLoc(), + getApplicableArgsFor(E)); break; } case ExprKind::StringLiteral: @@ -351,64 +382,6 @@ std::pair NameMatcher::walkToExprPre(Expr *E) { tryResolve(ASTWalker::ParentTy(E), nextLoc()); } while (!shouldSkip(E)); break; - case ExprKind::Subscript: { - auto SubExpr = cast(E); - // visit and check in source order - if (!SubExpr->getBase()->walk(*this)) - return {false, nullptr}; - - auto Labels = getCallArgLabelRanges(getSourceMgr(), SubExpr->getIndex(), - LabelRangeEndAt::BeforeElemStart); - tryResolve(ASTWalker::ParentTy(E), E->getLoc(), LabelRangeType::CallArg, - Labels.first, Labels.second); - if (isDone()) - break; - if (!SubExpr->getIndex()->walk(*this)) - return {false, nullptr}; - - // We already visited the children. - if (!walkToExprPost(E)) - return {false, nullptr}; - return {false, E}; - } - case ExprKind::Paren: { - ParenExpr *P = cast(E); - // Handle implicit callAsFunction reference on opening paren - auto Labels = getCallArgLabelRanges(getSourceMgr(), P, - LabelRangeEndAt::BeforeElemStart); - tryResolve(ASTWalker::ParentTy(E), P->getLParenLoc(), - LabelRangeType::CallArg, Labels.first, Labels.second); - break; - } - case ExprKind::Tuple: { - TupleExpr *T = cast(E); - // Handle implicit callAsFunction reference on opening paren - auto Labels = getCallArgLabelRanges(getSourceMgr(), T, - LabelRangeEndAt::BeforeElemStart); - tryResolve(ASTWalker::ParentTy(E), T->getLParenLoc(), - LabelRangeType::CallArg, Labels.first, Labels.second); - if (isDone()) - break; - - // Handle arg label locations (the index reports property occurrences - // on them for memberwise inits) - for (unsigned i = 0, e = T->getNumElements(); i != e; ++i) { - auto Name = T->getElementName(i); - if (!Name.empty()) { - tryResolve(ASTWalker::ParentTy(E), T->getElementNameLoc(i)); - if (isDone()) - break; - } - if (auto *Elem = T->getElement(i)) { - if (!Elem->walk(*this)) - return {false, nullptr}; - } - } - // We already visited the children. - if (!walkToExprPost(E)) - return {false, nullptr}; - return {false, E}; - } case ExprKind::Binary: { BinaryExpr *BinE = cast(E); // Visit in source order. @@ -475,7 +448,8 @@ Expr *NameMatcher::walkToExprPost(Expr *E) { break; case ExprKind::UnresolvedDot: { auto UDE = cast(E); - tryResolve(ASTWalker::ParentTy(E), UDE->getNameLoc(), getApplicableArgFor(E)); + tryResolve(ASTWalker::ParentTy(E), UDE->getNameLoc(), + getApplicableArgsFor(E)); break; } default: @@ -503,9 +477,10 @@ bool NameMatcher::walkToTypeReprPre(TypeRepr *T) { if (isa(T)) { // If we're walking a CustomAttr's type we may have an associated call // argument to resolve with from its semantic initializer. - if (CustomAttrArg.hasValue() && CustomAttrArg->Loc == T->getLoc()) { - auto Labels = getCallArgLabelRanges(getSourceMgr(), CustomAttrArg->Item, - LabelRangeEndAt::BeforeElemStart); + if (CustomAttrArgList.hasValue() && CustomAttrArgList->Loc == T->getLoc()) { + auto Labels = + getCallArgLabelRanges(getSourceMgr(), CustomAttrArgList->Item, + LabelRangeEndAt::BeforeElemStart); tryResolve(ASTWalker::ParentTy(T), T->getLoc(), LabelRangeType::CallArg, Labels.first, Labels.second); } else { @@ -606,7 +581,7 @@ std::vector getSelectorLabelRanges(SourceManager &SM, } bool NameMatcher::tryResolve(ASTWalker::ParentTy Node, DeclNameLoc NameLoc, - Expr *Arg) { + ArgumentList *Args) { if (NameLoc.isInvalid()) return false; @@ -627,8 +602,8 @@ bool NameMatcher::tryResolve(ASTWalker::ParentTy Node, DeclNameLoc NameLoc, } if (LocsToResolve.back().ResolveArgLocs) { - if (Arg) { - auto Labels = getCallArgLabelRanges(getSourceMgr(), Arg, + if (Args) { + auto Labels = getCallArgLabelRanges(getSourceMgr(), Args, LabelRangeEndAt::BeforeElemStart); return tryResolve(Node, NameLoc.getBaseNameLoc(), LabelRangeType::CallArg, Labels.first, Labels.second); @@ -828,44 +803,35 @@ static Expr* getSingleNonImplicitChild(Expr *Parent) { } std::vector swift::ide:: -getCallArgInfo(SourceManager &SM, Expr *Arg, LabelRangeEndAt EndKind) { +getCallArgInfo(SourceManager &SM, ArgumentList *Args, LabelRangeEndAt EndKind) { std::vector InfoVec; - if (auto *TE = dyn_cast(Arg)) { - auto FirstTrailing = TE->getUnlabeledTrailingClosureIndexOfPackedArgument(); - for (size_t ElemIndex: range(TE->getNumElements())) { - Expr *Elem = TE->getElement(ElemIndex); - if (isa(Elem)) - continue; - - SourceLoc LabelStart(Elem->getStartLoc()); - SourceLoc LabelEnd(LabelStart); - - bool IsTrailingClosure = FirstTrailing && ElemIndex >= *FirstTrailing; - SourceLoc NameLoc = TE->getElementNameLoc(ElemIndex); - if (NameLoc.isValid()) { - LabelStart = NameLoc; - if (EndKind == LabelRangeEndAt::LabelNameOnly || IsTrailingClosure) { - LabelEnd = Lexer::getLocForEndOfToken(SM, NameLoc); - } + auto *OriginalArgs = Args->getOriginalArgs(); + for (auto ElemIndex : indices(*OriginalArgs)) { + auto *Elem = OriginalArgs->getExpr(ElemIndex); + + SourceLoc LabelStart(Elem->getStartLoc()); + SourceLoc LabelEnd(LabelStart); + + bool IsTrailingClosure = OriginalArgs->isTrailingClosureIndex(ElemIndex); + auto NameLoc = OriginalArgs->getLabelLoc(ElemIndex); + if (NameLoc.isValid()) { + LabelStart = NameLoc; + if (EndKind == LabelRangeEndAt::LabelNameOnly || IsTrailingClosure) { + LabelEnd = Lexer::getLocForEndOfToken(SM, NameLoc); } - InfoVec.push_back({getSingleNonImplicitChild(Elem), - CharSourceRange(SM, LabelStart, LabelEnd), IsTrailingClosure}); } - } else if (auto *PE = dyn_cast(Arg)) { - Expr *Sub = PE->getSubExpr(); - if (Sub && !isa(Sub)) - InfoVec.push_back({getSingleNonImplicitChild(Sub), - CharSourceRange(Sub->getStartLoc(), 0), - PE->hasTrailingClosure() - }); + InfoVec.push_back({getSingleNonImplicitChild(Elem), + CharSourceRange(SM, LabelStart, LabelEnd), + IsTrailingClosure}); } return InfoVec; } -std::pair, Optional> swift::ide:: -getCallArgLabelRanges(SourceManager &SM, Expr *Arg, LabelRangeEndAt EndKind) { +std::pair, Optional> +swift::ide::getCallArgLabelRanges(SourceManager &SM, ArgumentList *Args, + LabelRangeEndAt EndKind) { std::vector Ranges; - auto InfoVec = getCallArgInfo(SM, Arg, EndKind); + auto InfoVec = getCallArgInfo(SM, Args, EndKind); Optional FirstTrailing; auto I = std::find_if(InfoVec.begin(), InfoVec.end(), [](CallArgInfo &Info) { diff --git a/lib/IDE/SyntaxModel.cpp b/lib/IDE/SyntaxModel.cpp index 3c76dd622792c..9ada8e102f7c0 100644 --- a/lib/IDE/SyntaxModel.cpp +++ b/lib/IDE/SyntaxModel.cpp @@ -361,6 +361,12 @@ class ModelASTWalker : public ASTWalker { friend class InactiveClauseRAII; bool inInactiveClause = false; + /// A mapping of argument expressions to their full argument info. + llvm::DenseMap ArgumentInfo; + + /// The number of ArgumentList parents in the walk. + unsigned ArgumentListDepth = 0; + public: SyntaxModelWalker &Walker; ArrayRef TokenNodes; @@ -378,6 +384,10 @@ class ModelASTWalker : public ASTWalker { void visitSourceFile(SourceFile &SrcFile, ArrayRef Tokens); + std::pair + walkToArgumentListPre(ArgumentList *ArgList) override; + ArgumentList *walkToArgumentListPost(ArgumentList *ArgList) override; + std::pair walkToExprPre(Expr *E) override; Expr *walkToExprPost(Expr *E) override; std::pair walkToStmtPre(Stmt *S) override; @@ -422,7 +432,6 @@ class ModelASTWalker : public ASTWalker { bool pushStructureNode(const SyntaxStructureNode &Node, const ASTNodeType& ASTNode); bool popStructureNode(); - bool isCurrentCallArgExpr(const Expr *E); bool processComment(CharSourceRange Range); bool searchForURL(CharSourceRange Range); @@ -484,36 +493,6 @@ CharSourceRange innerCharSourceRangeFromSourceRange(const SourceManager &SM, return CharSourceRange(SM, SRS, (SR.End != SR.Start) ? SR.End : SRS); } -CharSourceRange parameterNameRangeOfCallArg(const Expr *ArgListExpr, - const Expr *Arg) { - if (isa(ArgListExpr)) - return CharSourceRange(); - - auto *TE = cast(ArgListExpr); - if (!TE->hasElementNameLocs() || !TE->hasElementNames()) - return CharSourceRange(); - - // Loop over the elements to find the index representing Arg. - // This is somewhat inefficient but the only way to find the corresponding - // name without the index, and the number of parameters in a call is normally - // very low. If this becomes a performance problem, we could perhaps have - // ASTWalker visit the element name as well. - unsigned i = 0; - for (auto E : TE->getElements()) { - if (E == Arg) { - SourceLoc NL = TE->getElementNameLoc(i); - Identifier Name = TE->getElementName(i); - if (NL.isValid() && !Name.empty()) - return CharSourceRange(NL, Name.getLength()); - - return CharSourceRange(); - } - ++i; - } - - return CharSourceRange(); -} - static void setDecl(SyntaxStructureNode &N, Decl *D) { N.Dcl = D; N.Attrs = D->getAttrs(); @@ -547,15 +526,41 @@ static bool shouldTreatAsSingleToken(const SyntaxStructureNode &Node, SM.getLineAndColumnInBuffer(Node.Range.getEnd()).first; } +std::pair +ModelASTWalker::walkToArgumentListPre(ArgumentList *ArgList) { + for (auto Arg : *ArgList) { + auto res = ArgumentInfo.insert({Arg.getExpr(), Arg}); + assert(res.second && "Duplicate arguments?"); + (void)res; + } + ArgumentListDepth += 1; + return {true, ArgList}; +} + +ArgumentList *ModelASTWalker::walkToArgumentListPost(ArgumentList *ArgList) { + // If there are no more argument lists above us, we can clear out the argument + // mapping to save memory. + ArgumentListDepth -= 1; + if (ArgumentListDepth == 0) + ArgumentInfo.clear(); + return ArgList; +} + std::pair ModelASTWalker::walkToExprPre(Expr *E) { if (isVisitedBefore(E)) return {false, E}; - auto addCallArgExpr = [&](Expr *Elem, Expr *ArgListExpr) { - if (isa(Elem) || !isCurrentCallArgExpr(ArgListExpr)) + auto addCallArgExpr = [&](const Argument &Arg) { + auto *Elem = Arg.getExpr(); + if (isa(Elem)) return; - CharSourceRange NR = parameterNameRangeOfCallArg(ArgListExpr, Elem); + CharSourceRange NR; + auto NL = Arg.getLabelLoc(); + auto Name = Arg.getLabel(); + if (NL.isValid() && !Name.empty()) + NR = CharSourceRange(NL, Name.getLength()); + SyntaxStructureNode SN; SN.Kind = SyntaxStructureKind::Argument; SN.NameRange = NR; @@ -571,10 +576,9 @@ std::pair ModelASTWalker::walkToExprPre(Expr *E) { pushStructureNode(SN, Elem); }; - if (auto *ParentExpr = Parent.getAsExpr()) { - if (isa(ParentExpr) || isa(ParentExpr)) - addCallArgExpr(E, ParentExpr); - } + auto Arg = ArgumentInfo.find(E); + if (Arg != ArgumentInfo.end()) + addCallArgExpr(Arg->second); if (E->isImplicit()) return { true, E }; @@ -596,9 +600,9 @@ std::pair ModelASTWalker::walkToExprPre(Expr *E) { if (CE->getFn() && CE->getFn()->getSourceRange().isValid()) SN.NameRange = charSourceRangeFromSourceRange(SM, CE->getFn()->getSourceRange()); - if (CE->getArg() && CE->getArg()->getSourceRange().isValid()) - SN.BodyRange = innerCharSourceRangeFromSourceRange(SM, - CE->getArg()->getSourceRange()); + if (CE->getArgs()->getSourceRange().isValid()) + SN.BodyRange = innerCharSourceRangeFromSourceRange( + SM, CE->getArgs()->getSourceRange()); pushStructureNode(SN, CE); } else if (auto *ObjectE = dyn_cast(E)) { @@ -640,20 +644,15 @@ std::pair ModelASTWalker::walkToExprPre(Expr *E) { SN.BodyRange = innerCharSourceRangeFromSourceRange(SM, E->getSourceRange()); pushStructureNode(SN, E); } else if (auto *Tup = dyn_cast(E)) { - auto *ParentE = Parent.getAsExpr(); - if (!isCurrentCallArgExpr(Tup) && (!ParentE || !isa(ParentE))) { - SyntaxStructureNode SN; - SN.Kind = SyntaxStructureKind::TupleExpression; - SN.Range = charSourceRangeFromSourceRange(SM, Tup->getSourceRange()); - SN.BodyRange = innerCharSourceRangeFromSourceRange(SM, - Tup->getSourceRange()); - - for (auto *Elem : Tup->getElements()) { - addExprElem(Elem, SN); - } - - pushStructureNode(SN, Tup); + SyntaxStructureNode SN; + SN.Kind = SyntaxStructureKind::TupleExpression; + SN.Range = charSourceRangeFromSourceRange(SM, Tup->getSourceRange()); + SN.BodyRange = + innerCharSourceRangeFromSourceRange(SM, Tup->getSourceRange()); + for (auto *Elem : Tup->getElements()) { + addExprElem(Elem, SN); } + pushStructureNode(SN, Tup); } else if (auto *Closure = dyn_cast(E)) { SyntaxStructureNode SN; SN.Kind = SyntaxStructureKind::ClosureExpression; @@ -684,8 +683,8 @@ std::pair ModelASTWalker::walkToExprPre(Expr *E) { llvm::SaveAndRestore SetParent(Parent, E); ISL->forEachSegment(Ctx, [&](bool isInterpolation, CallExpr *CE) { if (isInterpolation) { - if (auto *Arg = CE->getArg()) - Arg->walk(*this); + for (auto arg : *CE->getArgs()) + arg.getExpr()->walk(*this); } }); return { false, walkToExprPost(E) }; @@ -1186,8 +1185,8 @@ bool ModelASTWalker::handleSpecialDeclAttribute(const DeclAttribute *D, if (!Repr->walk(*this)) return false; } - if (auto *Arg = CA->getArg()) { - if (!Arg->walk(*this)) + if (auto *Args = CA->getArgs()) { + if (!Args->walk(*this)) return false; } } else if (!TokenNodes.empty()) { @@ -1434,20 +1433,6 @@ bool ModelASTWalker::popStructureNode() { return true; } -bool ModelASTWalker::isCurrentCallArgExpr(const Expr *E) { - if (SubStructureStack.empty()) - return false; - auto Current = SubStructureStack.back(); - - if (Current.StructureNode.Kind == - SyntaxStructureKind::ObjectLiteralExpression && - cast(Current.ASTNode.getAsExpr())->getArg() == E) - return true; - - return Current.StructureNode.Kind == SyntaxStructureKind::CallExpression && - cast(Current.ASTNode.getAsExpr())->getArg() == E; -} - bool ModelASTWalker::processComment(CharSourceRange Range) { StringRef Text = SM.extractText(Range, BufferID); SourceLoc Loc = Range.getStart(); diff --git a/lib/IDE/Utils.cpp b/lib/IDE/Utils.cpp index 8878e613709f2..fe5d0111dee7f 100644 --- a/lib/IDE/Utils.cpp +++ b/lib/IDE/Utils.cpp @@ -1200,8 +1200,10 @@ bool swift::ide::isBeingCalled(ArrayRef ExprStack) { auto *AE = dyn_cast(E); if (!AE || AE->isImplicit()) continue; - if (isa(AE) && AE->getArg() == Target) - return true; + if (auto *CRCE = dyn_cast(AE)) { + if (CRCE->getBase() == Target) + return true; + } if (isa(AE)) continue; if (getReferencedDecl(AE->getFn()).second == UnderlyingDecl) diff --git a/lib/Index/Index.cpp b/lib/Index/Index.cpp index 5ddb875ef3bb5..bc9c1cb2328d7 100644 --- a/lib/Index/Index.cpp +++ b/lib/Index/Index.cpp @@ -372,28 +372,26 @@ class IndexSwiftASTWalker : public SourceEntityWalker { if (!DeclRef || !isMemberwiseInit(DeclRef->getDecl())) return; - // get label locations auto *MemberwiseInit = DeclRef->getDecl(); - std::vector LabelLocs; - ArrayRef Labels; auto NameLoc = DeclRef->getNameLoc(); + auto ArgNames = MemberwiseInit->getName().getArgumentNames(); + + // Get label locations. + llvm::SmallVector Args; if (NameLoc.isCompound()) { size_t LabelIndex = 0; - SourceLoc ArgLoc; - while ((ArgLoc = NameLoc.getArgumentLabelLoc(LabelIndex++)).isValid()) { - LabelLocs.push_back(ArgLoc); + while (auto ArgLoc = NameLoc.getArgumentLabelLoc(LabelIndex)) { + Args.emplace_back(ArgLoc, ArgNames[LabelIndex], /*expr*/ nullptr); + LabelIndex++; } - Labels = MemberwiseInit->getName().getArgumentNames(); } else if (auto *CallParent = dyn_cast_or_null(getParentExpr())) { - LabelLocs = CallParent->getArgumentLabelLocs(); - Labels = CallParent->getArgumentLabels(); + auto *args = CallParent->getArgs(); + Args.append(args->begin(), args->end()); } - if (LabelLocs.empty()) + if (Args.empty()) return; - assert(Labels.size() == LabelLocs.size()); - // match labels to properties auto *TypeContext = MemberwiseInit->getDeclContext()->getSelfNominalTypeDecl(); @@ -409,14 +407,15 @@ class IndexSwiftASTWalker : public SourceEntityWalker { if (!Prop->isMemberwiseInitialized(/*preferDeclaredProperties=*/true)) continue; - if (CurLabel == LabelLocs.size()) + if (CurLabel == Args.size()) break; - if (Labels[CurLabel] != Prop->getName()) + if (Args[CurLabel].getLabel() != Prop->getName()) continue; IndexSymbol Info; - if (initIndexSymbol(Prop, LabelLocs[CurLabel++], /*IsRef=*/true, Info)) + auto LabelLoc = Args[CurLabel++].getLabelLoc(); + if (initIndexSymbol(Prop, LabelLoc, /*IsRef=*/true, Info)) continue; if (startEntity(Prop, Info, /*IsRef=*/true)) finishCurrentEntity(); diff --git a/lib/Migrator/APIDiffMigratorPass.cpp b/lib/Migrator/APIDiffMigratorPass.cpp index 62a29ce4ca943..77f0f42d71c78 100644 --- a/lib/Migrator/APIDiffMigratorPass.cpp +++ b/lib/Migrator/APIDiffMigratorPass.cpp @@ -498,10 +498,10 @@ struct APIDiffMigratorPass : public ASTMigratorPass, public SourceEntityWalker { } }; - void emitRenameLabelChanges(Expr *Arg, DeclNameViewer NewName, + void emitRenameLabelChanges(ArgumentList *Args, DeclNameViewer NewName, llvm::ArrayRef IgnoreArgIndex) { unsigned Idx = 0; - auto Ranges = getCallArgLabelRanges(SM, Arg, + auto Ranges = getCallArgLabelRanges(SM, Args, LabelRangeEndAt::LabelNameOnly); llvm::SmallVector ToRemoveIndices; for (unsigned I = 0; I < Ranges.first.size(); I ++) { @@ -529,7 +529,7 @@ struct APIDiffMigratorPass : public ASTMigratorPass, public SourceEntityWalker { } } if (!ToRemoveIndices.empty()) { - auto Ranges = getCallArgLabelRanges(SM, Arg, + auto Ranges = getCallArgLabelRanges(SM, Args, LabelRangeEndAt::BeforeElemStart); for (auto I : ToRemoveIndices) { Editor.remove(Ranges.first[I]); @@ -537,7 +537,8 @@ struct APIDiffMigratorPass : public ASTMigratorPass, public SourceEntityWalker { } } - void handleFuncRename(ValueDecl *FD, Expr* FuncRefContainer, Expr *Arg) { + void handleFuncRename(ValueDecl *FD, Expr* FuncRefContainer, + ArgumentList *Args) { bool IgnoreBase = false; llvm::SmallString<32> Buffer; if (auto View = getFuncRename(FD, Buffer, IgnoreBase)) { @@ -546,7 +547,7 @@ struct APIDiffMigratorPass : public ASTMigratorPass, public SourceEntityWalker { Walker.walk(FuncRefContainer); Editor.replace(Walker.Result, View.base()); } - emitRenameLabelChanges(Arg, View, {}); + emitRenameLabelChanges(Args, View, {}); } } @@ -579,7 +580,7 @@ struct APIDiffMigratorPass : public ASTMigratorPass, public SourceEntityWalker { return false; } - bool handleSpecialCases(ValueDecl *FD, CallExpr* Call, Expr *Arg) { + bool handleSpecialCases(ValueDecl *FD, CallExpr* Call, ArgumentList *Args) { SpecialCaseDiffItem *Item = nullptr; for (auto *I: getRelatedDiffItems(FD)) { Item = dyn_cast(I); @@ -589,7 +590,7 @@ struct APIDiffMigratorPass : public ASTMigratorPass, public SourceEntityWalker { if (!Item) return false; std::vector AllArgs = - getCallArgInfo(SM, Arg, LabelRangeEndAt::LabelNameOnly); + getCallArgInfo(SM, Args, LabelRangeEndAt::LabelNameOnly); switch(Item->caseId) { case SpecialCaseId::NSOpenGLSetOption: { // swift 3.2: @@ -655,43 +656,39 @@ struct APIDiffMigratorPass : public ASTMigratorPass, public SourceEntityWalker { } return false; case SpecialCaseId::NSOpenGLGetVersion: { - if (const auto *Tuple = dyn_cast(Arg)) { - if (Tuple->getNumElements() != 2) { - return false; - } + if (Args->size() != 2) + return false; - auto extractArg = [](const Expr *Arg) -> const DeclRefExpr * { - while (const auto *ICE = dyn_cast(Arg)) { - Arg = ICE->getSubExpr(); - } - if (const auto *IOE = dyn_cast(Arg)) { - return dyn_cast(IOE->getSubExpr()); - } - return nullptr; - }; + auto extractArg = [](const Expr *Arg) -> const DeclRefExpr * { + while (const auto *ICE = dyn_cast(Arg)) { + Arg = ICE->getSubExpr(); + } + if (const auto *IOE = dyn_cast(Arg)) { + return dyn_cast(IOE->getSubExpr()); + } + return nullptr; + }; - const auto *Arg0 = extractArg(Tuple->getElement(0)); - const auto *Arg1 = extractArg(Tuple->getElement(1)); + const auto *Arg0 = extractArg(Args->getExpr(0)); + const auto *Arg1 = extractArg(Args->getExpr(1)); - if (!(Arg0 && Arg1)) { - return false; - } - SmallString<256> Scratch; - llvm::raw_svector_ostream OS(Scratch); - auto StartLoc = Call->getStartLoc(); - Editor.insert(StartLoc, "("); - Editor.insert(StartLoc, - SM.extractText(Lexer::getCharSourceRangeFromSourceRange(SM, - Arg0->getSourceRange()))); - Editor.insert(StartLoc, ", "); - Editor.insert(StartLoc, - SM.extractText(Lexer::getCharSourceRangeFromSourceRange(SM, - Arg1->getSourceRange()))); - Editor.insert(StartLoc, ") = "); - Editor.replace(Call->getSourceRange(), "NSOpenGLContext.openGLVersion"); - return true; + if (!(Arg0 && Arg1)) { + return false; } - return false; + SmallString<256> Scratch; + llvm::raw_svector_ostream OS(Scratch); + auto StartLoc = Call->getStartLoc(); + Editor.insert(StartLoc, "("); + Editor.insert(StartLoc, + SM.extractText(Lexer::getCharSourceRangeFromSourceRange(SM, + Arg0->getSourceRange()))); + Editor.insert(StartLoc, ", "); + Editor.insert(StartLoc, + SM.extractText(Lexer::getCharSourceRangeFromSourceRange(SM, + Arg1->getSourceRange()))); + Editor.insert(StartLoc, ") = "); + Editor.replace(Call->getSourceRange(), "NSOpenGLContext.openGLVersion"); + return true; } case SpecialCaseId::UIApplicationMain: { // If the first argument is CommandLine.argc, replace the second argument @@ -714,7 +711,7 @@ struct APIDiffMigratorPass : public ASTMigratorPass, public SourceEntityWalker { llvm_unreachable("unhandled case"); } - bool handleTypeHoist(ValueDecl *FD, CallExpr* Call, Expr *Arg) { + bool handleTypeHoist(ValueDecl *FD, CallExpr* Call, ArgumentList *Args) { TypeMemberDiffItem *Item = nullptr; for (auto *I: getRelatedDiffItems(FD)) { Item = dyn_cast(I); @@ -736,7 +733,7 @@ struct APIDiffMigratorPass : public ASTMigratorPass, public SourceEntityWalker { if (*Item->selfIndex) return false; std::vector AllArgs = - getCallArgInfo(SM, Arg, LabelRangeEndAt::LabelNameOnly); + getCallArgInfo(SM, Args, LabelRangeEndAt::LabelNameOnly); if (!AllArgs.size()) return false; assert(*Item->selfIndex == 0 && "we cannot handle otherwise"); @@ -745,7 +742,7 @@ struct APIDiffMigratorPass : public ASTMigratorPass, public SourceEntityWalker { IgnoredArgIndices.push_back(*Item->selfIndex); if (auto RI = Item->removedIndex) IgnoredArgIndices.push_back(*RI); - emitRenameLabelChanges(Arg, NewName, IgnoredArgIndices); + emitRenameLabelChanges(Args, NewName, IgnoredArgIndices); auto *SelfExpr = AllArgs[0].ArgExp; if (auto *IOE = dyn_cast(SelfExpr)) SelfExpr = IOE->getSubExpr(); @@ -796,28 +793,28 @@ struct APIDiffMigratorPass : public ASTMigratorPass, public SourceEntityWalker { } case TypeMemberDiffItemSubKind::HoistSelfAndUseProperty: // Remove ). - Editor.remove(Arg->getEndLoc()); + Editor.remove(Args->getEndLoc()); return true; } llvm_unreachable("unhandled subkind"); } void handleFunctionCallToPropertyChange(ValueDecl *FD, Expr* FuncRefContainer, - Expr *Arg) { + ArgumentList *Args) { for (auto *Item : getRelatedDiffItems(FD)) { if (auto *CD = dyn_cast(Item)) { switch (CD->DiffKind) { case NodeAnnotation::GetterToProperty: { // Remove "()" Editor.remove(Lexer::getCharSourceRangeFromSourceRange(SM, - Arg->getSourceRange())); + Args->getSourceRange())); return; } case NodeAnnotation::SetterToProperty: { ReferenceCollector Walker(FD); Walker.walk(FuncRefContainer); auto ReplaceRange = CharSourceRange(SM, Walker.Result.getStart(), - Arg->getStartLoc().getAdvancedLoc(1)); + Args->getStartLoc().getAdvancedLoc(1)); // Replace "x.getY(" with "x.Y =". auto Replacement = (llvm::Twine(Walker.Result.str() @@ -827,8 +824,8 @@ struct APIDiffMigratorPass : public ASTMigratorPass, public SourceEntityWalker { camel_case::toLowercaseInitialisms(Replacement, Scratch)); // Remove ")" - Editor.remove(CharSourceRange(SM, Arg->getEndLoc(), Arg->getEndLoc(). - getAdvancedLoc(1))); + Editor.remove(CharSourceRange(SM, Args->getEndLoc(), + Args->getEndLoc().getAdvancedLoc(1))); return; } default: @@ -974,7 +971,8 @@ struct APIDiffMigratorPass : public ASTMigratorPass, public SourceEntityWalker { return Info; } - void handleStringRepresentableArg(ValueDecl *FD, Expr *Arg, Expr *Call) { + void handleStringRepresentableArg(ValueDecl *FD, ArgumentList *Args, + Expr *Call) { NodeAnnotation Kind; StringRef RawType; StringRef NewAttributeType; @@ -998,7 +996,7 @@ struct APIDiffMigratorPass : public ASTMigratorPass, public SourceEntityWalker { if (ArgIdx) { ArgIdx --; FromString = true; - auto AllArgs = getCallArgInfo(SM, Arg, LabelRangeEndAt::LabelNameOnly); + auto AllArgs = getCallArgInfo(SM, Args, LabelRangeEndAt::LabelNameOnly); if (AllArgs.size() <= ArgIdx) return; WrapTarget = AllArgs[ArgIdx].ArgExp; @@ -1053,7 +1051,7 @@ struct APIDiffMigratorPass : public ASTMigratorPass, public SourceEntityWalker { if (!Found) return false; std::vector AllArgs = - getCallArgInfo(SM, CE->getArg(), LabelRangeEndAt::LabelNameOnly); + getCallArgInfo(SM, CE->getArgs(), LabelRangeEndAt::LabelNameOnly); if (AllArgs.size() == 1) { auto Label = AllArgs.front().LabelRange.str(); if (Label == "rawValue" || Label.empty()) { @@ -1128,7 +1126,7 @@ struct APIDiffMigratorPass : public ASTMigratorPass, public SourceEntityWalker { return false; if (auto *CE = dyn_cast(E)) { auto Fn = CE->getFn(); - auto Args = CE->getArg(); + auto Args = CE->getArgs(); if (auto *DRE = dyn_cast(Fn)) { if (auto *VD = DRE->getDecl()) { 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..e05b491f44fb4 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::createParsed(Context, SourceLoc(), + trailingClosures, SourceLoc(), + /*trailingClosureIdx*/ 0); 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,94 @@ 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; + + // 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); + if (args.size() > numNonTrailing) + trailingClosureIndex = numNonTrailing; + } + auto *argList = ArgumentList::createParsed(Context, leftLoc, args, rightLoc, + trailingClosureIndex); + 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 +3136,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 +3164,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 +3179,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 +3214,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 +3232,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 +3241,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 +3278,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 +3310,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 +3337,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 +3366,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 +3394,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 +3414,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 +3452,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::createParsed( + Context, lParenLoc, {Argument::unlabeled(CCE)}, rParenLoc, + /*trailingClosureIdx*/ None); + 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 +3471,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 +3683,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(); diff --git a/lib/SILGen/ArgumentSource.cpp b/lib/SILGen/ArgumentSource.cpp index c3035d821d609..cf4dd5cf59deb 100644 --- a/lib/SILGen/ArgumentSource.cpp +++ b/lib/SILGen/ArgumentSource.cpp @@ -251,18 +251,11 @@ void ArgumentSource::dump(raw_ostream &out, unsigned indent) const { llvm_unreachable("bad kind"); } -PreparedArguments::PreparedArguments( - ArrayRef params, - Expr *arg) : PreparedArguments(params) { - if (auto *PE = dyn_cast(arg)) - addArbitrary(PE->getSubExpr()); - else if (auto *TE = dyn_cast(arg)) { - for (auto *elt : TE->getElements()) - addArbitrary(elt); - } else { - // FIXME: All ApplyExprs should have a ParenExpr or TupleExpr as their argument - addArbitrary(arg); - } +PreparedArguments::PreparedArguments(ArrayRef params, + ArgumentList *argList) + : PreparedArguments(params) { + for (auto arg : *argList) + addArbitrary(arg.getExpr()); } PreparedArguments diff --git a/lib/SILGen/ArgumentSource.h b/lib/SILGen/ArgumentSource.h index b909ab09dc218..942a88afb43c8 100644 --- a/lib/SILGen/ArgumentSource.h +++ b/lib/SILGen/ArgumentSource.h @@ -296,8 +296,9 @@ class PreparedArguments { emplace(params); } - // Decompse an argument list expression. - PreparedArguments(ArrayRef params, Expr *arg); + // Create from an argument list. + PreparedArguments(ArrayRef params, + ArgumentList *argList); // Move-only. PreparedArguments(const PreparedArguments &) = delete; diff --git a/lib/SILGen/LValue.h b/lib/SILGen/LValue.h index 64bd57d7744bc..bb85e6a53b8ff 100644 --- a/lib/SILGen/LValue.h +++ b/lib/SILGen/LValue.h @@ -279,7 +279,7 @@ class LogicalPathComponent : public PathComponent { AbstractStorageDecl *Storage; bool IsSuper; const PreparedArguments *Indices; - Expr *IndexExprForDiagnostics; + ArgumentList *ArgListForDiagnostics; }; /// Get the storage accessed by this component. @@ -459,7 +459,7 @@ class LValue { AccessStrategy accessStrategy, CanType formalRValueType, PreparedArguments &&indices, - Expr *indexExprForDiagnostics); + ArgumentList *argListForDiagnostics); void addMemberVarComponent(SILGenFunction &SGF, SILLocation loc, VarDecl *var, @@ -481,7 +481,7 @@ class LValue { AccessStrategy accessStrategy, CanType formalRValueType, PreparedArguments &&indices, - Expr *indexExprForDiagnostics, + ArgumentList *argListForDiagnostics, bool isOnSelfParameter = false, Optional actorIso = None); diff --git a/lib/SILGen/SILGenApply.cpp b/lib/SILGen/SILGenApply.cpp index f1f00be426a2a..fea08d05db316 100644 --- a/lib/SILGen/SILGenApply.cpp +++ b/lib/SILGen/SILGenApply.cpp @@ -808,7 +808,7 @@ class SILGenApply : public Lowering::ExprVisitor { /// The lvalue or rvalue representing the argument source of self. ArgumentSource selfParam; - ApplyExpr *selfApply = nullptr; + SelfApplyExpr *selfApply = nullptr; ApplyExpr *callSite = nullptr; Expr *sideEffect = nullptr; @@ -831,15 +831,18 @@ class SILGenApply : public Lowering::ExprVisitor { selfParam = std::move(theSelfParam); } - bool isMethodSelfApply(Expr *e) { - return (isa(e) && - !isa( - cast(e)->getFn())); + SelfApplyExpr *getAsMethodSelfApply(Expr *e) { + auto *SAE = dyn_cast(e); + if (!SAE) + return nullptr; + if (isa(SAE->getFn())) + return nullptr; + return SAE; } void decompose(ApplyExpr *e) { - if (isMethodSelfApply(e)) { - selfApply = e; + if (auto *SAE = getAsMethodSelfApply(e)) { + selfApply = SAE; visit(selfApply->getFn()); return; @@ -847,10 +850,10 @@ class SILGenApply : public Lowering::ExprVisitor { callSite = e; - if (isMethodSelfApply(e->getFn())) { - selfApply = cast(e->getFn()); + if (auto *SAE = getAsMethodSelfApply(e->getFn())) { + selfApply = SAE; - if (selfApply->getArg()->isSuperExpr()) { + if (selfApply->getBase()->isSuperExpr()) { applySuper(selfApply); return; } @@ -960,14 +963,14 @@ class SILGenApply : public Lowering::ExprVisitor { void processProtocolMethod(DeclRefExpr *e, AbstractFunctionDecl *afd, ProtocolDecl *proto) { - ArgumentSource selfValue = selfApply->getArg(); + ArgumentSource selfValue = selfApply->getBase(); auto subs = e->getDeclRef().getSubstitutions(); SILDeclRef::Kind kind = SILDeclRef::Kind::Func; if (isa(afd)) { if (proto->isObjC()) { - SILLocation loc = selfApply->getArg(); + SILLocation loc = selfApply->getBase(); // For Objective-C initializers, we only have an initializing // initializer. We need to allocate the object ourselves. @@ -1017,8 +1020,8 @@ class SILGenApply : public Lowering::ExprVisitor { // Required constructors are statically dispatched when the 'self' // value is statically derived. - assert(selfApply->getArg()->getType()->is()); - if (selfApply->getArg()->isStaticallyDerivedMetatype()) + assert(selfApply->getBase()->getType()->is()); + if (selfApply->getBase()->isStaticallyDerivedMetatype()) return false; } @@ -1027,7 +1030,7 @@ class SILGenApply : public Lowering::ExprVisitor { } void processClassMethod(DeclRefExpr *e, AbstractFunctionDecl *afd) { - ArgumentSource selfArgSource(selfApply->getArg()); + ArgumentSource selfArgSource(selfApply->getBase()); setSelfParam(std::move(selfArgSource)); // Directly dispatch to calls of the replaced function inside of @@ -1036,7 +1039,7 @@ class SILGenApply : public Lowering::ExprVisitor { if (SGF.getOptions() .EnableDynamicReplacementCanCallPreviousImplementation && isCallToReplacedInDynamicReplacement(SGF, afd, isObjCReplacementCall) && - selfApply->getArg()->isSelfExprOf( + selfApply->getBase()->isSelfExprOf( cast(SGF.FunctionDC->getAsDecl()), false)) { auto constant = SILDeclRef(afd).asForeign( !isObjCReplacementCall && requiresForeignEntryPoint(e->getDecl())); @@ -1089,7 +1092,7 @@ class SILGenApply : public Lowering::ExprVisitor { // Enum case constructor references are open-coded. if (auto *eed = dyn_cast(e->getDecl())) { if (selfApply) { - ArgumentSource selfArgSource(selfApply->getArg()); + ArgumentSource selfArgSource(selfApply->getBase()); setSelfParam(std::move(selfArgSource)); } @@ -1131,6 +1134,7 @@ class SILGenApply : public Lowering::ExprVisitor { // dynamically_replaceable inside of a dynamic_replacement(for:) function. ApplyExpr *thisCallSite = (selfApply ? selfApply : callSite); bool isObjCReplacementSelfCall = false; + auto *unaryArg = thisCallSite->getArgs()->getUnaryExpr(); bool isSelfCallToReplacedInDynamicReplacement = SGF.getOptions() .EnableDynamicReplacementCanCallPreviousImplementation && @@ -1138,8 +1142,8 @@ class SILGenApply : public Lowering::ExprVisitor { SGF, cast(constant.getDecl()), isObjCReplacementSelfCall) && (afd->getDeclContext()->isModuleScopeContext() || - thisCallSite->getArg()->isSelfExprOf( - cast(SGF.FunctionDC->getAsDecl()), false)); + (unaryArg && unaryArg->isSelfExprOf( + cast(SGF.FunctionDC->getAsDecl()), false))); if (isSelfCallToReplacedInDynamicReplacement && !isObjCReplacementSelfCall) setCallee(Callee::forDirect( @@ -1152,7 +1156,7 @@ class SILGenApply : public Lowering::ExprVisitor { if (selfApply) { // This is a statically-dispatched method with a 'self' parameter. - ArgumentSource selfArgSource(selfApply->getArg()); + ArgumentSource selfArgSource(selfApply->getBase()); setSelfParam(std::move(selfArgSource)); } @@ -1259,9 +1263,9 @@ class SILGenApply : public Lowering::ExprVisitor { visit(e->getSubExpr()); } - void applySuper(ApplyExpr *apply) { + void applySuper(SelfApplyExpr *apply) { // Load the 'super' argument. - Expr *arg = apply->getArg(); + Expr *arg = apply->getBase(); RValue super; CanType superFormalType = arg->getType()->getCanonicalType(); @@ -1400,7 +1404,7 @@ class SILGenApply : public Lowering::ExprVisitor { } /// Try to emit the given application as initializer delegation. - bool applyInitDelegation(ApplyExpr *expr) { + bool applyInitDelegation(SelfApplyExpr *expr) { // Dig out the constructor we're delegating to. Expr *fn = expr->getFn(); auto ctorRef = dyn_cast( @@ -1439,7 +1443,7 @@ class SILGenApply : public Lowering::ExprVisitor { } // Load the 'self' argument. - Expr *arg = expr->getArg(); + Expr *arg = expr->getBase(); ManagedValue self; CanType selfFormalType = arg->getType()->getCanonicalType(); @@ -4273,20 +4277,14 @@ CallEmission CallEmission::forApplyExpr(SILGenFunction &SGF, ApplyExpr *e) { } // Apply arguments from the actual call site. - if (apply.callSite) { - Expr *arg = apply.callSite->getArg(); - - SmallVector params; - AnyFunctionType::decomposeTuple(arg->getType(), params); - - PreparedArguments preparedArgs(params, arg); - - emission.addCallSite(apply.callSite, std::move(preparedArgs), - apply.callSite->isNoThrows(), - apply.callSite->isNoAsync()); + if (auto *call = apply.callSite) { + auto fnTy = call->getFn()->getType()->castTo(); + PreparedArguments preparedArgs(fnTy->getParams(), call->getArgs()); + emission.addCallSite(call, std::move(preparedArgs), call->isNoThrows(), + call->isNoAsync()); // For an implicitly-async call, record the target of the actor hop. - if (auto target = apply.callSite->isImplicitlyAsync()) + if (auto target = call->isImplicitlyAsync()) emission.setImplicitlyAsync(target); } @@ -5629,9 +5627,7 @@ PreparedArguments SILGenFunction::prepareSubscriptIndices(SubscriptDecl *subscript, SubstitutionMap subs, AccessStrategy strategy, - Expr *indexExpr) { - // FIXME: we should expect an array of index expressions. - + ArgumentList *argList) { // TODO: use the real abstraction pattern from the accessor(s) in the // strategy. // Currently we use the substituted type so that we can reconstitute these @@ -5653,7 +5649,7 @@ SILGenFunction::prepareSubscriptIndices(SubscriptDecl *subscript, // Prepare the unevaluated index expression. auto substParams = substFnType->getParams(); - PreparedArguments args(substParams, indexExpr); + PreparedArguments args(substParams, argList); // Now, force it to be evaluated. SmallVector argValues; @@ -5666,11 +5662,11 @@ SILGenFunction::prepareSubscriptIndices(SubscriptDecl *subscript, PreparedArguments result(substParams); ArrayRef remainingArgs = argValues; - for (auto substParam : substParams) { - auto substParamType = substParam.getParameterType()->getCanonicalType(); + for (auto i : indices(substParams)) { + auto substParamType = substParams[i].getParameterType()->getCanonicalType(); auto count = RValue::getRValueSize(substParamType); RValue elt(*this, remainingArgs.slice(0, count), substParamType); - result.add(indexExpr, std::move(elt)); + result.add(argList->getExpr(i), std::move(elt)); remainingArgs = remainingArgs.slice(count); } assert(remainingArgs.empty()); @@ -6178,7 +6174,9 @@ RValue SILGenFunction::emitDynamicSubscriptExpr(DynamicSubscriptExpr *e, SILValue base = managedBase.getValue(); // Emit the index. - RValue index = emitRValue(e->getIndex()); + auto *indexExpr = e->getArgs()->getUnaryExpr(); + assert(indexExpr); + RValue index = emitRValue(indexExpr); // Create the continuation block. SILBasicBlock *contBB = createBasicBlock(); @@ -6214,7 +6212,7 @@ RValue SILGenFunction::emitDynamicSubscriptExpr(DynamicSubscriptExpr *e, // // FIXME: Verify ExtInfo state is correct, not working by accident. CanFunctionType::ExtInfo methodInfo; - FunctionType::Param indexArg(e->getIndex()->getType()->getCanonicalType()); + FunctionType::Param indexArg(indexExpr->getType()->getCanonicalType()); auto methodTy = CanFunctionType::get({indexArg}, valueTy, methodInfo); auto foreignMethodTy = getPartialApplyOfDynamicMethodFormalType(SGM, member, e->getMember()); @@ -6268,7 +6266,7 @@ RValue SILGenFunction::emitDynamicSubscriptExpr(DynamicSubscriptExpr *e, } SmallVector SILGenFunction::emitKeyPathSubscriptOperands( - SubscriptDecl *subscript, SubstitutionMap subs, Expr *indexExpr) { + SubscriptDecl *subscript, SubstitutionMap subs, ArgumentList *argList) { Type interfaceType = subscript->getInterfaceType(); CanFunctionType substFnType = subs ? cast(interfaceType->castTo() @@ -6291,7 +6289,7 @@ SmallVector SILGenFunction::emitKeyPathSubscriptOperands( auto prepared = prepareSubscriptIndices(subscript, subs, // Strategy doesn't matter - AccessStrategy::getStorage(), indexExpr); + AccessStrategy::getStorage(), argList); emitter.emitPreparedArgs(std::move(prepared), origFnType); if (!delayedArgs.empty()) diff --git a/lib/SILGen/SILGenExpr.cpp b/lib/SILGen/SILGenExpr.cpp index 8d55775669f55..2cc28892ae0b9 100644 --- a/lib/SILGen/SILGenExpr.cpp +++ b/lib/SILGen/SILGenExpr.cpp @@ -2524,7 +2524,7 @@ visitObjectLiteralExpr(ObjectLiteralExpr *E, SGFContext C) { AnyFunctionType *fnTy = decl->getMethodInterfaceType() .subst(init.getSubstitutions()) ->getAs(); - PreparedArguments args(fnTy->getParams(), E->getArg()); + PreparedArguments args(fnTy->getParams(), E->getArgs()); return SGF.emitApplyAllocatingInitializer(SILLocation(E), init, std::move(args), E->getType(), C); } @@ -3673,7 +3673,7 @@ RValue RValueEmitter::visitKeyPathExpr(KeyPathExpr *E, SGFContext C) { auto subscript = cast(decl); auto loweredArgs = SGF.emitKeyPathSubscriptOperands( subscript, component.getDeclRef().getSubstitutions(), - component.getIndexExpr()); + component.getSubscriptArgs()); for (auto &arg : loweredArgs) { operands.push_back(arg.forward(SGF)); diff --git a/lib/SILGen/SILGenFunction.h b/lib/SILGen/SILGenFunction.h index 792fea6f59a5b..7a44da8deef31 100644 --- a/lib/SILGen/SILGenFunction.h +++ b/lib/SILGen/SILGenFunction.h @@ -731,11 +731,10 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction /// \returns Lowered index arguments. /// \param subscript - The subscript decl who's arguments are being lowered. /// \param subs - Used to get subscript function type and to substitute generic args. - /// \param indexExpr - An expression holding the indices of the - /// subscript (either a TupleExpr or a ParenExpr). + /// \param argList - The argument list of the subscript. SmallVector emitKeyPathSubscriptOperands(SubscriptDecl *subscript, SubstitutionMap subs, - Expr *indexExpr); + ArgumentList *argList); /// Convert a block to a native function with a thunk. ManagedValue emitBlockToFunc(SILLocation loc, @@ -1366,7 +1365,7 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction PreparedArguments prepareSubscriptIndices(SubscriptDecl *subscript, SubstitutionMap subs, AccessStrategy strategy, - Expr *indices); + ArgumentList *argList); ArgumentSource prepareAccessorBaseArg(SILLocation loc, ManagedValue base, CanType baseFormalType, diff --git a/lib/SILGen/SILGenLValue.cpp b/lib/SILGen/SILGenLValue.cpp index 5794db6982823..5b6bf9b71d887 100644 --- a/lib/SILGen/SILGenLValue.cpp +++ b/lib/SILGen/SILGenLValue.cpp @@ -94,7 +94,8 @@ static void pushWriteback(SILGenFunction &SGF, cleanup.Depth = context.stable_begin(); } -static bool areCertainlyEqualIndices(const Expr *e1, const Expr *e2); +static bool areCertainlyEqualArgumentLists(const ArgumentList *l1, + const ArgumentList *l2); void ExclusiveBorrowFormalAccess::diagnoseConflict( const ExclusiveBorrowFormalAccess &rhs, @@ -168,10 +169,10 @@ void ExclusiveBorrowFormalAccess::diagnoseConflict( if (!lhsStorage->Indices->isObviouslyEqual(*rhsStorage->Indices)) { // If the index value doesn't lower to literally the same SILValue's, // do some fuzzy matching to catch the common case. - if (!lhsStorage->IndexExprForDiagnostics || - !rhsStorage->IndexExprForDiagnostics || - !areCertainlyEqualIndices(lhsStorage->IndexExprForDiagnostics, - rhsStorage->IndexExprForDiagnostics)) + if (!lhsStorage->ArgListForDiagnostics || + !rhsStorage->ArgListForDiagnostics || + !areCertainlyEqualArgumentLists(lhsStorage->ArgListForDiagnostics, + rhsStorage->ArgListForDiagnostics)) return; } @@ -1080,32 +1081,31 @@ static bool isReadNoneFunction(const Expr *e) { return false; } - -/// Given two expressions used as indexes to the same SubscriptDecl (and thus +/// Given two expressions used as arguments to the same SubscriptDecl (and thus /// are guaranteed to have the same AST type) check to see if they are going to /// produce the same value. -static bool areCertainlyEqualIndices(const Expr *e1, const Expr *e2) { +static bool areCertainlyEqualArgs(const Expr *e1, const Expr *e2) { if (e1->getKind() != e2->getKind()) return false; - + // Look through ParenExpr's. if (auto *pe1 = dyn_cast(e1)) { auto *pe2 = cast(e2); - return areCertainlyEqualIndices(pe1->getSubExpr(), pe2->getSubExpr()); + return areCertainlyEqualArgs(pe1->getSubExpr(), pe2->getSubExpr()); } - + // Calls are identical if the callee and operands are identical and we know // that the call is something that is "readnone". if (auto *ae1 = dyn_cast(e1)) { auto *ae2 = cast(e2); - return areCertainlyEqualIndices(ae1->getFn(), ae2->getFn()) && - areCertainlyEqualIndices(ae1->getArg(), ae2->getArg()) && + return areCertainlyEqualArgs(ae1->getFn(), ae2->getFn()) && + areCertainlyEqualArgumentLists(ae1->getArgs(), ae2->getArgs()) && isReadNoneFunction(ae1->getFn()); } - + // TypeExpr's that produce the same metatype type are identical. if (isa(e1)) return true; - + if (auto *dre1 = dyn_cast(e1)) { auto *dre2 = cast(e2); return dre1->getDecl() == dre2->getDecl() && @@ -1127,20 +1127,19 @@ static bool areCertainlyEqualIndices(const Expr *e1, const Expr *e2) { return bl1->getValue() == cast(e2)->getValue(); if (auto *sl1 = dyn_cast(e1)) return sl1->getValue() == cast(e2)->getValue(); - + // Compare tuple expressions. if (auto *te1 = dyn_cast(e1)) { auto *te2 = cast(e2); - // Easy checks: # of elements, trailing closures, element names. + // Easy checks: # of elements, element names. if (te1->getNumElements() != te2->getNumElements() || - te1->hasTrailingClosure() != te2->hasTrailingClosure() || te1->getElementNames() != te2->getElementNames()) { return false; } for (unsigned i = 0, n = te1->getNumElements(); i != n; ++i) { - if (!areCertainlyEqualIndices(te1->getElement(i), te2->getElement(i))) + if (!areCertainlyEqualArgs(te1->getElement(i), te2->getElement(i))) return false; } @@ -1151,6 +1150,23 @@ static bool areCertainlyEqualIndices(const Expr *e1, const Expr *e2) { return false; } +/// Given two argument lists to the same SubscriptDecl (and thus are guaranteed +/// to have the same AST type) check to see if they are going to produce the +/// same value. +static bool areCertainlyEqualArgumentLists(const ArgumentList *l1, + const ArgumentList *l2) { + if (l1->size() != l2->size()) + return false; + + for (auto idx : indices(*l1)) { + if (l1->getLabel(idx) != l2->getLabel(idx)) + return false; + if (!areCertainlyEqualArgs(l1->getExpr(idx), l2->getExpr(idx))) + return false; + } + return true; +} + static LValueOptions getBaseOptions(LValueOptions options, AccessStrategy strategy) { return (strategy.getKind() == AccessStrategy::Storage @@ -1178,8 +1194,8 @@ namespace { // The VarDecl or SubscriptDecl being get/set. AbstractStorageDecl *Storage; - /// The subscript index expression. Useless - Expr *IndexExprForDiagnostics; + /// The subscript argument list. Useless + ArgumentList *ArgListForDiagnostics; PreparedArguments Indices; /// AST type of the base expression, in case the accessor call @@ -1217,10 +1233,10 @@ namespace { AbstractStorageDecl *storage, CanType baseFormalType, LValueTypeData typeData, - Expr *indexExprForDiagnostics, + ArgumentList *argListForDiagnostics, PreparedArguments &&indices) : Base(typeData, kind), Storage(storage), - IndexExprForDiagnostics(indexExprForDiagnostics), + ArgListForDiagnostics(argListForDiagnostics), Indices(std::move(indices)), BaseFormalType(baseFormalType) { @@ -1231,7 +1247,7 @@ namespace { SILLocation loc) : Base(copied.getTypeData(), copied.getKind()), Storage(copied.Storage), - IndexExprForDiagnostics(copied.IndexExprForDiagnostics), + ArgListForDiagnostics(copied.ArgListForDiagnostics), Indices(copied.Indices.copy(SGF, loc)) , BaseFormalType(copied.BaseFormalType) {} @@ -1245,9 +1261,9 @@ namespace { void printBase(raw_ostream &OS, unsigned indent, StringRef name) const { OS.indent(indent) << name << "(" << Storage->getBaseName() << ")"; - if (IndexExprForDiagnostics) { + if (ArgListForDiagnostics) { OS << " subscript_index:\n"; - IndexExprForDiagnostics->dump(OS, 2); + ArgListForDiagnostics->dump(OS, 2); } OS << '\n'; } @@ -1273,11 +1289,11 @@ namespace { bool isSuper, bool isDirectAccessorUse, SubstitutionMap substitutions, CanType baseFormalType, LValueTypeData typeData, - Expr *indexExprForDiagnostics, + ArgumentList *argListForDiagnostics, PreparedArguments &&indices, bool isOnSelfParameter = false, Optional actorIso = None) - : super(kind, decl, baseFormalType, typeData, indexExprForDiagnostics, + : super(kind, decl, baseFormalType, typeData, argListForDiagnostics, std::move(indices)), Accessor(accessor), IsSuper(isSuper), IsDirectAccessorUse(isDirectAccessorUse), @@ -1310,13 +1326,13 @@ namespace { SubstitutionMap substitutions, CanType baseFormalType, LValueTypeData typeData, - Expr *subscriptIndexExpr, + ArgumentList *subscriptArgList, PreparedArguments &&indices, bool isOnSelfParameter, Optional actorIso) : AccessorBasedComponent(GetterSetterKind, decl, accessor, isSuper, isDirectAccessorUse, substitutions, - baseFormalType, typeData, subscriptIndexExpr, + baseFormalType, typeData, subscriptArgList, std::move(indices), isOnSelfParameter, actorIso) { assert(getAccessorDecl()->isGetterOrSetter()); @@ -1649,7 +1665,7 @@ namespace { Optional getAccessedStorage() const override { return AccessedStorage{Storage, IsSuper, Indices.isNull() ? nullptr : &Indices, - IndexExprForDiagnostics }; + ArgListForDiagnostics }; } }; @@ -1670,11 +1686,11 @@ namespace { AccessStrategy writeStrategy, CanType baseFormalType, LValueTypeData typeData, - Expr *indexExprForDiagnostics, + ArgumentList *argListForDiagnostics, PreparedArguments &&indices, bool isOnSelfParameter) : AccessComponent(MaterializeToTemporaryKind, storage, baseFormalType, - typeData, indexExprForDiagnostics, std::move(indices)), + typeData, argListForDiagnostics, std::move(indices)), Substitutions(subs), ReadStrategy(readStrategy), WriteStrategy(writeStrategy), Options(options), IsSuper(isSuper), IsOnSelfParameter(isOnSelfParameter) @@ -1690,7 +1706,7 @@ namespace { Options, ReadStrategy, WriteStrategy, BaseFormalType, getTypeData(), - IndexExprForDiagnostics, + ArgListForDiagnostics, std::move(clonedIndices), IsOnSelfParameter); return std::unique_ptr(clone); @@ -1715,7 +1731,7 @@ namespace { Optional getAccessedStorage() const override { return AccessedStorage{Storage, IsSuper, Indices.isNull() ? nullptr : &Indices, - IndexExprForDiagnostics}; + ArgListForDiagnostics}; } void dump(raw_ostream &OS, unsigned indent) const override { @@ -1739,7 +1755,7 @@ namespace { Options, IsSuper, accessKind, strategy, getSubstFormalType(), std::move(Indices), - IndexExprForDiagnostics); + ArgListForDiagnostics); } else { auto var = cast(Storage); if (base) { @@ -1768,12 +1784,12 @@ namespace { SubstitutionMap substitutions, CanType baseFormalType, LValueTypeData typeData, SILType substFieldType, - Expr *indexExprForDiagnostics, + ArgumentList *argListForDiagnostics, PreparedArguments &&indices, bool isOnSelfParameter) : AccessorBasedComponent(AddressorKind, decl, accessor, isSuper, isDirectAccessorUse, substitutions, baseFormalType, typeData, - indexExprForDiagnostics, std::move(indices), + argListForDiagnostics, std::move(indices), isOnSelfParameter), SubstFieldType(substFieldType) { @@ -1815,19 +1831,19 @@ namespace { AbstractStorageDecl *Storage; bool IsSuper; PreparedArguments PeekedIndices; - Expr *IndexExprForDiagnostics; + ArgumentList *ArgListForDiagnostics; public: EndApplyPseudoComponent(const LValueTypeData &typeData, CleanupHandle endApplyHandle, AbstractStorageDecl *storage, bool isSuper, PreparedArguments &&peekedIndices, - Expr *indexExprForDiagnostics) + ArgumentList *argListForDiagnostics) : WritebackPseudoComponent(typeData), EndApplyHandle(endApplyHandle), Storage(storage), IsSuper(isSuper), PeekedIndices(std::move(peekedIndices)), - IndexExprForDiagnostics(indexExprForDiagnostics) {} + ArgListForDiagnostics(argListForDiagnostics) {} private: void writeback(SILGenFunction &SGF, SILLocation loc, @@ -1849,7 +1865,7 @@ namespace { Optional getAccessedStorage() const override { return AccessedStorage{Storage, IsSuper, PeekedIndices.isNull() ? nullptr : &PeekedIndices, - IndexExprForDiagnostics}; + ArgListForDiagnostics}; } }; } @@ -1862,11 +1878,11 @@ static void pushEndApplyWriteback(SILGenFunction &SGF, SILLocation loc, bool isSuper = false, PreparedArguments &&indices = PreparedArguments(), - Expr *indexExprForDiagnostics = nullptr) { + ArgumentList *argListForDiagnostics = nullptr) { std::unique_ptr component(new EndApplyPseudoComponent(typeData, endApplyHandle, storage, isSuper, std::move(indices), - indexExprForDiagnostics)); + argListForDiagnostics)); pushWriteback(SGF, loc, std::move(component), /*for diagnostics*/ base, MaterializedLValue()); } @@ -1881,13 +1897,13 @@ namespace { bool isSuper, bool isDirectAccessorUse, SubstitutionMap substitutions, CanType baseFormalType, LValueTypeData typeData, - Expr *indexExprForDiagnostics, + ArgumentList *argListForDiagnostics, PreparedArguments &&indices, bool isOnSelfParameter) : AccessorBasedComponent( CoroutineAccessorKind, decl, accessor, isSuper, isDirectAccessorUse, substitutions, baseFormalType, typeData, - indexExprForDiagnostics, std::move(indices), isOnSelfParameter) {} + argListForDiagnostics, std::move(indices), isOnSelfParameter) {} using AccessorBasedComponent::AccessorBasedComponent; @@ -1910,7 +1926,7 @@ namespace { // Push a writeback that ends the access. pushEndApplyWriteback(SGF, loc, endApplyHandle, getTypeData(), base, Storage, IsSuper, std::move(peekedIndices), - IndexExprForDiagnostics); + ArgListForDiagnostics); auto decl = cast(Accessor.getFuncDecl()); @@ -2374,7 +2390,7 @@ void LValue::addMemberComponent(SILGenFunction &SGF, SILLocation loc, AccessStrategy accessStrategy, CanType formalRValueType, PreparedArguments &&indices, - Expr *indexExprForDiagnostics) { + ArgumentList *argListForDiagnostics) { if (auto var = dyn_cast(storage)) { assert(indices.isNull()); addMemberVarComponent(SGF, loc, var, subs, options, isSuper, @@ -2383,7 +2399,7 @@ void LValue::addMemberComponent(SILGenFunction &SGF, SILLocation loc, auto subscript = cast(storage); addMemberSubscriptComponent(SGF, loc, subscript, subs, options, isSuper, accessKind, accessStrategy, formalRValueType, - std::move(indices), indexExprForDiagnostics); + std::move(indices), argListForDiagnostics); } } @@ -3221,7 +3237,7 @@ struct MemberStorageAccessEmitter : AccessEmitter { bool IsOnSelfParameter; // Is self the self parameter in context. CanType BaseFormalType; SubstitutionMap Subs; - Expr *IndexExprForDiagnostics; + ArgumentList *ArgListForDiagnostics; PreparedArguments Indices; // If any, holds the actor we must switch to when performing the access. Optional ActorIso; @@ -3230,13 +3246,13 @@ struct MemberStorageAccessEmitter : AccessEmitter { StorageType *storage, SubstitutionMap subs, bool isSuper, SGFAccessKind accessKind, CanType formalRValueType, LValueOptions options, - LValue &lv, Expr *indexExprForDiagnostics, + LValue &lv, ArgumentList *argListForDiagnostics, PreparedArguments &&indices, bool isSelf = false, Optional actorIso = None) : super(SGF, storage, accessKind, formalRValueType), LV(lv), Options(options), Loc(loc), IsSuper(isSuper), IsOnSelfParameter(isSelf), BaseFormalType(lv.getSubstFormalType()), Subs(subs), - IndexExprForDiagnostics(indexExprForDiagnostics), + ArgListForDiagnostics(argListForDiagnostics), Indices(std::move(indices)), ActorIso(actorIso) {} void emitUsingAddressor(SILDeclRef addressor, bool isDirect, @@ -3247,7 +3263,7 @@ struct MemberStorageAccessEmitter : AccessEmitter { LV.add(Storage, addressor, IsSuper, isDirect, Subs, BaseFormalType, typeData, varStorageType, - IndexExprForDiagnostics, std::move(Indices), + ArgListForDiagnostics, std::move(Indices), IsOnSelfParameter); } @@ -3256,14 +3272,14 @@ struct MemberStorageAccessEmitter : AccessEmitter { assert(!ActorIso); LV.add( Storage, accessor, IsSuper, isDirect, Subs, BaseFormalType, typeData, - IndexExprForDiagnostics, std::move(Indices), IsOnSelfParameter); + ArgListForDiagnostics, std::move(Indices), IsOnSelfParameter); } void emitUsingGetterSetter(SILDeclRef accessor, bool isDirect, LValueTypeData typeData) { LV.add( Storage, accessor, IsSuper, isDirect, Subs, BaseFormalType, typeData, - IndexExprForDiagnostics, std::move(Indices), IsOnSelfParameter, + ArgListForDiagnostics, std::move(Indices), IsOnSelfParameter, ActorIso); } @@ -3273,7 +3289,7 @@ struct MemberStorageAccessEmitter : AccessEmitter { assert(!ActorIso); LV.add( Storage, IsSuper, Subs, Options, readStrategy, writeStrategy, - BaseFormalType, typeData, IndexExprForDiagnostics, std::move(Indices), + BaseFormalType, typeData, ArgListForDiagnostics, std::move(Indices), IsOnSelfParameter); } }; @@ -3386,14 +3402,14 @@ LValue SILGenLValue::visitSubscriptExpr(SubscriptExpr *e, if (e->isImplicitlyAsync()) actorIso = getActorIsolation(decl); - Expr *indexExpr = e->getIndex(); - auto indices = SGF.prepareSubscriptIndices(decl, subs, strategy, indexExpr); + auto *argList = e->getArgs(); + auto indices = SGF.prepareSubscriptIndices(decl, subs, strategy, argList); CanType formalRValueType = getSubstFormalRValueType(e); lv.addMemberSubscriptComponent(SGF, e, decl, subs, options, e->isSuper(), accessKind, strategy, formalRValueType, std::move(indices), - indexExpr, isOnSelfParameter, actorIso); + argList, isOnSelfParameter, actorIso); return lv; } @@ -3493,7 +3509,7 @@ void LValue::addMemberSubscriptComponent(SILGenFunction &SGF, SILLocation loc, AccessStrategy strategy, CanType formalRValueType, PreparedArguments &&indices, - Expr *indexExprForDiagnostics, + ArgumentList *argListForDiagnostics, bool isOnSelfParameter, Optional actorIso) { struct MemberSubscriptAccessEmitter @@ -3505,7 +3521,7 @@ void LValue::addMemberSubscriptComponent(SILGenFunction &SGF, SILLocation loc, llvm_unreachable("subscripts never have storage"); } } emitter(SGF, loc, decl, subs, isSuper, accessKind, formalRValueType, - options, *this, indexExprForDiagnostics, std::move(indices), + options, *this, argListForDiagnostics, std::move(indices), isOnSelfParameter, actorIso); emitter.emitUsingStrategy(strategy); diff --git a/lib/SILOptimizer/Mandatory/DIMemoryUseCollector.cpp b/lib/SILOptimizer/Mandatory/DIMemoryUseCollector.cpp index 721f504d52cfe..281a46bd2a9c1 100644 --- a/lib/SILOptimizer/Mandatory/DIMemoryUseCollector.cpp +++ b/lib/SILOptimizer/Mandatory/DIMemoryUseCollector.cpp @@ -1187,7 +1187,9 @@ static bool isSuperInitUse(SILInstruction *User) { if (!LocExpr || !isa(LocExpr->getFn())) return false; - if (LocExpr->getArg()->isSuperExpr()) + auto *UnaryArg = LocExpr->getArgs()->getUnaryExpr(); + assert(UnaryArg); + if (UnaryArg->isSuperExpr()) return true; // Instead of super_ref_expr, we can also get this for inherited delegating @@ -1195,7 +1197,7 @@ static bool isSuperInitUse(SILInstruction *User) { // (derived_to_base_expr implicit type='C' // (declref_expr type='D' decl='self')) - if (auto *DTB = dyn_cast(LocExpr->getArg())) { + if (auto *DTB = dyn_cast(UnaryArg)) { if (auto *DRE = dyn_cast(DTB->getSubExpr())) { ASTContext &Ctx = DRE->getDecl()->getASTContext(); if (DRE->getDecl()->isImplicit() && diff --git a/lib/SILOptimizer/Mandatory/DiagnoseStaticExclusivity.cpp b/lib/SILOptimizer/Mandatory/DiagnoseStaticExclusivity.cpp index 7cb1be53757ce..4a4dea281a62c 100644 --- a/lib/SILOptimizer/Mandatory/DiagnoseStaticExclusivity.cpp +++ b/lib/SILOptimizer/Mandatory/DiagnoseStaticExclusivity.cpp @@ -401,9 +401,9 @@ canReplaceWithCallToCollectionSwapAt(const BeginAccessInst *Access1, assert(isCallToStandardLibrarySwap(CE, Ctx)); // swap() takes two arguments. - auto *ArgTuple = cast(CE->getArg()); - const Expr *Arg1 = ArgTuple->getElement(0); - const Expr *Arg2 = ArgTuple->getElement(1); + auto *Args = CE->getArgs(); + const Expr *Arg1 = Args->getExpr(0); + const Expr *Arg2 = Args->getExpr(1); if ((Arg1 == InOut1 && Arg2 == InOut2)) { FoundCall = CE; break; @@ -463,17 +463,14 @@ canReplaceWithCallToCollectionSwapAt(const BeginAccessInst *Access1, if (Base1Text != Base2Text) return false; - auto *Index1Paren = dyn_cast(SE1->getIndex()); - if (!Index1Paren) - return false; - - auto *Index2Paren = dyn_cast(SE2->getIndex()); - if (!Index2Paren) + if (!SE1->getArgs()->isUnlabeledUnary() || + !SE2->getArgs()->isUnlabeledUnary()) { return false; + } Base = SE1->getBase(); - Index1 = Index1Paren->getSubExpr(); - Index2 = Index2Paren->getSubExpr(); + Index1 = SE1->getArgs()->getExpr(0); + Index2 = SE2->getArgs()->getExpr(0); return true; } diff --git a/lib/SILOptimizer/Utils/ConstantFolding.cpp b/lib/SILOptimizer/Utils/ConstantFolding.cpp index 65ca711697c8a..cb9974f002b1a 100644 --- a/lib/SILOptimizer/Utils/ConstantFolding.cpp +++ b/lib/SILOptimizer/Utils/ConstantFolding.cpp @@ -205,17 +205,17 @@ constantFoldBinaryWithOverflow(BuiltinInst *BI, llvm::Intrinsic::ID ID, const ApplyExpr *CE = Loc.getAsASTNode(); SourceRange LHSRange, RHSRange; if (CE) { - const auto *Args = dyn_cast_or_null(CE->getArg()); - if (Args && Args->getNumElements() == 2) { + const auto *Args = CE->getArgs(); + if (Args->size() == 2) { // Look through inout types in order to handle += well. - CanType LHSTy = Args->getElement(0)->getType()->getInOutObjectType()-> + CanType LHSTy = Args->getExpr(0)->getType()->getInOutObjectType()-> getCanonicalType(); - CanType RHSTy = Args->getElement(1)->getType()->getCanonicalType(); + CanType RHSTy = Args->getExpr(1)->getType()->getCanonicalType(); if (LHSTy == RHSTy) - OpType = Args->getElement(1)->getType(); + OpType = Args->getExpr(1)->getType(); - LHSRange = Args->getElement(0)->getSourceRange(); - RHSRange = Args->getElement(1)->getSourceRange(); + LHSRange = Args->getExpr(0)->getSourceRange(); + RHSRange = Args->getExpr(1)->getSourceRange(); } } @@ -779,13 +779,8 @@ constantFoldAndCheckIntegerConversions(BuiltinInst *BI, // Eventually we might be able to use SILLocation (when it contains info // about inlined call chains). if (CE) { - if (const TupleType *RTy = CE->getArg()->getType()->getAs()) { - if (RTy->getNumElements() == 1) { - UserSrcTy = RTy->getElementType(0); - UserDstTy = CE->getType(); - } - } else { - UserSrcTy = CE->getArg()->getType(); + if (auto *unaryArg = CE->getArgs()->getUnaryExpr()) { + UserSrcTy = unaryArg->getType(); UserDstTy = CE->getType(); } } else if (auto *ILE = Loc.getAsASTNode()) { diff --git a/lib/Sema/BuilderTransform.cpp b/lib/Sema/BuilderTransform.cpp index 8660d22bd17a2..67b7357a35cd5 100644 --- a/lib/Sema/BuilderTransform.cpp +++ b/lib/Sema/BuilderTransform.cpp @@ -88,8 +88,8 @@ class BuilderClosureVisitor /// Produce a builder call to the given named function with the given /// arguments. - Expr *buildCallIfWanted(SourceLoc loc, - Identifier fnName, ArrayRef args, + Expr *buildCallIfWanted(SourceLoc loc, Identifier fnName, + ArrayRef argExprs, ArrayRef argLabels) { if (!cs) return nullptr; @@ -120,23 +120,24 @@ class BuilderClosureVisitor } cs->setType(typeExpr, MetatypeType::get(builderType)); - SmallVector argLabelLocs; - for (auto i : indices(argLabels)) { - argLabelLocs.push_back(args[i]->getStartLoc()); + SmallVector args; + for (auto i : indices(argExprs)) { + auto *expr = argExprs[i]; + auto label = argLabels.empty() ? Identifier() : argLabels[i]; + auto labelLoc = argLabels.empty() ? SourceLoc() : expr->getStartLoc(); + args.emplace_back(labelLoc, label, expr); } auto memberRef = new (ctx) UnresolvedDotExpr( typeExpr, loc, DeclNameRef(fnName), DeclNameLoc(loc), /*implicit=*/true); memberRef->setFunctionRefKind(FunctionRefKind::SingleApply); - SourceLoc openLoc = args.empty() ? loc : args.front()->getStartLoc(); - SourceLoc closeLoc = args.empty() ? loc : args.back()->getEndLoc(); - Expr *result = CallExpr::create(ctx, memberRef, openLoc, args, - argLabels, argLabelLocs, closeLoc, - /*trailing closures*/{}, - /*implicit*/true); - return result; + auto openLoc = args.empty() ? loc : argExprs.front()->getStartLoc(); + auto closeLoc = args.empty() ? loc : argExprs.back()->getEndLoc(); + + auto *argList = ArgumentList::createImplicit(ctx, openLoc, args, closeLoc); + return CallExpr::createImplicit(ctx, memberRef, argList); } /// Check whether the builder supports the given operation. @@ -653,7 +654,8 @@ class BuilderClosureVisitor auto someRef = new (ctx) UnresolvedDotExpr( optionalTypeExpr, loc, DeclNameRef(ctx.getIdentifier("some")), DeclNameLoc(loc), /*implicit=*/true); - return CallExpr::createImplicit(ctx, someRef, arg, { }); + auto *argList = ArgumentList::forImplicitUnlabeled(ctx, {arg}); + return CallExpr::createImplicit(ctx, someRef, argList); } Expr *buildNoneExpr(SourceLoc endLoc) { @@ -873,10 +875,12 @@ class BuilderClosureVisitor arrayVarRef, endLoc, DeclNameRef(ctx.getIdentifier("append")), DeclNameLoc(endLoc), /*implicit=*/true); arrayAppendRef->setFunctionRefKind(FunctionRefKind::SingleApply); + auto bodyVarRef = buildVarRef(bodyVar, endLoc); - Expr *arrayAppendCall = CallExpr::create( - ctx, arrayAppendRef, endLoc, { bodyVarRef } , { Identifier() }, - { endLoc }, endLoc, /*trailingClosures=*/{}, /*implicit=*/true); + auto *argList = ArgumentList::createImplicit( + ctx, endLoc, {Argument::unlabeled(bodyVarRef)}, endLoc); + Expr *arrayAppendCall = + CallExpr::createImplicit(ctx, arrayAppendRef, argList); arrayAppendCall = cs->generateConstraints(arrayAppendCall, dc); if (!arrayAppendCall) { hadError = true; diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index ba8d844b062e7..37c5a548b6c34 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,17 +5745,10 @@ 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); - - auto oldTrailingClosureIndex = - arg->getUnlabeledTrailingClosureIndexOfPackedArgument(); - Optional newTrailingClosureIndex; + return args; // Determine the parameter bindings that were applied. auto *locatorPtr = cs.getConstraintLocator(locator); @@ -5846,52 +5756,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,22 +5772,15 @@ 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. - if (oldTrailingClosureIndex && *oldTrailingClosureIndex == argIdx) { - assert(!newTrailingClosureIndex); - newTrailingClosureIndex = newArgs.size(); - } - // If the argument type exactly matches, this just works. if (argType->isEqual(param.getPlainType())) { variadicArgs.push_back(arg); @@ -5953,8 +5816,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 +5824,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,17 +5836,13 @@ 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) { - assert(!newTrailingClosureIndex); - 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 +5852,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 +5871,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 +5909,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 +5937,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 +5949,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 +5971,15 @@ 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]; - } + // Write back the rewritten argument to the original argument list. This + // ensures it has the same semantic argument information as the rewritten + // argument list, which may be required by IDE logic. + args->setExpr(argIdx, convertedArg); - // 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); + return ArgumentList::createTypeChecked(ctx, args, newArgs); } static bool isClosureLiteralExpr(Expr *expr) { @@ -6902,15 +6706,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 +7330,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 +7342,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 +7351,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 +7385,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 +7402,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(); - - // Build the argument list expr. - argument = TupleExpr::createImplicit(ctx, {argument}, {argumentLabel}); - cs.setType(argument, - TupleType::get({TupleTypeElt(argumentType, argumentLabel)}, ctx)); + argExpr->setImplicit(); - 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 +7432,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 +7442,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 +7481,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 +7500,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 +7532,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 +7579,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 +7631,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 +7681,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 +7720,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 +7744,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 +7812,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..2d3727567c828 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()->getNumTrailingClosures() != 1) 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->getFirstTrailingClosureIndex(); + 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->isTrailingClosureIndex(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->isTrailingClosureIndex(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->isTrailingClosureIndex(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. `[