diff --git a/include/swift/AST/Expr.h b/include/swift/AST/Expr.h index c9804f29831e3..fac6e211e4caf 100644 --- a/include/swift/AST/Expr.h +++ b/include/swift/AST/Expr.h @@ -295,19 +295,6 @@ class alignas(8) Expr { NumElements : 16 ); - SWIFT_INLINE_BITFIELD_FULL(ArgumentShuffleExpr, ImplicitConversionExpr, 2+16+16+16, - TypeImpact : 2, - : NumPadBits, - NumCallerDefaultArgs : 16, - /// This contains an entry for each element in the Expr type. Each element - /// specifies which index from the SubExpr that the destination element gets. - /// If the element value is DefaultInitialize, then the destination value - /// gets the default initializer for that tuple element value. - NumElementMappings : 16, - /// The arguments that are packed into the variadic element. - NumVariadicArgs : 16 - ); - SWIFT_INLINE_BITFIELD(ForceValueExpr, Expr, 1, ForcedIUO : 1 ); @@ -3020,157 +3007,6 @@ class DestructureTupleExpr final : public ImplicitConversionExpr, } }; -/// ArgumentShuffleExpr - This represents a "complex" argument list of an -/// ApplyExpr, with default arguments or varargs. -/// -/// If hasScalarSource() is true, the subexpression should be treated -/// as if it were implicitly injected into a single-element tuple -/// type. Otherwise, the subexpression is known to have a tuple type. -class ArgumentShuffleExpr final : public ImplicitConversionExpr, - private llvm::TrailingObjects { - friend TrailingObjects; - - size_t numTrailingObjects(OverloadToken) const { - return Bits.ArgumentShuffleExpr.NumCallerDefaultArgs; - } - size_t numTrailingObjects(OverloadToken) const { - return Bits.ArgumentShuffleExpr.NumElementMappings; - } - size_t numTrailingObjects(OverloadToken) const { - return Bits.ArgumentShuffleExpr.NumVariadicArgs; - } - -public: - enum : int { - /// The element mapping value indicating that a field of the destination - /// tuple should be default-initialized. - DefaultInitialize = -1, - /// The element mapping is part of the variadic field. - Variadic = -2, - /// The element mapping value indicating that the field of the - /// destination tuple should be default-initialized with an expression - /// provided by the caller. - /// FIXME: Yet another indication that ArgumentShuffleExpr uses the wrong - /// formulation. - CallerDefaultInitialize = -3 - }; - - enum TypeImpact { - /// The source value is a tuple which is destructured and modified to - /// create the result, which is a tuple. - /// - /// Example: (x: Int) => (x: Int, y: Int = 0). - TupleToTuple, - - /// The source value is a tuple which is destructured and modified to - /// create the result, which is a scalar because it has one element and - /// no labels. - /// - /// Example: () -> (_: Int = 0) - /// Another example: (Int, Int) => (_: Int...) - TupleToScalar, - - /// The source value is an individual value (possibly one with tuple - /// type) which is inserted into a particular position in the result, - /// which is a tuple. - /// - /// Example: (Int) -> (_: Int, y: Int = 0) - ScalarToTuple - - // (ArgumentShuffleExpr are never created for a scalar-to-scalar conversion.) - }; - -private: - /// If we're doing a varargs shuffle, this is the array type to build. - Type VarargsArrayTy; - - /// If there are any default arguments, the owning function - /// declaration. - ConcreteDeclRef DefaultArgsOwner; - - ArgumentShuffleExpr(Expr *subExpr, ArrayRef elementMapping, - TypeImpact typeImpact, - ConcreteDeclRef defaultArgsOwner, - ArrayRef VariadicArgs, - Type VarargsArrayTy, - ArrayRef CallerDefaultArgs, - Type ty) - : ImplicitConversionExpr(ExprKind::ArgumentShuffle, subExpr, ty), - VarargsArrayTy(VarargsArrayTy), DefaultArgsOwner(defaultArgsOwner) { - Bits.ArgumentShuffleExpr.TypeImpact = typeImpact; - Bits.ArgumentShuffleExpr.NumCallerDefaultArgs = CallerDefaultArgs.size(); - Bits.ArgumentShuffleExpr.NumElementMappings = elementMapping.size(); - Bits.ArgumentShuffleExpr.NumVariadicArgs = VariadicArgs.size(); - std::uninitialized_copy(CallerDefaultArgs.begin(), CallerDefaultArgs.end(), - getTrailingObjects()); - std::uninitialized_copy(elementMapping.begin(), elementMapping.end(), - getTrailingObjects()); - std::uninitialized_copy(VariadicArgs.begin(), VariadicArgs.end(), - getTrailingObjects()); - } - -public: - static ArgumentShuffleExpr *create(ASTContext &ctx, Expr *subExpr, - ArrayRef elementMapping, - TypeImpact typeImpact, - ConcreteDeclRef defaultArgsOwner, - ArrayRef VariadicArgs, - Type VarargsArrayTy, - ArrayRef CallerDefaultArgs, - Type ty); - - ArrayRef getElementMapping() const { - return {getTrailingObjects(), - static_cast(Bits.ArgumentShuffleExpr.NumElementMappings)}; - } - - /// What is the type impact of this shuffle? - TypeImpact getTypeImpact() const { - return TypeImpact(Bits.ArgumentShuffleExpr.TypeImpact); - } - - bool isSourceScalar() const { - return getTypeImpact() == ScalarToTuple; - } - - bool isResultScalar() const { - return getTypeImpact() == TupleToScalar; - } - - Type getVarargsArrayType() const { - assert(!VarargsArrayTy.isNull()); - return VarargsArrayTy; - } - Type getVarargsArrayTypeOrNull() const { - return VarargsArrayTy; - } - - /// Retrieve the argument indices for the variadic arguments. - ArrayRef getVariadicArgs() const { - return {getTrailingObjects(), - static_cast(Bits.ArgumentShuffleExpr.NumVariadicArgs)}; - } - - /// Retrieve the owner of the default arguments. - ConcreteDeclRef getDefaultArgsOwner() const { return DefaultArgsOwner; } - - /// Retrieve the caller-defaulted arguments. - ArrayRef getCallerDefaultArgs() const { - return {getTrailingObjects(), - static_cast(Bits.ArgumentShuffleExpr.NumCallerDefaultArgs)}; - } - - /// Retrieve the caller-defaulted arguments. - MutableArrayRef getCallerDefaultArgs() { - return {getTrailingObjects(), - static_cast(Bits.ArgumentShuffleExpr.NumCallerDefaultArgs)}; - } - - static bool classof(const Expr *E) { - return E->getKind() == ExprKind::ArgumentShuffle; - } -}; - /// LoadExpr - Turn an l-value into an r-value by performing a "load" /// operation. This operation may actually be a logical operation, /// i.e. one implemented using a call to a potentially user-defined @@ -4021,7 +3857,7 @@ class DynamicTypeExpr : public Expr { /// Opaque value expressions occur when a particular value within the AST /// needs to be re-used without being re-evaluated or for a value that is /// a placeholder. OpaqueValueExpr nodes are introduced by some other AST -/// node (say, a \c DynamicMemberRefExpr) and can only be used within the +/// node (say, an \c OpenExistentialExpr) and can only be used within the /// subexpressions of that AST node. class OpaqueValueExpr : public Expr { SourceLoc Loc; @@ -4037,6 +3873,82 @@ class OpaqueValueExpr : public Expr { } }; +/// An expression referring to a default argument left unspecified at the +/// call site. +/// +/// A DefaultArgumentExpr must only appear as a direct child of a +/// ParenExpr or a TupleExpr that is itself a call argument. +class DefaultArgumentExpr final : public Expr { + /// The owning declaration. + ConcreteDeclRef DefaultArgsOwner; + + /// The caller parameter index. + unsigned ParamIndex; + + /// The source location of the argument list. + SourceLoc Loc; + +public: + explicit DefaultArgumentExpr(ConcreteDeclRef defaultArgsOwner, unsigned paramIndex, + SourceLoc loc, Type Ty) + : Expr(ExprKind::DefaultArgument, /*Implicit=*/true, Ty), + DefaultArgsOwner(defaultArgsOwner), ParamIndex(paramIndex), Loc(loc) { } + + SourceRange getSourceRange() const { + return Loc; + } + + ConcreteDeclRef getDefaultArgsOwner() const { + return DefaultArgsOwner; + } + + unsigned getParamIndex() const { + return ParamIndex; + } + + static bool classof(const Expr *E) { + return E->getKind() == ExprKind::DefaultArgument; + } +}; + +/// An expression referring to a caller-side default argument left unspecified +/// at the call site. +/// +/// A CallerDefaultArgumentExpr must only appear as a direct child of a +/// ParenExpr or a TupleExpr that is itself a call argument. +/// +/// FIXME: This only exists to distinguish caller default arguments from arguments +/// that were specified at the call site. Once we remove SanitizeExpr, we can remove +/// this hack too. +class CallerDefaultArgumentExpr final : public Expr { + /// The expression that is evaluated to produce the default argument value. + Expr *SubExpr; + + /// The source location of the argument list. + SourceLoc Loc; + +public: + explicit CallerDefaultArgumentExpr(Expr *subExpr, SourceLoc loc, Type Ty) + : Expr(ExprKind::CallerDefaultArgument, /*Implicit=*/true, Ty), + SubExpr(subExpr), Loc(loc) { } + + SourceRange getSourceRange() const { + return Loc; + } + + Expr *getSubExpr() const { + return SubExpr; + } + + void setSubExpr(Expr *subExpr) { + SubExpr = subExpr; + } + + static bool classof(const Expr *E) { + return E->getKind() == ExprKind::CallerDefaultArgument; + } +}; + /// ApplyExpr - Superclass of various function calls, which apply an argument to /// a function to get a result. class ApplyExpr : public Expr { @@ -4047,8 +3959,7 @@ class ApplyExpr : public Expr { llvm::PointerIntPair ArgAndIsSuper; /// 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, \c TupleExpr, or - /// \c ArgumentShuffleExpr. + /// subclasses, this means it is a \c ParenExpr or \c TupleExpr. bool validateArg(Expr *e) const; protected: @@ -4112,7 +4023,7 @@ class ApplyExpr : public Expr { E->getKind() <= ExprKind::Last_ApplyExpr; } }; - + /// CallExpr - Application of an argument to a function, which occurs /// syntactically through juxtaposition with a TupleExpr whose /// leading '(' is unspaced. @@ -5428,7 +5339,7 @@ inline bool ApplyExpr::validateArg(Expr *e) const { else if (isa(this)) return isa(e); else - return isa(e) || isa(e) || isa(e); + return isa(e) || isa(e); } inline Expr *const *CollectionExpr::getTrailingObjectsPointer() const { diff --git a/include/swift/AST/ExprNodes.def b/include/swift/AST/ExprNodes.def index c5d6866f5f10c..7c5225c916970 100644 --- a/include/swift/AST/ExprNodes.def +++ b/include/swift/AST/ExprNodes.def @@ -126,6 +126,8 @@ EXPR(VarargExpansion, Expr) EXPR(DynamicType, Expr) EXPR(RebindSelfInConstructor, Expr) EXPR(OpaqueValue, Expr) +EXPR(DefaultArgument, Expr) +EXPR(CallerDefaultArgument, Expr) EXPR(BindOptional, Expr) EXPR(OptionalEvaluation, Expr) EXPR(ForceValue, Expr) @@ -144,7 +146,6 @@ ABSTRACT_EXPR(Apply, Expr) ABSTRACT_EXPR(ImplicitConversion, Expr) EXPR(Load, ImplicitConversionExpr) EXPR(DestructureTuple, ImplicitConversionExpr) - EXPR(ArgumentShuffle, ImplicitConversionExpr) EXPR(UnresolvedTypeConversion, ImplicitConversionExpr) EXPR(FunctionConversion, ImplicitConversionExpr) EXPR(CovariantFunctionConversion, ImplicitConversionExpr) diff --git a/include/swift/Sema/IDETypeChecking.h b/include/swift/Sema/IDETypeChecking.h index f10b06b0561bd..e1d7bccd11273 100644 --- a/include/swift/Sema/IDETypeChecking.h +++ b/include/swift/Sema/IDETypeChecking.h @@ -202,6 +202,25 @@ namespace swift { /// the decl context. bool resolveProtocolNames(DeclContext *DC, ArrayRef names, llvm::MapVector &result); + + /// 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; + bool hasTrailingClosure = false; + }; + + /// 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); } #endif diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index a5fd17df09951..2ecc190a3014c 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -2156,42 +2156,6 @@ class PrintExpr : public ExprVisitor { printRec(E->getResultExpr()); PrintWithColorRAII(OS, ParenthesisColor) << ')'; } - void visitArgumentShuffleExpr(ArgumentShuffleExpr *E) { - printCommon(E, "argument_shuffle_expr"); - switch (E->getTypeImpact()) { - case ArgumentShuffleExpr::ScalarToTuple: - OS << " scalar_to_tuple"; - break; - case ArgumentShuffleExpr::TupleToTuple: - OS << " tuple_to_tuple"; - break; - case ArgumentShuffleExpr::TupleToScalar: - OS << " tuple_to_scalar"; - break; - } - OS << " elements=["; - for (unsigned i = 0, e = E->getElementMapping().size(); i != e; ++i) { - if (i) OS << ", "; - OS << E->getElementMapping()[i]; - } - OS << "]"; - OS << " variadic_sources=["; - interleave(E->getVariadicArgs(), - [&](unsigned source) { - OS << source; - }, - [&] { OS << ", "; }); - OS << "]"; - - if (auto defaultArgsOwner = E->getDefaultArgsOwner()) { - OS << " default_args_owner="; - defaultArgsOwner.dump(OS); - } - - OS << "\n"; - printRec(E->getSubExpr()); - PrintWithColorRAII(OS, ParenthesisColor) << ')'; - } void visitUnresolvedTypeConversionExpr(UnresolvedTypeConversionExpr *E) { printCommon(E, "unresolvedtype_conversion_expr") << '\n'; printRec(E->getSubExpr()); @@ -2454,6 +2418,20 @@ class PrintExpr : public ExprVisitor { PrintWithColorRAII(OS, ParenthesisColor) << ')'; } + void visitDefaultArgumentExpr(DefaultArgumentExpr *E) { + printCommon(E, "default_argument_expr"); + OS << " default_args_owner="; + E->getDefaultArgsOwner().dump(OS); + OS << " param=" << E->getParamIndex(); + PrintWithColorRAII(OS, ParenthesisColor) << ')'; + } + + void visitCallerDefaultArgumentExpr(CallerDefaultArgumentExpr *E) { + printCommon(E, "caller_default_argument_expr"); + printRec(E->getSubExpr()); + PrintWithColorRAII(OS, ParenthesisColor) << ')'; + } + void printArgumentLabels(ArrayRef argLabels) { PrintWithColorRAII(OS, ArgumentsColor) << " arg_labels="; for (auto label : argLabels) { diff --git a/lib/AST/ASTVerifier.cpp b/lib/AST/ASTVerifier.cpp index 1248b281a5c06..695ee774624ff 100644 --- a/lib/AST/ASTVerifier.cpp +++ b/lib/AST/ASTVerifier.cpp @@ -1729,12 +1729,6 @@ class Verifier : public ASTWalker { } }; - // If we have an argument shuffle, strip it off. We want to visit the - // underlying paren or tuple expr. - if (auto *ArgShuffle = dyn_cast(Arg)) { - Arg = ArgShuffle->getSubExpr(); - } - if (auto *ParentExprArg = dyn_cast(Arg)) { return handleSubExpr(ParentExprArg->getSubExpr()); } @@ -2039,66 +2033,7 @@ class Verifier : public ASTWalker { verifyCheckedBase(E); } - - void verifyChecked(ArgumentShuffleExpr *E) { - PrettyStackTraceExpr debugStack(Ctx, "verifying ArgumentShuffleExpr", E); - - auto getSubElementType = [&](unsigned i) { - if (E->isSourceScalar()) { - assert(i == 0); - return E->getSubExpr()->getType(); - } else { - return (E->getSubExpr()->getType()->castTo() - ->getElementType(i)); - } - }; - /// Retrieve the ith element type from the resulting tuple type. - auto getOuterElementType = [&](unsigned i) -> Type { - if (E->isResultScalar()) { - assert(i == 0); - return E->getType()->getWithoutParens(); - } else { - return E->getType()->castTo()->getElementType(i); - } - }; - - Type varargsType; - unsigned callerDefaultArgIndex = 0; - for (unsigned i = 0, e = E->getElementMapping().size(); i != e; ++i) { - int subElem = E->getElementMapping()[i]; - if (subElem == ArgumentShuffleExpr::DefaultInitialize) - continue; - if (subElem == ArgumentShuffleExpr::Variadic) { - varargsType = (E->getType()->castTo() - ->getElement(i).getVarargBaseTy()); - break; - } - if (subElem == ArgumentShuffleExpr::CallerDefaultInitialize) { - auto init = E->getCallerDefaultArgs()[callerDefaultArgIndex++]; - if (!getOuterElementType(i)->isEqual(init->getType())) { - Out << "Type mismatch in ArgumentShuffleExpr\n"; - abort(); - } - continue; - } - if (!getOuterElementType(i)->isEqual(getSubElementType(subElem))) { - Out << "Type mismatch in ArgumentShuffleExpr\n"; - abort(); - } - } - if (varargsType) { - for (auto sourceIdx : E->getVariadicArgs()) { - if (!getSubElementType(sourceIdx)->isEqual(varargsType)) { - Out << "Vararg type mismatch in ArgumentShuffleExpr\n"; - abort(); - } - } - } - - verifyCheckedBase(E); - } - void verifyChecked(DynamicTypeExpr *E) { PrettyStackTraceExpr debugStack(Ctx, "verifying DynamicTypeExpr", E); diff --git a/lib/AST/ASTWalker.cpp b/lib/AST/ASTWalker.cpp index e299778e5a260..6c64e646c20d1 100644 --- a/lib/AST/ASTWalker.cpp +++ b/lib/AST/ASTWalker.cpp @@ -443,6 +443,17 @@ class Traversal : public ASTVisitorgetSubExpr())) { + E->setSubExpr(subExpr); + return E; + } + + return nullptr; + } + Expr *visitInterpolatedStringLiteralExpr(InterpolatedStringLiteralExpr *E) { HANDLE_SEMANTIC_EXPR(E); @@ -655,23 +666,6 @@ class Traversal : public ASTVisitorgetSubExpr())) { - E->setSubExpr(E2); - } else { - return nullptr; - } - - for (auto &defaultArg : E->getCallerDefaultArgs()) { - if (Expr *newDefaultArg = doIt(defaultArg)) - defaultArg = newDefaultArg; - else - return nullptr; - } - - return E; - } - Expr *visitTryExpr(TryExpr *E) { if (Expr *E2 = doIt(E->getSubExpr())) { E->setSubExpr(E2); diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 98db5ba25aa1c..76e26b1f36854 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -308,6 +308,9 @@ ConcreteDeclRef Expr::getReferencedDecl() const { PASS_THROUGH_REFERENCE(RebindSelfInConstructor, getSubExpr); NO_REFERENCE(OpaqueValue); + NO_REFERENCE(DefaultArgument); + NO_REFERENCE(CallerDefaultArgument); + PASS_THROUGH_REFERENCE(BindOptional, getSubExpr); PASS_THROUGH_REFERENCE(OptionalEvaluation, getSubExpr); PASS_THROUGH_REFERENCE(ForceValue, getSubExpr); @@ -323,7 +326,6 @@ ConcreteDeclRef Expr::getReferencedDecl() const { PASS_THROUGH_REFERENCE(ConstructorRefCall, getFn); PASS_THROUGH_REFERENCE(Load, getSubExpr); NO_REFERENCE(DestructureTuple); - NO_REFERENCE(ArgumentShuffle); NO_REFERENCE(UnresolvedTypeConversion); PASS_THROUGH_REFERENCE(FunctionConversion, getSubExpr); PASS_THROUGH_REFERENCE(CovariantFunctionConversion, getSubExpr); @@ -612,6 +614,8 @@ bool Expr::canAppendPostfixExpression(bool appendingPostfixOperator) const { case ExprKind::RebindSelfInConstructor: case ExprKind::OpaqueValue: + case ExprKind::DefaultArgument: + case ExprKind::CallerDefaultArgument: case ExprKind::BindOptional: case ExprKind::OptionalEvaluation: return false; @@ -638,7 +642,6 @@ bool Expr::canAppendPostfixExpression(bool appendingPostfixOperator) const { case ExprKind::Load: case ExprKind::DestructureTuple: - case ExprKind::ArgumentShuffle: case ExprKind::UnresolvedTypeConversion: case ExprKind::FunctionConversion: case ExprKind::CovariantFunctionConversion: @@ -1343,24 +1346,6 @@ DestructureTupleExpr::create(ASTContext &ctx, srcExpr, dstExpr, ty); } -ArgumentShuffleExpr *ArgumentShuffleExpr::create(ASTContext &ctx, - Expr *subExpr, - ArrayRef elementMapping, - TypeImpact typeImpact, - ConcreteDeclRef defaultArgsOwner, - ArrayRef VariadicArgs, - Type VarargsArrayTy, - ArrayRef CallerDefaultArgs, - Type ty) { - auto size = totalSizeToAlloc(CallerDefaultArgs.size(), - elementMapping.size(), - VariadicArgs.size()); - auto mem = ctx.Allocate(size, alignof(ArgumentShuffleExpr)); - return ::new(mem) ArgumentShuffleExpr(subExpr, elementMapping, typeImpact, - defaultArgsOwner, VariadicArgs, - VarargsArrayTy, CallerDefaultArgs, ty); -} - SourceRange TupleExpr::getSourceRange() const { SourceLoc start = SourceLoc(); SourceLoc end = SourceLoc(); diff --git a/lib/IDE/ExprContextAnalysis.cpp b/lib/IDE/ExprContextAnalysis.cpp index 523aaaf1d9486..f6c8d883b286a 100644 --- a/lib/IDE/ExprContextAnalysis.cpp +++ b/lib/IDE/ExprContextAnalysis.cpp @@ -311,7 +311,7 @@ class ExprParentFinder : public ASTWalker { }; /// Collect function (or subscript) members with the given \p name on \p baseTy. -void collectPossibleCalleesByQualifiedLookup( +static void collectPossibleCalleesByQualifiedLookup( DeclContext &DC, Type baseTy, DeclBaseName name, SmallVectorImpl &candidates) { @@ -358,7 +358,7 @@ void collectPossibleCalleesByQualifiedLookup( /// Collect function (or subscript) members with the given \p name on /// \p baseExpr expression. -void collectPossibleCalleesByQualifiedLookup( +static void collectPossibleCalleesByQualifiedLookup( DeclContext &DC, Expr *baseExpr, DeclBaseName name, SmallVectorImpl &candidates) { ConcreteDeclRef ref = nullptr; @@ -374,7 +374,7 @@ void collectPossibleCalleesByQualifiedLookup( } /// For the given \c callExpr, collect possible callee types and declarations. -bool collectPossibleCalleesForApply( +static bool collectPossibleCalleesForApply( DeclContext &DC, ApplyExpr *callExpr, SmallVectorImpl &candidates) { auto *fnExpr = callExpr->getFn(); @@ -421,7 +421,7 @@ bool collectPossibleCalleesForApply( /// For the given \c subscriptExpr, collect possible callee types and /// declarations. -bool collectPossibleCalleesForSubscript( +static bool collectPossibleCalleesForSubscript( DeclContext &DC, SubscriptExpr *subscriptExpr, SmallVectorImpl &candidates) { if (subscriptExpr->hasDecl()) { @@ -438,14 +438,11 @@ bool collectPossibleCalleesForSubscript( return !candidates.empty(); } -/// Get index of \p CCExpr in \p Args. \p Args is usually a \c TupleExpr, -/// \c ParenExpr, or a \c ArgumentShuffleExpr. +/// Get index of \p CCExpr in \p Args. \p Args is usually a \c TupleExpr +/// or \c ParenExpr. /// \returns \c true if success, \c false if \p CCExpr is not a part of \p Args. -bool getPositionInArgs(DeclContext &DC, Expr *Args, Expr *CCExpr, - unsigned &Position, bool &HasName) { - if (auto ASE = dyn_cast(Args)) - Args = ASE->getSubExpr(); - +static bool getPositionInArgs(DeclContext &DC, Expr *Args, Expr *CCExpr, + unsigned &Position, bool &HasName) { if (isa(Args)) { HasName = false; Position = 0; @@ -468,38 +465,6 @@ bool getPositionInArgs(DeclContext &DC, Expr *Args, Expr *CCExpr, return false; } -/// Translate argument index in \p Args to parameter index. -/// Does nothing unless \p Args is \c ArgumentShuffleExpr. -bool translateArgIndexToParamIndex(Expr *Args, unsigned &Position, - bool &HasName) { - auto ASE = dyn_cast(Args); - if (!ASE) - return true; - - auto mapping = ASE->getElementMapping(); - for (unsigned destIdx = 0, e = mapping.size(); destIdx != e; ++destIdx) { - auto srcIdx = mapping[destIdx]; - if (srcIdx == (signed)Position) { - Position = destIdx; - return true; - } - if (srcIdx == ArgumentShuffleExpr::Variadic && - llvm::is_contained(ASE->getVariadicArgs(), Position)) { - // The arg is a part of variadic args. - Position = destIdx; - HasName = false; - if (auto Args = dyn_cast(ASE->getSubExpr())) { - // Check if the first variadiac argument has the label. - auto firstVarArgIdx = ASE->getVariadicArgs().front(); - HasName = Args->getElementNameLoc(firstVarArgIdx).isValid(); - } - return true; - } - } - - return false; -} - /// Given an expression and its context, the analyzer tries to figure out the /// expected type of the expression by analyzing its context. class ExprContextAnalyzer { @@ -546,8 +511,6 @@ class ExprContextAnalyzer { bool HasName; if (!getPositionInArgs(*DC, Arg, ParsedExpr, Position, HasName)) return false; - if (!translateArgIndexToParamIndex(Arg, Position, HasName)) - return false; // Collect possible types (or labels) at the position. { @@ -756,7 +719,7 @@ class ExprContextAnalyzer { auto ParentE = Parent.getAsExpr(); return !ParentE || (!isa(ParentE) && !isa(ParentE) && - !isa(ParentE) && !isa(ParentE)); + !isa(ParentE)); } case ExprKind::Closure: { // Note: we cannot use hasSingleExpressionBody, because we explicitly diff --git a/lib/IDE/Refactoring.cpp b/lib/IDE/Refactoring.cpp index 87121278406f9..0100acccee680 100644 --- a/lib/IDE/Refactoring.cpp +++ b/lib/IDE/Refactoring.cpp @@ -27,6 +27,7 @@ #include "swift/Frontend/Frontend.h" #include "swift/Index/Index.h" #include "swift/Parse/Lexer.h" +#include "swift/Sema/IDETypeChecking.h" #include "swift/Subsystems.h" #include "clang/Rewrite/Core/RewriteBuffer.h" #include "llvm/ADT/StringSet.h" @@ -2856,8 +2857,6 @@ static CallExpr *findTrailingClosureTarget(SourceManager &SM, if (!Args) return nullptr; Expr *LastArg; - if (auto *ASE = dyn_cast(Args)) - Args = ASE->getSubExpr(); if (auto *PE = dyn_cast(Args)) { LastArg = PE->getSubExpr(); } else { @@ -2885,33 +2884,24 @@ bool RefactoringActionTrailingClosure::performChange() { auto *CE = findTrailingClosureTarget(SM, CursorInfo); if (!CE) return true; - Expr *Args = CE->getArg(); - if (auto *ASE = dyn_cast(Args)) - Args = ASE->getSubExpr(); + Expr *Arg = CE->getArg(); Expr *ClosureArg = nullptr; Expr *PrevArg = nullptr; - SourceLoc LPLoc, RPLoc; - if (auto *PE = dyn_cast(Args)) { - ClosureArg = PE->getSubExpr(); - LPLoc = PE->getLParenLoc(); - RPLoc = PE->getRParenLoc(); - } else { - auto *TE = cast(Args); - auto NumArgs = TE->getNumElements(); - if (NumArgs == 0) - return true; - LPLoc = TE->getLParenLoc(); - RPLoc = TE->getRParenLoc(); - ClosureArg = TE->getElement(NumArgs - 1); - if (NumArgs > 1) - PrevArg = TE->getElement(NumArgs - 2); - } + OriginalArgumentList ArgList = getOriginalArgumentList(Arg); + + auto NumArgs = ArgList.args.size(); + if (NumArgs == 0) + return true; + ClosureArg = ArgList.args[NumArgs - 1]; + if (NumArgs > 1) + PrevArg = ArgList.args[NumArgs - 2]; + if (auto *ICE = dyn_cast(ClosureArg)) ClosureArg = ICE->getSyntacticSubExpr(); - if (LPLoc.isInvalid() || RPLoc.isInvalid()) + if (ArgList.lParenLoc.isInvalid() || ArgList.rParenLoc.isInvalid()) return true; // Replace: @@ -2925,14 +2915,14 @@ bool RefactoringActionTrailingClosure::performChange() { EditConsumer.accept(SM, PreRange, ") "); } else { CharSourceRange PreRange( - SM, LPLoc, ClosureArg->getStartLoc()); + SM, ArgList.lParenLoc, ClosureArg->getStartLoc()); EditConsumer.accept(SM, PreRange, " "); } // Remove original closing paren. CharSourceRange PostRange( SM, Lexer::getLocForEndOfToken(SM, ClosureArg->getEndLoc()), - Lexer::getLocForEndOfToken(SM, RPLoc)); + Lexer::getLocForEndOfToken(SM, ArgList.rParenLoc)); EditConsumer.remove(SM, PostRange); return false; } diff --git a/lib/SILGen/ASTVisitor.h b/lib/SILGen/ASTVisitor.h index 3f0429aa02dfd..e98f9b7bfa1a6 100644 --- a/lib/SILGen/ASTVisitor.h +++ b/lib/SILGen/ASTVisitor.h @@ -56,6 +56,15 @@ class ASTVisitor : public swift::ASTVisitor(this)->visit(E->getSubExpr(), + std::forward(AA)...); + } + ExprRetTy visitVarargExpansionExpr(VarargExpansionExpr *E, Args... AA) { return static_cast(this)->visit(E->getSubExpr(), std::forward(AA)...); diff --git a/lib/SILGen/ArgumentSource.cpp b/lib/SILGen/ArgumentSource.cpp index e3bbbf789ca65..8969b34a81461 100644 --- a/lib/SILGen/ArgumentSource.cpp +++ b/lib/SILGen/ArgumentSource.cpp @@ -251,10 +251,7 @@ void ArgumentSource::dump(raw_ostream &out, unsigned indent) const { PreparedArguments::PreparedArguments( ArrayRef params, Expr *arg) : PreparedArguments(params) { - if (isa(arg)) { - IsScalar = true; - addArbitrary(arg); - } else if (auto *PE = dyn_cast(arg)) + if (auto *PE = dyn_cast(arg)) addArbitrary(PE->getSubExpr()); else if (auto *TE = dyn_cast(arg)) { for (auto *elt : TE->getElements()) @@ -271,7 +268,6 @@ PreparedArguments::copy(SILGenFunction &SGF, SILLocation loc) const { assert(isValid()); PreparedArguments result(getParams()); - result.IsScalar = isScalar(); for (auto &elt : Arguments) { assert(elt.isRValue()); result.add(elt.getKnownRValueLocation(), @@ -320,7 +316,6 @@ PreparedArguments PreparedArguments::copyForDiagnostics() const { assert(isValid()); PreparedArguments result(getParams()); - result.IsScalar = isScalar(); for (auto &arg : Arguments) { result.Arguments.push_back(arg.copyForDiagnostics()); } diff --git a/lib/SILGen/ArgumentSource.h b/lib/SILGen/ArgumentSource.h index b856a15f15710..f9e7399acee0d 100644 --- a/lib/SILGen/ArgumentSource.h +++ b/lib/SILGen/ArgumentSource.h @@ -172,6 +172,25 @@ class ArgumentSource { bool isRValue() const & { return StoredKind == Kind::RValue; } bool isLValue() const & { return StoredKind == Kind::LValue; } + bool isDefaultArg() const { + switch (StoredKind) { + case Kind::Invalid: + llvm_unreachable("argument source is invalid"); + case Kind::RValue: + case Kind::LValue: + return false; + case Kind::Expr: + return isa(asKnownExpr()); + } + llvm_unreachable("bad kind"); + } + + /// Return the default argument owner and parameter index, consuming + /// the argument source. Will assert if this is not a default argument. + DefaultArgumentExpr *asKnownDefaultArg() && { + return cast(std::move(*this).asKnownExpr()); + } + /// Given that this source is storing an RValue, extract and clear /// that value. RValue &&asKnownRValue(SILGenFunction &SGF) && { @@ -261,12 +280,11 @@ class ArgumentSource { class PreparedArguments { SmallVector Params; std::vector Arguments; - unsigned IsScalar : 1; unsigned IsNull : 1; public: - PreparedArguments() : IsScalar(false), IsNull(true) {} + PreparedArguments() : IsNull(true) {} explicit PreparedArguments(ArrayRef params) - : IsScalar(false), IsNull(true) { + : IsNull(true) { emplace(params); } @@ -279,10 +297,9 @@ class PreparedArguments { PreparedArguments(PreparedArguments &&other) : Params(std::move(other.Params)), Arguments(std::move(other.Arguments)), - IsScalar(other.IsScalar), IsNull(other.IsNull) {} + IsNull(other.IsNull) {} PreparedArguments &operator=(PreparedArguments &&other) { Params = std::move(other.Params); - IsScalar = other.IsScalar; Arguments = std::move(other.Arguments); IsNull = other.IsNull; other.IsNull = true; @@ -297,8 +314,6 @@ class PreparedArguments { /// Returns true if this is a non-null and completed argument list. bool isValid() const { assert(!isNull()); - if (IsScalar) - return Arguments.size() == 1; return Arguments.size() == Params.size(); } @@ -308,12 +323,6 @@ class PreparedArguments { return Params; } - /// Is this a single-argument list? Note that the argument might be a tuple. - bool isScalar() const { - assert(!isNull()); - return IsScalar; - } - MutableArrayRef getSources() && { assert(isValid()); return Arguments; @@ -323,7 +332,6 @@ class PreparedArguments { void emplace(ArrayRef params) { assert(isNull()); Params.append(params.begin(), params.end()); - IsScalar = false; IsNull = false; } diff --git a/lib/SILGen/SILGenApply.cpp b/lib/SILGen/SILGenApply.cpp index efd687c827698..15ff0c3e7c676 100644 --- a/lib/SILGen/SILGenApply.cpp +++ b/lib/SILGen/SILGenApply.cpp @@ -2601,89 +2601,7 @@ Expr *ArgumentSource::findStorageReferenceExprForBorrow() && { namespace { -/// A destination for an argument other than just "onto to the end -/// of the arguments lists". -/// -/// This allows us to re-use the argument expression emitter for -/// some weird cases, like a shuffled tuple where some of the -/// arguments are going into a varargs array. -struct ArgSpecialDest { - VarargsInfo *SharedInfo; - unsigned Index : 32; - CleanupHandle Cleanup; - - ArgSpecialDest() : SharedInfo(nullptr) {} - explicit ArgSpecialDest(VarargsInfo &info, unsigned index) - : SharedInfo(&info), Index(index) {} - - // Reference semantics: need to preserve the cleanup handle. - ArgSpecialDest(const ArgSpecialDest &) = delete; - ArgSpecialDest &operator=(const ArgSpecialDest &) = delete; - ArgSpecialDest(ArgSpecialDest &&other) - : SharedInfo(other.SharedInfo), Index(other.Index), - Cleanup(other.Cleanup) { - other.SharedInfo = nullptr; - } - ArgSpecialDest &operator=(ArgSpecialDest &&other) { - assert(!isValid() && "overwriting valid special destination!"); - SharedInfo = other.SharedInfo; - Index = other.Index; - Cleanup = other.Cleanup; - other.SharedInfo = nullptr; - return *this; - } - - ~ArgSpecialDest() { - assert(!isValid() && "failed to deactivate special dest"); - } - - /// Is this a valid special destination? - bool isValid() const { return SharedInfo != nullptr; } - - /// Fill this special destination with a value. - void fill(SILGenFunction &SGF, ArgumentSource &&arg, - AbstractionPattern _unused_origType, - SILType loweredSubstParamType) { - assert(isValid() && "filling an invalid destination"); - - SILLocation loc = arg.getLocation(); - auto destAddr = SharedInfo->getBaseAddress(); - if (Index != 0) { - SILValue index = SGF.B.createIntegerLiteral(loc, - SILType::getBuiltinWordType(SGF.getASTContext()), Index); - destAddr = SGF.B.createIndexAddr(loc, destAddr, index); - } - - assert(destAddr->getType() == loweredSubstParamType.getAddressType()); - - auto &destTL = SharedInfo->getBaseTypeLowering(); - Cleanup = - SGF.enterDormantFormalAccessTemporaryCleanup(destAddr, loc, destTL); - - TemporaryInitialization init(destAddr, Cleanup); - std::move(arg).forwardInto(SGF, SharedInfo->getBaseAbstractionPattern(), - &init, destTL); - } - - /// Deactivate this special destination. Must always be called - /// before destruction. - void deactivate(SILGenFunction &SGF) { - assert(isValid() && "deactivating an invalid destination"); - if (Cleanup.isValid()) - SGF.Cleanups.forwardCleanup(Cleanup); - SharedInfo = nullptr; - } -}; - -using ArgSpecialDestArray = MutableArrayRef; - -class ArgumentShuffleEmitter; - class ArgEmitter { - // TODO: Refactor out the parts of ArgEmitter needed by ArgumentShuffleEmitter - // into its own "context struct". - friend class ArgumentShuffleEmitter; - SILGenFunction &SGF; SILFunctionTypeRepresentation Rep; bool IsYield; @@ -2697,24 +2615,39 @@ class ArgEmitter { /// in order to a "hole" (a null value) in Args. SmallVectorImpl &DelayedArguments; - Optional SpecialDests; public: ArgEmitter(SILGenFunction &SGF, SILFunctionTypeRepresentation Rep, bool isYield, bool isForCoroutine, ClaimedParamsRef paramInfos, SmallVectorImpl &args, SmallVectorImpl &delayedArgs, const Optional &foreignError, - ImportAsMemberStatus foreignSelf, - Optional specialDests = None) + ImportAsMemberStatus foreignSelf) : SGF(SGF), Rep(Rep), IsYield(isYield), IsForCoroutine(isForCoroutine), ForeignError(foreignError), ForeignSelf(foreignSelf), - ParamInfos(paramInfos), Args(args), DelayedArguments(delayedArgs), - SpecialDests(specialDests) { - assert(!specialDests || specialDests->size() == paramInfos.size()); - } + ParamInfos(paramInfos), Args(args), DelayedArguments(delayedArgs) {} // origParamType is a parameter type. void emitSingleArg(ArgumentSource &&arg, AbstractionPattern origParamType) { + // If this is default argument, prepare to emit the default argument + // generator later. + if (arg.isDefaultArg()) { + auto substParamType = arg.getSubstRValueType(); + auto defArg = std::move(arg).asKnownDefaultArg(); + + auto numParams = getFlattenedValueCount(origParamType, + substParamType, + ImportAsMemberStatus()); + DelayedArguments.emplace_back(defArg, + defArg->getDefaultArgsOwner(), + defArg->getParamIndex(), + substParamType, origParamType, + claimNextParameters(numParams), + Rep); + Args.push_back(ManagedValue()); + + maybeEmitForeignErrorArgument(); + return; + } emit(std::move(arg), origParamType); maybeEmitForeignErrorArgument(); } @@ -2725,26 +2658,10 @@ class ArgEmitter { assert(args.isValid()); auto argSources = std::move(args).getSources(); - if (args.isScalar()) { - assert(argSources.size() == 1); - auto arg = std::move(argSources[0]); - auto *shuffle = cast(std::move(arg).asKnownExpr()); - - SmallVector origParamTypes; - for (unsigned i = 0, e = origFormalType.getNumFunctionParams(); i < e; ++i) { - origParamTypes.push_back(origFormalType.getFunctionParamType(i)); - } - - auto origParamType = AbstractionPattern::getTuple(origParamTypes); - - emitShuffle(shuffle, origParamType); - maybeEmitForeignErrorArgument(); - } else { - maybeEmitForeignErrorArgument(); - for (auto i : indices(argSources)) { - emitSingleArg(std::move(argSources[i]), - origFormalType.getFunctionParamType(i)); - } + maybeEmitForeignErrorArgument(); + for (auto i : indices(argSources)) { + emitSingleArg(std::move(argSources[i]), + origFormalType.getFunctionParamType(i)); } } @@ -2776,7 +2693,6 @@ class ArgEmitter { // substituted argument type by abstraction and/or bridging. auto paramSlice = claimNextParameters(1); SILParameterInfo param = paramSlice.front(); - ArgSpecialDest *specialDest = claimNextSpecialDest(); assert(arg.hasLValueType() == param.isIndirectInOut()); @@ -2796,7 +2712,6 @@ class ArgEmitter { // If the caller takes the argument indirectly, the argument has an // inout type. if (param.isIndirectInOut()) { - assert(!specialDest); emitInOut(std::move(arg), loweredSubstArgType, loweredSubstParamType, origParamType, substArgType); return; @@ -2804,26 +2719,11 @@ class ArgEmitter { // If this is a yield, and the yield is borrowed, emit a borrowed r-value. if (IsYield && param.isGuaranteed()) { - assert(!specialDest); if (tryEmitBorrowed(std::move(arg), loweredSubstArgType, loweredSubstParamType, origParamType, paramSlice)) return; } - // If the original type is passed indirectly, copy to memory if - // it's not already there. (Note that this potentially includes - // conventions which pass indirectly without transferring - // ownership, like Itanium C++.) - if (specialDest) { - assert(param.isFormalIndirect() && - "SpecialDest should imply indirect parameter"); - // TODO: Change the way we initialize array storage in opaque mode - emitIndirectInto(std::move(arg), origParamType, loweredSubstParamType, - *specialDest); - Args.push_back(ManagedValue::forInContext()); - return; - } - if (SGF.silConv.isSILIndirect(param)) { emitIndirect(std::move(arg), loweredSubstArgType, origParamType, param); return; @@ -2841,16 +2741,6 @@ class ArgEmitter { return slice; } - /// Claim the next destination, returning a null pointer if there - /// is no special destination. - ArgSpecialDest *claimNextSpecialDest() { - if (!SpecialDests) return nullptr; - assert(!SpecialDests->empty()); - auto dest = &SpecialDests->front(); - SpecialDests = SpecialDests->slice(1); - return (dest->isValid() ? dest : nullptr); - } - /// Emit an argument as an expanded tuple. void emitExpanded(ArgumentSource &&arg, AbstractionPattern origParamType) { assert(!arg.isLValue() && "argument is l-value but parameter is tuple?"); @@ -2908,8 +2798,6 @@ class ArgEmitter { emitExpanded({ e, SGF.emitRValue(e) }, origParamType); } - void emitShuffle(ArgumentShuffleExpr *shuffle, AbstractionPattern origType); - void emitIndirect(ArgumentSource &&arg, SILType loweredSubstArgType, AbstractionPattern origParamType, @@ -2949,13 +2837,6 @@ class ArgEmitter { Args.push_back(result); } - void emitIndirectInto(ArgumentSource &&arg, - AbstractionPattern origType, - SILType loweredSubstParamType, - ArgSpecialDest &dest) { - dest.fill(SGF, std::move(arg), origType, loweredSubstParamType); - } - void emitInOut(ArgumentSource &&arg, SILType loweredSubstArgType, SILType loweredSubstParamType, AbstractionPattern origType, CanType substType) { @@ -3269,11 +3150,8 @@ class ArgEmitter { return; SILParameterInfo param = claimNextParameters(1).front(); - ArgSpecialDest *specialDest = claimNextSpecialDest(); - assert(param.getConvention() == ParameterConvention::Direct_Unowned); - assert(!specialDest && "special dest for error argument?"); - (void) param; (void) specialDest; + (void) param; // Leave a placeholder in the position. Args.push_back(ManagedValue::forInContext()); @@ -3433,407 +3311,8 @@ void DelayedArgument::emitBorrowedLValue(SILGenFunction &SGF, // That should drain all the parameters. assert(params.empty()); } - -struct ElementExtent { - /// The parameters which go into this tuple element. - /// This is set in the first pass. - ClaimedParamsRef Params; - /// The destination index, if any. - /// This is set in the first pass. - unsigned DestIndex : 30; - unsigned HasDestIndex : 1; -#ifndef NDEBUG - unsigned Used : 1; -#endif - /// The arguments which feed this tuple element. - /// This is set in the second pass. - ArrayRef Args; - /// The inout arguments which feed this tuple element. - /// This is set in the second pass. - MutableArrayRef DelayedArgs; - - ElementExtent() - : HasDestIndex(false) -#ifndef NDEBUG - , - Used(false) -#endif - { - } -}; - -class ArgumentShuffleEmitter { - Expr *inner; - Expr *outer; - ArrayRef innerElts; - ConcreteDeclRef defaultArgsOwner; - ArrayRef callerDefaultArgs; - ArrayRef elementMapping; - ArrayRef variadicArgs; - Type varargsArrayType; - AbstractionPattern origParamType; - bool isResultScalar; - - TupleTypeElt singleOuterElement; - ArrayRef outerElements; - CanType canVarargsArrayType; - - /// The original parameter type. - SmallVector origInnerElts; - AbstractionPattern innerOrigParamType; - /// Flattened inner parameter sequence. - SmallVector innerParams; - /// Extents of the inner elements. - SmallVector innerExtents; - Optional varargsInfo; - SILParameterInfo variadicParamInfo; // innerExtents will point at this - Optional> innerSpecialDests; - - // Used by flattenPatternFromInnerExtendIntoInnerParams and - // splitInnerArgumentsCorrectly. - SmallVector innerArgs; - SmallVector innerDelayedArgs; - -public: - ArgumentShuffleEmitter(ArgumentShuffleExpr *e, ArrayRef innerElts, - AbstractionPattern origParamType) - : inner(e->getSubExpr()), outer(e), innerElts(innerElts), - defaultArgsOwner(e->getDefaultArgsOwner()), - callerDefaultArgs(e->getCallerDefaultArgs()), - elementMapping(e->getElementMapping()), - variadicArgs(e->getVariadicArgs()), - varargsArrayType(e->getVarargsArrayTypeOrNull()), - origParamType(origParamType), isResultScalar(e->isResultScalar()), - canVarargsArrayType(), - origInnerElts(innerElts.size(), AbstractionPattern::getInvalid()), - innerOrigParamType(AbstractionPattern::getInvalid()), innerParams(), - innerExtents(innerElts.size()), varargsInfo(), variadicParamInfo(), - innerSpecialDests() { - - // Decompose the shuffle result. - CanType resultType = e->getType()->getCanonicalType(); - if (isResultScalar) { - singleOuterElement = TupleTypeElt(resultType); - outerElements = singleOuterElement; - } else { - outerElements = cast(resultType)->getElements(); - } - - if (varargsArrayType) - canVarargsArrayType = varargsArrayType->getCanonicalType(); - } - - ArgumentShuffleEmitter(const ArgumentShuffleEmitter &) = delete; - ArgumentShuffleEmitter &operator=(const ArgumentShuffleEmitter &) = delete; - ArgumentShuffleEmitter(ArgumentShuffleEmitter &&) = delete; - ArgumentShuffleEmitter &operator=(ArgumentShuffleEmitter &&) = delete; - - void emit(ArgEmitter &parent); - -private: - void constructInnerTupleTypeInfo(ArgEmitter &parent); - void flattenPatternFromInnerExtendIntoInnerParams(ArgEmitter &parent); - void splitInnerArgumentsCorrectly(ArgEmitter &parent); - void emitDefaultArgsAndFinalize(ArgEmitter &parent); - - AbstractionPattern getOutputOrigElementType(unsigned index) { - assert(!isResultScalar || index == 0); - return origParamType.getTupleElementType(index); - } -}; - } // end anonymous namespace -void ArgumentShuffleEmitter::constructInnerTupleTypeInfo(ArgEmitter &parent) { - unsigned nextParamIndex = 0; - for (unsigned outerIndex : indices(outerElements)) { - CanType substEltType = - outerElements[outerIndex].getType()->getCanonicalType(); - AbstractionPattern origEltType = - getOutputOrigElementType(outerIndex); - unsigned numParams = - getFlattenedValueCount(origEltType, substEltType, parent.ForeignSelf); - - // Skip the foreign-error parameter. - assert((!parent.ForeignError || - parent.ForeignError->getErrorParameterIndex() <= nextParamIndex || - parent.ForeignError->getErrorParameterIndex() >= - nextParamIndex + numParams) && - "error parameter falls within shuffled range?"); - if (numParams && // Don't skip it twice if there's an empty tuple. - parent.ForeignError && - parent.ForeignError->getErrorParameterIndex() == nextParamIndex) { - nextParamIndex++; - } - - // Grab the parameter infos corresponding to this tuple element - // (but don't drop them from ParamInfos yet). - auto eltParams = parent.ParamInfos.slice(nextParamIndex, numParams); - nextParamIndex += numParams; - - int innerIndex = elementMapping[outerIndex]; - if (innerIndex >= 0) { -#ifndef NDEBUG - assert(!innerExtents[innerIndex].Used && "using element twice"); - innerExtents[innerIndex].Used = true; -#endif - innerExtents[innerIndex].Params = eltParams; - origInnerElts[innerIndex] = origEltType; - } else if (innerIndex == ArgumentShuffleExpr::Variadic) { - auto &varargsField = outerElements[outerIndex]; - assert(varargsField.isVararg()); - assert(!varargsInfo.hasValue() && "already had varargs entry?"); - - CanType varargsEltType = CanType(varargsField.getVarargBaseTy()); - unsigned numVarargs = variadicArgs.size(); - assert(canVarargsArrayType == substEltType); - - // If we don't have any vararg expansions, eagerly emit into - // the array value. - varargsInfo.emplace(emitBeginVarargs(parent.SGF, outer, varargsEltType, - canVarargsArrayType, numVarargs)); - - // If we have any varargs, we'll need to actually initialize - // the array buffer. - if (numVarargs) { - // For this, we'll need special destinations. - assert(!innerSpecialDests); - innerSpecialDests.emplace(); - - // Prepare the variadic "arguments" as single +1 indirect parameters - // with the array's desired abstraction pattern. The vararg element - // type should be materializable, and the abstraction pattern should be - // opaque, so ArgEmitter's lowering should always generate exactly one - // "argument" per element even if the substituted element type is a - // tuple. - variadicParamInfo = - SILParameterInfo(varargsInfo->getBaseTypeLowering() - .getLoweredType().getASTType(), - ParameterConvention::Indirect_In); - - unsigned i = 0; - for (unsigned innerIndex : variadicArgs) { - // Find out where the next varargs element is coming from. - assert(innerIndex >= 0 && "special source for varargs element??"); -#ifndef NDEBUG - assert(!innerExtents[innerIndex].Used && "using element twice"); - innerExtents[innerIndex].Used = true; -#endif - - // Set the destination index. - innerExtents[innerIndex].HasDestIndex = true; - innerExtents[innerIndex].DestIndex = i++; - - // Use the singleton param info we prepared before. - innerExtents[innerIndex].Params = - ClaimedParamsRef(variadicParamInfo); - - // Propagate the element abstraction pattern. - origInnerElts[innerIndex] = - varargsInfo->getBaseAbstractionPattern(); - } - } - } - } -} - -void ArgumentShuffleEmitter::flattenPatternFromInnerExtendIntoInnerParams( - ArgEmitter &parent) { - for (auto &extent : innerExtents) { - assert(extent.Used && "didn't use all the inner tuple elements!"); - - for (auto param : extent.Params) { - innerParams.push_back(param); - } - - // Fill in the special destinations array. - if (innerSpecialDests) { - // Use the saved index if applicable. - if (extent.HasDestIndex) { - assert(extent.Params.size() == 1); - innerSpecialDests->push_back( - ArgSpecialDest(*varargsInfo, extent.DestIndex)); - - // Otherwise, fill in with the appropriate number of invalid - // special dests. - } else { - // ArgSpecialDest isn't copyable, so we can't just use append. - for (auto &p : extent.Params) { - (void)p; - innerSpecialDests->push_back(ArgSpecialDest()); - } - } - } - } -} - -void ArgumentShuffleEmitter::splitInnerArgumentsCorrectly(ArgEmitter &parent) { - ArrayRef nextArgs = innerArgs; - MutableArrayRef nextDelayedArgs = innerDelayedArgs; - for (auto &extent : innerExtents) { - auto length = extent.Params.size(); - - // Claim the next N inner args for this inner argument. - extent.Args = nextArgs.slice(0, length); - nextArgs = nextArgs.slice(length); - - // Claim the correct number of inout arguments as well. - size_t numDelayed = 0; - for (auto arg : extent.Args) { - assert(!arg.isInContext() || extent.HasDestIndex); - if (!arg) - numDelayed++; - } - extent.DelayedArgs = nextDelayedArgs.slice(0, numDelayed); - nextDelayedArgs = nextDelayedArgs.slice(numDelayed); - } - - assert(nextArgs.empty() && "didn't claim all args"); - assert(nextDelayedArgs.empty() && "didn't claim all inout args"); -} - -void ArgumentShuffleEmitter::emitDefaultArgsAndFinalize(ArgEmitter &parent) { - unsigned nextCallerDefaultArg = 0; - for (unsigned outerIndex = 0, e = outerElements.size(); - outerIndex != e; ++outerIndex) { - // If this comes from an inner element, move the appropriate - // inner element values over. - int innerIndex = elementMapping[outerIndex]; - if (innerIndex >= 0) { - auto &extent = innerExtents[innerIndex]; - auto numArgs = extent.Args.size(); - - parent.maybeEmitForeignErrorArgument(); - - // Drop N parameters off of ParamInfos. - parent.ParamInfos = parent.ParamInfos.slice(numArgs); - - // Move the appropriate inner arguments over as outer arguments. - parent.Args.append(extent.Args.begin(), extent.Args.end()); - for (auto &delayedArg : extent.DelayedArgs) - parent.DelayedArguments.push_back(std::move(delayedArg)); - continue; - } - - // If this is default initialization, prepare to emit the default argument - // generator later. - if (innerIndex == ArgumentShuffleExpr::DefaultInitialize) { - // Otherwise, emit the default initializer, then map that as a - // default argument. - CanType eltType = outerElements[outerIndex].getType()->getCanonicalType(); - auto origType = getOutputOrigElementType(outerIndex); - - auto numParams = getFlattenedValueCount(origType, eltType, - ImportAsMemberStatus()); - - parent.DelayedArguments.emplace_back(outer, defaultArgsOwner, - outerIndex, eltType, origType, - parent.claimNextParameters(numParams), - parent.Rep); - parent.Args.push_back(ManagedValue()); - continue; - } - - // If this is caller default initialization, generate the - // appropriate value. - if (innerIndex == ArgumentShuffleExpr::CallerDefaultInitialize) { - auto arg = callerDefaultArgs[nextCallerDefaultArg++]; - parent.emit(ArgumentSource(arg), - getOutputOrigElementType(outerIndex)); - continue; - } - - // If we're supposed to create a varargs array with the rest, do so. - if (innerIndex == ArgumentShuffleExpr::Variadic) { - auto &varargsField = outerElements[outerIndex]; - assert(varargsField.isVararg() && - "Cannot initialize nonvariadic element"); - assert(varargsInfo.hasValue()); - (void) varargsField; - - // We've successfully built the varargs array; deactivate all - // the special destinations. - if (innerSpecialDests) { - for (auto &dest : *innerSpecialDests) { - if (dest.isValid()) - dest.deactivate(parent.SGF); - } - } - - CanType eltType = outerElements[outerIndex].getType()->getCanonicalType(); - ManagedValue varargs = - emitEndVarargs(parent.SGF, outer, std::move(*varargsInfo)); - parent.emit( - ArgumentSource(outer, RValue(parent.SGF, outer, eltType, varargs)), - getOutputOrigElementType(outerIndex)); - continue; - } - - // That's the last special case defined so far. - llvm_unreachable("unexpected special case in tuple shuffle!"); - } -} - -void ArgumentShuffleEmitter::emit(ArgEmitter &parent) { - // We could support dest addrs here, but it can't actually happen - // with the current limitations on default arguments in tuples. - assert(!parent.SpecialDests && "shuffle nested within varargs expansion?"); - - // First, construct an abstraction pattern and parameter sequence - // which we can use to emit the inner tuple. - constructInnerTupleTypeInfo(parent); - - // The inner abstraction pattern is opaque if we started with an - // opaque pattern; otherwise, it's a tuple of the de-shuffled - // tuple elements. - innerOrigParamType = origParamType; - - // That "tuple" might not actually be a tuple. - if (innerElts.size() == 1 && !innerElts[0].hasName()) { - innerOrigParamType = origInnerElts[0]; - } else { - innerOrigParamType = AbstractionPattern::getTuple(origInnerElts); - } - - flattenPatternFromInnerExtendIntoInnerParams(parent); - - // Emit the inner expression. - if (!innerParams.empty()) { - ArgEmitter(parent.SGF, parent.Rep, parent.IsYield, parent.IsForCoroutine, - ClaimedParamsRef(innerParams), innerArgs, innerDelayedArgs, - /*foreign error*/ None, /*foreign self*/ ImportAsMemberStatus(), - (innerSpecialDests ? ArgSpecialDestArray(*innerSpecialDests) - : Optional())) - .emitSingleArg(ArgumentSource(inner), innerOrigParamType); - } - - // Make a second pass to split the inner arguments correctly. - splitInnerArgumentsCorrectly(parent); - - // Make a final pass to emit default arguments and move things into - // the outer arguments lists. - emitDefaultArgsAndFinalize(parent); -} - -void ArgEmitter::emitShuffle(ArgumentShuffleExpr *E, - AbstractionPattern origParamType) { - ArrayRef srcElts; - TupleTypeElt singletonSrcElt; - auto srcEltTy = E->getSubExpr()->getType()->getCanonicalType(); - if (E->isSourceScalar()) { - ParameterTypeFlags flags; - if (E->getSubExpr()->isSemanticallyInOutExpr()) { - flags = flags.withInOut(true); - } - singletonSrcElt = {srcEltTy->getInOutObjectType(), Identifier(), flags}; - srcElts = singletonSrcElt; - } else { - srcElts = cast(srcEltTy)->getElements(); - } - - ArgumentShuffleEmitter(E, srcElts, origParamType).emit(*this); -} - namespace { /// Cleanup to destroy an uninitialized box. class DeallocateUninitializedBox : public Cleanup { diff --git a/lib/SILGen/SILGenBuiltin.cpp b/lib/SILGen/SILGenBuiltin.cpp index d2b0e78608942..76e7cfba1a318 100644 --- a/lib/SILGen/SILGenBuiltin.cpp +++ b/lib/SILGen/SILGenBuiltin.cpp @@ -31,16 +31,6 @@ using namespace swift; using namespace Lowering; -static bool isTrivialShuffle(ArgumentShuffleExpr *shuffle) { - // Each element must be mapped to the corresponding element of the input. - auto mapping = shuffle->getElementMapping(); - for (auto index : indices(mapping)) { - if (mapping[index] < 0 || unsigned(mapping[index]) != index) - return false; - } - return true; -} - /// Break down an expression that's the formal argument expression to /// a builtin function, returning its individualized arguments. /// @@ -58,22 +48,6 @@ decomposeArguments(SILGenFunction &SGF, for (auto &&source : sources) result.push_back(std::move(source).asKnownExpr()); return result; - } else if (sources.size() == 1) { - auto *arg = std::move(sources[0]).asKnownExpr(); - - // The use of owned parameters can trip up CSApply enough to introduce - // a trivial tuple shuffle here. - if (auto shuffle = dyn_cast(arg)) { - if (isTrivialShuffle(shuffle)) - arg = shuffle->getSubExpr(); - } - - auto tuple = dyn_cast(arg); - if (tuple && tuple->getElements().size() == expectedCount) { - for (auto elt : tuple->getElements()) - result.push_back(elt); - return result; - } } SGF.SGM.diagnose(loc, diag::invalid_sil_builtin, diff --git a/lib/SILGen/SILGenExpr.cpp b/lib/SILGen/SILGenExpr.cpp index b7dd79fd1cc4f..06e5a47880935 100644 --- a/lib/SILGen/SILGenExpr.cpp +++ b/lib/SILGen/SILGenExpr.cpp @@ -450,7 +450,6 @@ namespace { RValue visitDynamicSubscriptExpr(DynamicSubscriptExpr *E, SGFContext C); RValue visitDestructureTupleExpr(DestructureTupleExpr *E, SGFContext C); - RValue visitArgumentShuffleExpr(ArgumentShuffleExpr *E, SGFContext C); RValue visitDynamicTypeExpr(DynamicTypeExpr *E, SGFContext C); RValue visitCaptureListExpr(CaptureListExpr *E, SGFContext C); RValue visitAbstractClosureExpr(AbstractClosureExpr *E, SGFContext C); @@ -2165,11 +2164,6 @@ RValue RValueEmitter::visitDestructureTupleExpr(DestructureTupleExpr *E, return result; } -RValue RValueEmitter::visitArgumentShuffleExpr(ArgumentShuffleExpr *E, - SGFContext C) { - llvm_unreachable("ArgumentShuffleExpr cannot appear in rvalue position"); -} - static SILValue emitMetatypeOfDelegatingInitExclusivelyBorrowedSelf( SILGenFunction &SGF, SILLocation loc, DeclRefExpr *dre, SILType metaTy) { SGFContext ctx; diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index 8dc7b5cbd7474..ca11941f9e19d 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -2963,6 +2963,14 @@ namespace { llvm_unreachable("Already type-checked"); } + Expr *visitDefaultArgumentExpr(DefaultArgumentExpr *expr) { + llvm_unreachable("Already type-checked"); + } + + Expr *visitCallerDefaultArgumentExpr(CallerDefaultArgumentExpr *expr) { + llvm_unreachable("Already type-checked"); + } + Expr *visitApplyExpr(ApplyExpr *expr) { return finishApply(expr, cs.getType(expr), ConstraintLocatorBuilder( @@ -5316,6 +5324,15 @@ Expr *ExprRewriter::coerceCallArguments( // 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 * { @@ -5329,118 +5346,133 @@ Expr *ExprRewriter::coerceCallArguments( return arg; }; - // Local function to extract the ith argument label, which papers over some - // of the weirdness with tuples vs. parentheses. - auto getArgLabel = [&](unsigned i) -> Identifier { + auto getLabelLoc = [&](unsigned i) -> SourceLoc { if (argTuple) - return argTuple->getElementName(i); + return argTuple->getElementNameLoc(i); assert(i == 0 && "Scalar only has a single argument"); - return Identifier(); + return SourceLoc(); }; - SmallVector toSugarFields; - SmallVector fromTupleExprFields( - argTuple? argTuple->getNumElements() : 1); - SmallVector fromTupleExpr(argTuple? argTuple->getNumElements() : 1); - SmallVector variadicArgs; - SmallVector callerDefaultArgs; - Type sliceType = nullptr; - SmallVector sources; + SmallVector newArgs; + SmallVector newLabels; + SmallVector newLabelLocs; + SmallVector newParams; + for (unsigned paramIdx = 0, numParams = parameterBindings.size(); paramIdx != numParams; ++paramIdx) { // Extract the parameter. const auto ¶m = params[paramIdx]; + newLabels.push_back(param.getLabel()); // Handle variadic parameters. if (param.isVariadic()) { - // Find the appropriate injection function. - if (tc.requireArrayLiteralIntrinsics(arg->getStartLoc())) - return nullptr; + assert(!param.isInOut()); - // Record this parameter. - auto paramBaseType = param.getOldType(); - assert(sliceType.isNull() && "Multiple variadic parameters?"); - sliceType = tc.getArraySliceType(arg->getLoc(), paramBaseType); - toSugarFields.push_back( - TupleTypeElt(sliceType, param.getLabel(), param.getParameterFlags())); - sources.push_back(ArgumentShuffleExpr::Variadic); + SmallVector variadicArgs; + + // The first argument of this vararg parameter may have had a label; + // save its location. + auto &varargIndices = parameterBindings[paramIdx]; + if (!varargIndices.empty()) + newLabelLocs.push_back(getLabelLoc(varargIndices[0])); + else + newLabelLocs.push_back(SourceLoc()); // Convert the arguments. - for (auto argIdx : parameterBindings[paramIdx]) { + for (auto argIdx : varargIndices) { auto arg = getArg(argIdx); auto argType = cs.getType(arg); - variadicArgs.push_back(argIdx); // If the argument type exactly matches, this just works. - if (argType->isEqual(paramBaseType)) { - fromTupleExprFields[argIdx] = TupleTypeElt(argType, - getArgLabel(argIdx)); - fromTupleExpr[argIdx] = arg; + if (argType->isEqual(param.getPlainType())) { + variadicArgs.push_back(arg); continue; } // Convert the argument. - auto convertedArg = coerceToType(arg, paramBaseType, + auto convertedArg = coerceToType(arg, param.getPlainType(), getArgLocator(argIdx, paramIdx)); if (!convertedArg) return nullptr; // Add the converted argument. - fromTupleExpr[argIdx] = convertedArg; - fromTupleExprFields[argIdx] = TupleTypeElt(cs.getType(convertedArg), - getArgLabel(argIdx)); + variadicArgs.push_back(convertedArg); + } + + SourceLoc start, end; + if (!variadicArgs.empty()) { + start = variadicArgs.front()->getStartLoc(); + end = variadicArgs.back()->getEndLoc(); } + // Collect them into an ArrayExpr. + auto *arrayExpr = ArrayExpr::create(tc.Context, + start, + variadicArgs, + {}, end, + param.getParameterType()); + arrayExpr->setImplicit(); + cs.cacheType(arrayExpr); + + // Wrap the ArrayExpr in a VarargExpansionExpr. + auto *varargExpansionExpr = + new (tc.Context) VarargExpansionExpr(arrayExpr, + /*implicit=*/true, + arrayExpr->getType()); + cs.cacheType(varargExpansionExpr); + + newArgs.push_back(varargExpansionExpr); + newParams.push_back(param); continue; } - // If we are using a default argument, handle it now. + // Handle default arguments. if (parameterBindings[paramIdx].empty()) { - // Create a caller-side default argument, if we need one. Expr *defArg; DefaultArgumentKind defArgKind; std::tie(defArg, defArgKind) = getCallerDefaultArg(cs, dc, arg->getLoc(), callee, paramIdx); - // Note that we'll be doing a shuffle involving default arguments. - toSugarFields.push_back(TupleTypeElt( - param.isVariadic() - ? tc.getArraySliceType(arg->getLoc(), - param.getOldType()) - : param.getOldType(), - param.getLabel(), - param.getParameterFlags())); - + // If we have a caller-side default argument, just add the magic literal + // expression to our argument list. if (defArg) { - callerDefaultArgs.push_back(defArg); - sources.push_back(ArgumentShuffleExpr::CallerDefaultInitialize); + defArg = + new (tc.Context) CallerDefaultArgumentExpr(defArg, + arg->getStartLoc(), + param.getParameterType()); + + // Otherwise, create a call of the default argument generator. } else { - sources.push_back(ArgumentShuffleExpr::DefaultInitialize); + defArg = + new (tc.Context) DefaultArgumentExpr(callee, paramIdx, + arg->getStartLoc(), + param.getParameterType()); } + + cs.cacheType(defArg); + newArgs.push_back(defArg); + newParams.push_back(param); + newLabelLocs.push_back(SourceLoc()); continue; } + // Otherwise, we have a plain old ordinary argument. + // 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); - // If the argument and parameter indices differ, or if the names differ, - // this is a shuffle. - sources.push_back(argIdx); + // Save the original label location. + newLabelLocs.push_back(getLabelLoc(argIdx)); // If the types exactly match, this is easy. auto paramType = param.getOldType(); if (argType->isEqual(paramType)) { - toSugarFields.push_back( - TupleTypeElt(param.getPlainType(), getArgLabel(argIdx), - param.getParameterFlags())); - fromTupleExprFields[argIdx] = - TupleTypeElt(param.getPlainType(), getArgLabel(argIdx), - param.getParameterFlags()); - fromTupleExpr[argIdx] = arg; + newArgs.push_back(arg); + newParams.push_back(param); continue; } @@ -5458,6 +5490,8 @@ Expr *ExprRewriter::coerceCallArguments( // a regular function coversion by `coerceToType`. if (param.isAutoClosure() && (!argType->is() || !isAutoClosureArg(arg))) { + assert(!param.isInOut()); + // If parameter is an autoclosure, we need to make sure that: // - argument type is coerced to parameter result type // - impilict autoclosure is created to wrap argument expression @@ -5478,109 +5512,65 @@ Expr *ExprRewriter::coerceCallArguments( if (!convertedArg) return nullptr; - // Add the converted argument. - fromTupleExpr[argIdx] = convertedArg; - fromTupleExprFields[argIdx] = TupleTypeElt( - cs.getType(convertedArg)->getInOutObjectType(), - getArgLabel(argIdx), param.getParameterFlags()); - toSugarFields.push_back( - TupleTypeElt(argType->getInOutObjectType(), param.getLabel(), - param.getParameterFlags())); + 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()); } - Type argTupleType = TupleType::get(fromTupleExprFields, tc.Context); + assert(newArgs.size() == newParams.size()); + assert(newArgs.size() == newLabels.size()); + assert(newArgs.size() == newLabelLocs.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(!hasTrailingClosure); + return newArgs[0]; + } - // Compute a new 'arg', from the bits we have. We have three cases: the - // scalar case, the paren case, and the tuple literal case. - if (!argTuple && !argParen) { - assert(fromTupleExpr.size() == 1 && fromTupleExpr[0]); - arg = fromTupleExpr[0]; - } else if (argParen) { - // If the element changed, rebuild a new ParenExpr. - assert(fromTupleExpr.size() == 1 && fromTupleExpr[0]); - if (fromTupleExpr[0] != argParen->getSubExpr()) { - bool argParenImplicit = argParen->isImplicit(); - argParen = - cs.cacheType(new (tc.Context) - ParenExpr(argParen->getLParenLoc(), - fromTupleExpr[0], - argParen->getRParenLoc(), - argParen->hasTrailingClosure(), - argTupleType)); - if (argParenImplicit) { - argParen->setImplicit(); - } - arg = argParen; + // Rebuild the argument list, sharing as much structure as possible. + auto paramType = AnyFunctionType::composeInput(tc.Context, 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 { - // coerceToType may have updated the element type of the ParenExpr in - // place. If so, propagate the type out to the ParenExpr as well. - cs.setType(argParen, argTupleType); + arg = new (tc.Context) ParenExpr(lParenLoc, + newArgs[0], + rParenLoc, + hasTrailingClosure); + arg->setImplicit(); } } else { - assert(argTuple); + assert(isa(paramType.getPointer())); - bool anyChanged = false; - for (unsigned i = 0, e = argTuple->getNumElements(); i != e; ++i) - if (fromTupleExpr[i] != argTuple->getElement(i)) { - anyChanged = true; - break; + 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]); } - - // If anything about the TupleExpr changed, rebuild a new one. - Type argTupleType = TupleType::get(fromTupleExprFields, tc.Context); - assert(isa(argTupleType.getPointer())); - - if (anyChanged || !cs.getType(argTuple)->isEqual(argTupleType)) { - auto EltNames = argTuple->getElementNames(); - auto EltNameLocs = argTuple->getElementNameLocs(); - argTuple = - cs.cacheType(TupleExpr::create(tc.Context, argTuple->getLParenLoc(), - fromTupleExpr, EltNames, EltNameLocs, - argTuple->getRParenLoc(), - argTuple->hasTrailingClosure(), - argTuple->isImplicit(), - argTupleType)); - arg = argTuple; + } else { + // Build a new TupleExpr, re-using source location information. + arg = TupleExpr::create(tc.Context, lParenLoc, + newArgs, newLabels, newLabelLocs, + rParenLoc, + hasTrailingClosure, + /*implicit=*/true); } } - // If we don't have to shuffle anything, we're done. - args.clear(); - AnyFunctionType::decomposeInput(cs.getType(arg), args); - if (AnyFunctionType::equalParams(args, params)) - return arg; - - auto paramType = AnyFunctionType::composeInput(tc.Context, params, - /*canonicalVararg=*/false); - - // If we came from a scalar, create a scalar-to-tuple conversion. - ArgumentShuffleExpr::TypeImpact typeImpact; - if (argTuple == nullptr) { - // Deal with a difference in only scalar ownership. - if (auto paramParenTy = dyn_cast(paramType.getPointer())) { - assert(paramParenTy->getUnderlyingType() - ->isEqual(cs.getType(arg))); - auto argParen = new (tc.Context) ParenExpr(arg->getStartLoc(), - arg, arg->getEndLoc(), false, - paramParenTy); - argParen->setImplicit(); - return cs.cacheType(argParen); - } - - typeImpact = ArgumentShuffleExpr::ScalarToTuple; - assert(isa(paramType.getPointer())); - } else if (isa(paramType.getPointer())) { - typeImpact = ArgumentShuffleExpr::TupleToTuple; - } else { - typeImpact = ArgumentShuffleExpr::TupleToScalar; - assert(isa(paramType.getPointer())); - } - - // Create the argument shuffle. - return cs.cacheType(ArgumentShuffleExpr::create(tc.Context, arg, sources, - typeImpact, callee, variadicArgs, - sliceType, callerDefaultArgs, - paramType)); + arg->setType(paramType); + return cs.cacheType(arg); } static ClosureExpr *getClosureLiteralExpr(Expr *expr) { @@ -6852,9 +6842,6 @@ Expr *ExprRewriter::finishApply(ApplyExpr *apply, Type openedType, return nullptr; } - if (auto shuffle = dyn_cast(arg)) - arg = shuffle->getSubExpr(); - if (auto tuple = dyn_cast(arg)) arg = tuple->getElements()[0]; @@ -7055,8 +7042,7 @@ Expr *ExprRewriter::finishApply(ApplyExpr *apply, Type openedType, // Extract all arguments. auto *CEA = arg; - if (auto *ASE = dyn_cast(CEA)) - CEA = ASE->getSubExpr(); + // The argument is either a ParenExpr or TupleExpr. ArrayRef arguments; diff --git a/lib/Sema/CSDiag.cpp b/lib/Sema/CSDiag.cpp index fd434241856c2..b84f5cf21d7e0 100644 --- a/lib/Sema/CSDiag.cpp +++ b/lib/Sema/CSDiag.cpp @@ -3537,8 +3537,6 @@ class ArgumentMatcher : public MatchCallArgumentListener { CS.getType(ArgExpr)->hasParenSugar()) && "unexpected argument expression type"); insertLoc = ArgExpr->getLoc(); - - // Can't be ArgumentShuffleExpr because this argExpr is not yet resolved. } assert(insertLoc.isValid() && "missing argument after trailing closure?"); diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp index 77199a739f4e5..61899f9dd82a3 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -2452,7 +2452,15 @@ namespace { } Type visitOpaqueValueExpr(OpaqueValueExpr *expr) { - return expr->getType(); + llvm_unreachable("Already type checked"); + } + + Type visitDefaultArgumentExpr(DefaultArgumentExpr *expr) { + llvm_unreachable("Already type checked"); + } + + Type visitCallerDefaultArgumentExpr(CallerDefaultArgumentExpr *expr) { + llvm_unreachable("Already type checked"); } Type visitApplyExpr(ApplyExpr *expr) { @@ -3175,6 +3183,9 @@ namespace { /// This is necessary because Sema fills in too much type information before /// the type-checker runs, causing redundant work, and for expression that /// have already been typechecked and may contain unhandled AST nodes. + /// + /// FIXME: Remove this one we no longer re-type check expressions during + /// diagnostics and code completion. class SanitizeExpr : public ASTWalker { ConstraintSystem &CS; TypeChecker &TC; @@ -3256,11 +3267,70 @@ namespace { EPE->setSemanticExpr(nullptr); } + // Strip default arguments and varargs from type-checked call + // argument lists. + if (isa(expr) || isa(expr)) { + if (shouldSanitizeArgumentList(expr)) + expr = sanitizeArgumentList(expr); + } + // Now, we're ready to walk into sub expressions. return {true, expr}; } } + bool isSyntheticArgumentExpr(const Expr *expr) { + if (isa(expr) || + isa(expr)) + return true; + + if (auto *varargExpr = dyn_cast(expr)) + if (isa(varargExpr->getSubExpr())) + return true; + + return false; + } + + bool shouldSanitizeArgumentList(const Expr *expr) { + if (auto *parenExpr = dyn_cast(expr)) { + return isSyntheticArgumentExpr(parenExpr->getSubExpr()); + } else if (auto *tupleExpr = dyn_cast(expr)) { + for (auto *arg : tupleExpr->getElements()) { + if (isSyntheticArgumentExpr(arg)) + return true; + } + + return false; + } else { + return isSyntheticArgumentExpr(expr); + } + } + + Expr *sanitizeArgumentList(Expr *original) { + auto argList = getOriginalArgumentList(original); + + if (argList.args.size() == 1 && + argList.labels[0].empty() && + !isa(argList.args[0])) { + auto *result = + new (TC.Context) ParenExpr(argList.lParenLoc, + argList.args[0], + argList.rParenLoc, + argList.hasTrailingClosure); + result->setImplicit(); + return result; + } + + return TupleExpr::create(TC.Context, + argList.lParenLoc, + argList.args, + argList.labels, + argList.labelLocs, + argList.rParenLoc, + argList.hasTrailingClosure, + /*implicit=*/true); + } + Expr *walkToExprPost(Expr *expr) override { if (CS.hasType(expr)) { Type type = CS.getType(expr); @@ -3774,3 +3844,58 @@ swift::resolveValueMember(DeclContext &DC, Type BaseTy, DeclName Name) { } return Result; } + +OriginalArgumentList +swift::getOriginalArgumentList(Expr *expr) { + OriginalArgumentList result; + + auto add = [&](Expr *arg, Identifier label, SourceLoc labelLoc) { + if (isa(arg) || + isa(arg)) { + return; + } + + if (auto *varargExpr = dyn_cast(arg)) { + if (auto *arrayExpr = dyn_cast(varargExpr->getSubExpr())) { + for (auto *elt : arrayExpr->getElements()) { + result.args.push_back(elt); + result.labels.push_back(label); + result.labelLocs.push_back(labelLoc); + + label = Identifier(); + labelLoc = SourceLoc(); + } + + return; + } + } + + result.args.push_back(arg); + result.labels.push_back(label); + result.labelLocs.push_back(labelLoc); + }; + + if (auto *parenExpr = dyn_cast(expr)) { + result.lParenLoc = parenExpr->getLParenLoc(); + result.rParenLoc = parenExpr->getRParenLoc(); + result.hasTrailingClosure = parenExpr->hasTrailingClosure(); + add(parenExpr->getSubExpr(), Identifier(), SourceLoc()); + } else if (auto *tupleExpr = dyn_cast(expr)) { + result.lParenLoc = tupleExpr->getLParenLoc(); + result.rParenLoc = tupleExpr->getRParenLoc(); + result.hasTrailingClosure = tupleExpr->hasTrailingClosure(); + + auto args = tupleExpr->getElements(); + auto labels = tupleExpr->getElementNames(); + auto labelLocs = tupleExpr->getElementNameLocs(); + for (unsigned i = 0, e = args.size(); i != e; ++i) { + // Implicit TupleExprs don't always store label locations. + add(args[i], labels[i], + labelLocs.empty() ? SourceLoc() : labelLocs[i]); + } + } else { + add(expr, Identifier(), SourceLoc()); + } + + return result; +} \ No newline at end of file diff --git a/lib/Sema/MiscDiagnostics.cpp b/lib/Sema/MiscDiagnostics.cpp index c766e02130b8f..dfffc6dd0d4f9 100644 --- a/lib/Sema/MiscDiagnostics.cpp +++ b/lib/Sema/MiscDiagnostics.cpp @@ -25,6 +25,7 @@ #include "swift/Basic/StringExtras.h" #include "swift/Parse/Lexer.h" #include "swift/Parse/Parser.h" +#include "swift/Sema/IDETypeChecking.h" #include "llvm/ADT/MapVector.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/SaveAndRestore.h" @@ -145,11 +146,6 @@ static void diagSyntacticUseRestrictions(TypeChecker &TC, const Expr *E, if (isa(Base)) checkUseOfMetaTypeName(Base); - if (auto *ASE = dyn_cast(E)) { - if (CallArgs.count(ASE)) - CallArgs.insert(ASE->getSubExpr()); - } - if (auto *SE = dyn_cast(E)) { CallArgs.insert(SE->getIndex()); @@ -329,11 +325,6 @@ static void diagSyntacticUseRestrictions(TypeChecker &TC, const Expr *E, static void argExprVisitArguments(Expr* arg, llvm::function_ref fn) { - // The argument could be shuffled if it includes default arguments, - // label differences, or other exciting things like that. - if (auto *ASE = dyn_cast(arg)) - arg = ASE->getSubExpr(); - // The argument is either a ParenExpr or TupleExpr. if (auto *TE = dyn_cast(arg)) { auto elts = TE->getElements(); @@ -1688,7 +1679,7 @@ bool TypeChecker::getDefaultGenericArgumentsString( /// Diagnose an argument labeling issue, returning true if we successfully /// diagnosed the issue. bool swift::diagnoseArgumentLabelError(ASTContext &ctx, - const Expr *expr, + Expr *expr, ArrayRef newNames, bool isSubscript, InFlightDiagnostic *existingDiag) { @@ -1700,56 +1691,26 @@ bool swift::diagnoseArgumentLabelError(ASTContext &ctx, }; auto &diags = ctx.Diags; - auto tuple = dyn_cast(expr); - if (!tuple) { - if (newNames[0].empty()) { - // We don't know what to do with this. - return false; - } - llvm::SmallString<16> str; - // If the diagnostic is local, flush it before returning. - // This makes sure it's emitted before 'str' is destroyed. - SWIFT_DEFER { diagOpt.reset(); }; - - // This is a scalar-to-tuple conversion. Add the name. We "know" - // that we're inside a ParenExpr, because ParenExprs are required - // by the syntax and locator resolution looks through on level of - // them. - - // Look through the paren expression, if there is one. - if (auto parenExpr = dyn_cast(expr)) - expr = parenExpr->getSubExpr(); - - str += newNames[0].str(); - str += ": "; - if (!existingDiag) { - diagOpt.emplace(diags.diagnose(expr->getStartLoc(), - diag::missing_argument_labels, - false, str.str().drop_back(), - isSubscript)); - } - getDiag().fixItInsert(expr->getStartLoc(), str); - return true; - } + OriginalArgumentList argList = getOriginalArgumentList(expr); // Figure out how many extraneous, missing, and wrong labels are in // the call. unsigned numExtra = 0, numMissing = 0, numWrong = 0; - unsigned n = std::max(tuple->getNumElements(), (unsigned)newNames.size()); + unsigned n = std::max(argList.args.size(), newNames.size()); llvm::SmallString<16> missingBuffer; llvm::SmallString<16> extraBuffer; for (unsigned i = 0; i != n; ++i) { Identifier oldName; - if (i < tuple->getNumElements()) - oldName = tuple->getElementName(i); + if (i < argList.args.size()) + oldName = argList.labels[i]; Identifier newName; if (i < newNames.size()) newName = newNames[i]; if (oldName == newName || - (tuple->hasTrailingClosure() && i == tuple->getNumElements()-1)) + (argList.hasTrailingClosure && i == argList.args.size()-1)) continue; if (oldName.empty()) { @@ -1774,8 +1735,8 @@ bool swift::diagnoseArgumentLabelError(ASTContext &ctx, if (!existingDiag) { bool plural = (numMissing + numExtra + numWrong) > 1; if (numWrong > 0 || (numMissing > 0 && numExtra > 0)) { - for (unsigned i = 0, n = tuple->getNumElements(); i != n; ++i) { - auto haveName = tuple->getElementName(i); + for (unsigned i = 0, n = argList.args.size(); i != n; ++i) { + auto haveName = argList.labels[i]; if (haveName.empty()) haveBuffer += '_'; else @@ -1813,19 +1774,19 @@ bool swift::diagnoseArgumentLabelError(ASTContext &ctx, // Emit Fix-Its to correct the names. auto &diag = getDiag(); - for (unsigned i = 0, n = tuple->getNumElements(); i != n; ++i) { - Identifier oldName = tuple->getElementName(i); + for (unsigned i = 0, n = argList.args.size(); i != n; ++i) { + Identifier oldName = argList.labels[i]; Identifier newName; if (i < newNames.size()) newName = newNames[i]; - if (oldName == newName || (i == n-1 && tuple->hasTrailingClosure())) + if (oldName == newName || (i == n-1 && argList.hasTrailingClosure)) continue; if (newName.empty()) { // Delete the old name. - diag.fixItRemoveChars(tuple->getElementNameLocs()[i], - tuple->getElement(i)->getStartLoc()); + diag.fixItRemoveChars(argList.labelLocs[i], + argList.args[i]->getStartLoc()); continue; } @@ -1840,12 +1801,12 @@ bool swift::diagnoseArgumentLabelError(ASTContext &ctx, if (oldName.empty()) { // Insert the name. newStr += ": "; - diag.fixItInsert(tuple->getElement(i)->getStartLoc(), newStr); + diag.fixItInsert(argList.args[i]->getStartLoc(), newStr); continue; } // Change the name. - diag.fixItReplace(tuple->getElementNameLocs()[i], newStr); + diag.fixItReplace(argList.labelLocs[i], newStr); } // If the diagnostic is local, flush it before returning. @@ -2941,32 +2902,29 @@ void swift::fixItEncloseTrailingClosure(TypeChecker &TC, const CallExpr *call, Identifier closureLabel) { auto argsExpr = call->getArg(); - if (auto ASE = dyn_cast(argsExpr)) - argsExpr = ASE->getSubExpr(); SmallString<32> replacement; SourceLoc lastLoc; SourceRange closureRange; - if (auto PE = dyn_cast(argsExpr)) { - assert(PE->hasTrailingClosure() && "must have trailing closure"); - closureRange = PE->getSubExpr()->getSourceRange(); - lastLoc = PE->getLParenLoc(); // e.g funcName() { 1 } + + auto argList = getOriginalArgumentList(argsExpr); + + assert(argList.args.size() >= 1 && "must have at least one argument"); + + if (argList.args.size() == 1) { + closureRange = argList.args[0]->getSourceRange(); + lastLoc = argList.lParenLoc; // e.g funcName() { 1 } if (!lastLoc.isValid()) { // Bare trailing closure: e.g. funcName { 1 } replacement = "("; lastLoc = call->getFn()->getEndLoc(); } - } else if (auto TE = dyn_cast(argsExpr)) { + } else { // Tuple + trailing closure: e.g. funcName(x: 1) { 1 } - assert(TE->hasTrailingClosure() && "must have trailing closure"); - auto numElements = TE->getNumElements(); - assert(numElements >= 2 && "Unexpected num of elements in TupleExpr"); - closureRange = TE->getElement(numElements - 1)->getSourceRange(); - lastLoc = TE->getElement(numElements - 2)->getEndLoc(); + auto numElements = argList.args.size(); + closureRange = argList.args[numElements - 1]->getSourceRange(); + lastLoc = argList.args[numElements - 2]->getEndLoc(); replacement = ", "; - } else { - // Can't be here. - return; } // Add argument label of the closure. @@ -2997,9 +2955,6 @@ static void checkStmtConditionTrailingClosure(TypeChecker &TC, const Expr *E) { // Ignore invalid argument type. Some diagnostics are already emitted. if (!argsTy || argsTy->hasError()) return; - if (auto ASE = dyn_cast(argsExpr)) - argsExpr = ASE->getSubExpr(); - SourceLoc closureLoc; if (auto PE = dyn_cast(argsExpr)) closureLoc = PE->getSubExpr()->getStartLoc(); diff --git a/lib/Sema/MiscDiagnostics.h b/lib/Sema/MiscDiagnostics.h index 358376b74333e..5d0c4437bfd6f 100644 --- a/lib/Sema/MiscDiagnostics.h +++ b/lib/Sema/MiscDiagnostics.h @@ -65,7 +65,7 @@ void fixItAccess(InFlightDiagnostic &diag, /// /// \returns true if the issue was diagnosed bool diagnoseArgumentLabelError(ASTContext &ctx, - const Expr *expr, + Expr *expr, ArrayRef newNames, bool isSubscript, InFlightDiagnostic *existingDiag = nullptr); diff --git a/lib/Sema/PlaygroundTransform.cpp b/lib/Sema/PlaygroundTransform.cpp index c4e6778e4b094..56566fa39982c 100644 --- a/lib/Sema/PlaygroundTransform.cpp +++ b/lib/Sema/PlaygroundTransform.cpp @@ -344,10 +344,6 @@ class Instrumenter : InstrumenterBase { return dyn_cast( inout->getSubExpr()->getSemanticsProvidingExpr()); - // Drill through argument shuffles, ignoring non-default-argument inouts. - } else if (auto shuffle = dyn_cast(E)) { - return digForInoutDeclRef(shuffle->getSubExpr()); - // Try to find a unique inout argument in a tuple. } else if (auto tuple = dyn_cast(E)) { DeclRefExpr *uniqueRef = nullptr; diff --git a/lib/Sema/TypeCheckAvailability.cpp b/lib/Sema/TypeCheckAvailability.cpp index 24beba941ba06..a537324b56609 100644 --- a/lib/Sema/TypeCheckAvailability.cpp +++ b/lib/Sema/TypeCheckAvailability.cpp @@ -27,6 +27,7 @@ #include "swift/Basic/StringExtras.h" #include "swift/Parse/Lexer.h" #include "swift/Parse/Parser.h" +#include "swift/Sema/IDETypeChecking.h" #include "llvm/ADT/MapVector.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/SaveAndRestore.h" @@ -1544,77 +1545,68 @@ static void fixItAvailableAttrRename(InFlightDiagnostic &diag, SourceLoc removeRangeStart; SourceLoc removeRangeEnd; - const Expr *argExpr = call->getArg(); - if (auto args = dyn_cast(argExpr)) { - size_t numElementsWithinParens = args->getNumElements(); - numElementsWithinParens -= args->hasTrailingClosure(); - if (selfIndex >= numElementsWithinParens) - return; - - if (parsed.IsGetter) { - if (numElementsWithinParens != 1) - return; - } else if (parsed.IsSetter) { - if (numElementsWithinParens != 2) - return; - } else { - if (parsed.ArgumentLabels.size() != args->getNumElements() - 1) - return; - } + auto *argExpr = call->getArg(); + auto argList = getOriginalArgumentList(argExpr); - selfExpr = args->getElement(selfIndex); + size_t numElementsWithinParens = argList.args.size(); + numElementsWithinParens -= argList.hasTrailingClosure; + if (selfIndex >= numElementsWithinParens) + return; - if (selfIndex + 1 == numElementsWithinParens) { - if (selfIndex > 0) { - // Remove from the previous comma to the close-paren (half-open). - removeRangeStart = args->getElement(selfIndex-1)->getEndLoc(); - removeRangeStart = Lexer::getLocForEndOfToken(sourceMgr, - removeRangeStart); - } else { - // Remove from after the open paren to the close paren (half-open). - removeRangeStart = Lexer::getLocForEndOfToken(sourceMgr, - argExpr->getStartLoc()); - } + if (parsed.IsGetter) { + if (numElementsWithinParens != 1) + return; + } else if (parsed.IsSetter) { + if (numElementsWithinParens != 2) + return; + } else { + if (parsed.ArgumentLabels.size() != argList.args.size() - 1) + return; + } - // Prefer the r-paren location, so that we get the right behavior when - // there's a trailing closure, but handle some implicit cases too. - removeRangeEnd = args->getRParenLoc(); - if (removeRangeEnd.isInvalid()) - removeRangeEnd = args->getEndLoc(); + selfExpr = argList.args[selfIndex]; + if (selfIndex + 1 == numElementsWithinParens) { + if (selfIndex > 0) { + // Remove from the previous comma to the close-paren (half-open). + removeRangeStart = argList.args[selfIndex-1]->getEndLoc(); + removeRangeStart = Lexer::getLocForEndOfToken(sourceMgr, + removeRangeStart); } else { - // Remove from the label to the start of the next argument (half-open). - SourceLoc labelLoc = args->getElementNameLoc(selfIndex); - if (labelLoc.isValid()) - removeRangeStart = labelLoc; - else - removeRangeStart = selfExpr->getStartLoc(); - - SourceLoc nextLabelLoc = args->getElementNameLoc(selfIndex + 1); - if (nextLabelLoc.isValid()) - removeRangeEnd = nextLabelLoc; - else - removeRangeEnd = args->getElement(selfIndex + 1)->getStartLoc(); + // Remove from after the open paren to the close paren (half-open). + removeRangeStart = Lexer::getLocForEndOfToken(sourceMgr, + argExpr->getStartLoc()); } - // Avoid later argument label fix-its for this argument. - if (!parsed.isPropertyAccessor()) { - Identifier oldLabel = args->getElementName(selfIndex); - StringRef oldLabelStr; - if (!oldLabel.empty()) - oldLabelStr = oldLabel.str(); - parsed.ArgumentLabels.insert(parsed.ArgumentLabels.begin() + selfIndex, - oldLabelStr); - } + // Prefer the r-paren location, so that we get the right behavior when + // there's a trailing closure, but handle some implicit cases too. + removeRangeEnd = argList.rParenLoc; + if (removeRangeEnd.isInvalid()) + removeRangeEnd = argExpr->getEndLoc(); } else { - if (selfIndex != 0 || !parsed.ArgumentLabels.empty()) - return; - selfExpr = cast(argExpr)->getSubExpr(); - // Remove from after the open paren to the close paren (half-open). - removeRangeStart = Lexer::getLocForEndOfToken(sourceMgr, - argExpr->getStartLoc()); - removeRangeEnd = argExpr->getEndLoc(); + // Remove from the label to the start of the next argument (half-open). + SourceLoc labelLoc = argList.labelLocs[selfIndex]; + if (labelLoc.isValid()) + removeRangeStart = labelLoc; + else + removeRangeStart = selfExpr->getStartLoc(); + + SourceLoc nextLabelLoc = argList.labelLocs[selfIndex + 1]; + if (nextLabelLoc.isValid()) + removeRangeEnd = nextLabelLoc; + else + removeRangeEnd = argList.args[selfIndex + 1]->getStartLoc(); + } + + // Avoid later argument label fix-its for this argument. + if (!parsed.isPropertyAccessor()) { + Identifier oldLabel = argList.labels[selfIndex]; + StringRef oldLabelStr; + if (!oldLabel.empty()) + oldLabelStr = oldLabel.str(); + parsed.ArgumentLabels.insert(parsed.ArgumentLabels.begin() + selfIndex, + oldLabelStr); } if (auto *inoutSelf = dyn_cast(selfExpr)) @@ -1698,7 +1690,9 @@ static void fixItAvailableAttrRename(InFlightDiagnostic &diag, if (!call || !isa(call)) return; - const Expr *argExpr = call->getArg(); + auto *argExpr = call->getArg(); + auto argList = getOriginalArgumentList(argExpr); + if (parsed.IsGetter) { diag.fixItRemove(argExpr->getSourceRange()); return; @@ -1707,16 +1701,16 @@ static void fixItAvailableAttrRename(InFlightDiagnostic &diag, if (parsed.IsSetter) { const Expr *newValueExpr = nullptr; - if (auto args = dyn_cast(argExpr)) { + if (argList.args.size() >= 1) { size_t newValueIndex = 0; if (parsed.isInstanceMember()) { assert(parsed.SelfIndex.getValue() == 0 || parsed.SelfIndex.getValue() == 1); newValueIndex = !parsed.SelfIndex.getValue(); } - newValueExpr = args->getElement(newValueIndex); + newValueExpr = argList.args[newValueIndex]; } else { - newValueExpr = cast(argExpr)->getSubExpr(); + newValueExpr = argList.args[0]; } diag.fixItReplaceChars(argExpr->getStartLoc(), newValueExpr->getStartLoc(), @@ -1738,33 +1732,28 @@ static void fixItAvailableAttrRename(InFlightDiagnostic &diag, return labelStr.empty() ? Identifier() : ctx.getIdentifier(labelStr); }); - if (auto args = dyn_cast(argExpr)) { - argExpr = args->getSubExpr(); - - // Coerce the `argumentLabelIDs` to the user supplied arguments. - // e.g: - // @available(.., renamed: "new(w:x:y:z:)") - // func old(a: Int, b: Int..., c: String="", d: Int=0){} - // old(a: 1, b: 2, 3, 4, d: 5) - // coerce - // argumentLabelIDs = {"w", "x", "y", "z"} - // to - // argumentLabelIDs = {"w", "x", "", "", "z"} - auto elementMap = args->getElementMapping(); - if (elementMap.size() != argumentLabelIDs.size()) { - // Mismatched lengths; give up. + // Coerce the `argumentLabelIDs` to the user supplied arguments. + // e.g: + // @available(.., renamed: "new(w:x:y:z:)") + // func old(a: Int, b: Int..., c: String="", d: Int=0){} + // old(a: 1, b: 2, 3, 4, d: 5) + // coerce + // argumentLabelIDs = {"w", "x", "y", "z"} + // to + // argumentLabelIDs = {"w", "x", "", "", "z"} + auto I = argumentLabelIDs.begin(); + + auto updateLabelsForArg = [&](Expr *expr) { + if (isa(expr) || + isa(expr)) { + // Defaulted: remove param label of it. + I = argumentLabelIDs.erase(I); return; } - auto I = argumentLabelIDs.begin(); - for (auto shuffleIdx : elementMap) { - switch (shuffleIdx) { - case ArgumentShuffleExpr::DefaultInitialize: - case ArgumentShuffleExpr::CallerDefaultInitialize: - // Defaulted: remove param label of it. - I = argumentLabelIDs.erase(I); - break; - case ArgumentShuffleExpr::Variadic: { - auto variadicArgsNum = args->getVariadicArgs().size(); + + if (auto *varargExpr = dyn_cast(expr)) { + if (auto *arrayExpr = dyn_cast(varargExpr->getSubExpr())) { + auto variadicArgsNum = arrayExpr->getNumElements(); if (variadicArgsNum == 0) { // No arguments: Remove param label of it. I = argumentLabelIDs.erase(I); @@ -1772,65 +1761,42 @@ static void fixItAvailableAttrRename(InFlightDiagnostic &diag, // One argument: Just advance. ++I; } else { + ++I; + // Two or more arguments: Insert empty labels after the first one. - I = argumentLabelIDs.insert(++I, --variadicArgsNum, Identifier()); + variadicArgsNum--; + I = argumentLabelIDs.insert(I, variadicArgsNum, Identifier()); I += variadicArgsNum; } - break; - } - default: - // Normal: Just advance. - assert(shuffleIdx == (I - argumentLabelIDs.begin()) && - "SE-0060 guarantee"); - ++I; - break; + return; } } - } - if (auto args = dyn_cast(argExpr)) { - if (argumentLabelIDs.size() != args->getNumElements()) { - // Mismatched lengths; give up. - return; - } - - auto argumentLabelsToCheck = llvm::makeArrayRef(argumentLabelIDs); - // The argument label for a trailing closure is ignored. - if (args->hasTrailingClosure()) - argumentLabelsToCheck = argumentLabelsToCheck.drop_back(); - - if (args->hasElementNames()) { - if (std::equal(argumentLabelsToCheck.begin(), argumentLabelsToCheck.end(), - args->getElementNames().begin())) { - // Already matching. - return; - } + // Normal: Just advance. + ++I; + }; - } else { - if (std::all_of(argumentLabelsToCheck.begin(),argumentLabelsToCheck.end(), - std::mem_fn(&Identifier::empty))) { - // Already matching (as in, there are no labels). - return; - } - } + if (auto *parenExpr = dyn_cast(argExpr)) { + updateLabelsForArg(parenExpr->getSubExpr()); + } else { + for (auto *arg : cast(argExpr)->getElements()) + updateLabelsForArg(arg); + } - } else if (auto args = dyn_cast(argExpr)) { - if (args->hasTrailingClosure()) { - // The argument label for a trailing closure is ignored. - return; - } + if (argumentLabelIDs.size() != argList.args.size()) { + // Mismatched lengths; give up. + return; + } - if (argumentLabelIDs.size() != 1) { - // Mismatched lengths; give up. - return; - } + auto argumentLabelsToCheck = llvm::makeArrayRef(argumentLabelIDs); + // The argument label for a trailing closure is ignored. + if (argList.hasTrailingClosure) + argumentLabelsToCheck = argumentLabelsToCheck.drop_back(); - if (argumentLabelIDs.front().empty()) { - // Already matching (no labels). - return; - } - } else { - llvm_unreachable("Unexpected arg expression"); + if (std::equal(argumentLabelsToCheck.begin(), argumentLabelsToCheck.end(), + argList.labels.begin())) { + // Already matching. + return; } diagnoseArgumentLabelError(ctx, argExpr, argumentLabelIDs, false, &diag); diff --git a/lib/Sema/TypeCheckError.cpp b/lib/Sema/TypeCheckError.cpp index 60084c8c6b501..0fbbda4741f38 100644 --- a/lib/Sema/TypeCheckError.cpp +++ b/lib/Sema/TypeCheckError.cpp @@ -679,6 +679,12 @@ class ApplyClassifier { Classification classifyRethrowsArgument(Expr *arg, Type paramType) { arg = arg->getValueProvidingExpr(); + if (isa(arg) || + isa(arg)) { + return classifyArgumentByType(arg->getType(), + PotentialReason::forDefaultArgument()); + } + // If this argument is `nil` literal or `.none`, // it doesn't cause the call to throw. if (auto *DSCE = dyn_cast(arg)) { @@ -694,8 +700,6 @@ class ApplyClassifier { if (auto paramTupleType = dyn_cast(paramType.getPointer())) { if (auto tuple = dyn_cast(arg)) { return classifyTupleRethrowsArgument(tuple, paramTupleType); - } else if (auto shuffle = dyn_cast(arg)) { - return classifyShuffleRethrowsArgument(shuffle, paramTupleType); } if (paramTupleType->getNumElements() != 1) { @@ -709,7 +713,7 @@ class ApplyClassifier { // FIXME: There's a case where we can end up with an ApplyExpr that // has a single-element-tuple argument type, but the argument is just - // a ClosureExpr and not a TupleExpr/ArgumentShuffleExpr. + // a ClosureExpr and not a TupleExpr. paramType = paramTupleType->getElementType(0); } @@ -756,79 +760,6 @@ class ApplyClassifier { return result; } - /// Classify an argument to a 'rethrows' function that's a tuple shuffle. - Classification classifyShuffleRethrowsArgument(ArgumentShuffleExpr *shuffle, - TupleType *paramTupleType) { - auto reversedParamType = - reverseShuffleParamType(shuffle, paramTupleType); - - // Classify the operand. - auto result = classifyRethrowsArgument(shuffle->getSubExpr(), - reversedParamType); - - // Check for default arguments in the shuffle. - for (auto i : indices(shuffle->getElementMapping())) { - // If this element comes from the sub-expression, we've already - // analyzed it. (Variadic arguments also end up here, which is - // correct for our purposes.) - auto elt = shuffle->getElementMapping()[i]; - if (elt >= 0) { - // Ignore. - - // Otherwise, it might come from a default argument. It still - // might contribute to 'rethrows', but treat it as an opaque source. - } else if (elt == ArgumentShuffleExpr::DefaultInitialize || - elt == ArgumentShuffleExpr::CallerDefaultInitialize) { - result.merge(classifyArgumentByType(paramTupleType->getElementType(i), - PotentialReason::forDefaultArgument())); - } - } - - return result; - } - - /// Given a tuple shuffle and an original parameter type, construct - /// the type of the source of the tuple shuffle preserving as much - /// information as possible from the original parameter type. - Type reverseShuffleParamType(ArgumentShuffleExpr *shuffle, - TupleType *origParamTupleType) { - SmallVector origSrcElts; - if (shuffle->isSourceScalar()) { - origSrcElts.append(1, TupleTypeElt()); - } else { - auto srcTupleType = shuffle->getSubExpr()->getType()->castTo(); - origSrcElts.append(srcTupleType->getNumElements(), TupleTypeElt()); - } - - auto mapping = shuffle->getElementMapping(); - for (unsigned destIndex = 0; destIndex != mapping.size(); ++destIndex) { - auto srcIndex = mapping[destIndex]; - if (srcIndex >= 0) { - origSrcElts[srcIndex] = origParamTupleType->getElement(destIndex); - } else if (srcIndex == ArgumentShuffleExpr::DefaultInitialize || - srcIndex == ArgumentShuffleExpr::CallerDefaultInitialize) { - // Nothing interesting from the source expression. - } else if (srcIndex == ArgumentShuffleExpr::Variadic) { - // Variadic arguments never contribute to 'rethrows'. - // Assign the rest of the source elements parameter types that will - // cause the recursive walker to ignore them. - for (unsigned srcIndex : shuffle->getVariadicArgs()) { - assert(srcIndex >= 0 && "default-initialized variadic argument?"); - origSrcElts[srcIndex] = - origParamTupleType->getASTContext().TheRawPointerType; - } - } else { - llvm_unreachable("bad source-element mapping!"); - } - } - - if (shuffle->isSourceScalar()) { - return origSrcElts[0].getType(); - } else { - return TupleType::get(origSrcElts, origParamTupleType->getASTContext()); - } - } - /// Given the type of an argument, try to determine if it contains /// a throwing function in a way that is permitted to cause a /// 'rethrows' function to throw. diff --git a/test/Interpreter/repl.swift b/test/Interpreter/repl.swift index f37d76cd69e51..1eedb45e12bcf 100644 --- a/test/Interpreter/repl.swift +++ b/test/Interpreter/repl.swift @@ -46,22 +46,22 @@ hashValue // Check that we handle unmatched parentheses in REPL. 1+1) -var z = 44 +var z = 46 +z -// CHECK: Int = 44{{$}} +// CHECK: Int = 46{{$}} -+44 -// CHECK: Int = 44{{$}} ++48 +// CHECK: Int = 48{{$}} typealias Foo = Int var f1 : Foo = 1 -var f44 : Foo = 44 +var f50 : Foo = 50 f1 + - f44 -// CHECK: Foo = 45{{$}} -+(f44) -// CHECK: Foo = 44{{$}} + f50 +// CHECK: Foo = 51{{$}} ++(f50) +// CHECK: Foo = 50{{$}} 1.5 // CHECK: Double = 1.5{{$}} diff --git a/test/SILGen/scalar_to_tuple_args.swift b/test/SILGen/scalar_to_tuple_args.swift index 83f203b1b2a86..a549998b8f8da 100644 --- a/test/SILGen/scalar_to_tuple_args.swift +++ b/test/SILGen/scalar_to_tuple_args.swift @@ -7,7 +7,7 @@ func inoutWithCallerSideDefaults(_ x: inout Int, y: Int = #line) {} func scalarWithDefaults(_ x: Int, y: Int = 0, z: Int = 0) {} func scalarWithCallerSideDefaults(_ x: Int, y: Int = #line) {} -func tupleWithDefaults(x x: (Int, Int), y: Int = 0, z: Int = 0) {} +func tupleWithDefaults(x: (Int, Int), y: Int = 0, z: Int = 0) {} func variadicFirst(_ x: Int...) {} func variadicSecond(_ x: Int, _ y: Int...) {} @@ -57,16 +57,15 @@ tupleWithDefaults(x: (x,x)) // CHECK: ([[ARRAY:%.*]], [[MEMORY:%.*]]) = destructure_tuple [[ALLOC_ARRAY]] // CHECK: [[ADDR:%.*]] = pointer_to_address [[MEMORY]] // CHECK: [[READ:%.*]] = begin_access [read] [dynamic] [[X_ADDR]] : $*Int -// CHECK: [[X:%.*]] = load [trivial] [[READ]] -// CHECK: store [[X]] to [trivial] [[ADDR]] +// CHECK: copy_addr [[READ]] to [initialization] [[ADDR]] // CHECK: [[VARIADIC_FIRST:%.*]] = function_ref @$s20scalar_to_tuple_args13variadicFirstyySid_tF // CHECK: apply [[VARIADIC_FIRST]]([[ARRAY]]) variadicFirst(x) -// CHECK: [[ALLOC_ARRAY:%.*]] = apply {{.*}} -> (@owned Array<τ_0_0>, Builtin.RawPointer) -// CHECK: ([[ARRAY:%.*]], [[MEMORY:%.*]]) = destructure_tuple [[ALLOC_ARRAY]] // CHECK: [[READ:%.*]] = begin_access [read] [dynamic] [[X_ADDR]] : $*Int // CHECK: [[X:%.*]] = load [trivial] [[READ]] +// CHECK: [[ALLOC_ARRAY:%.*]] = apply {{.*}} -> (@owned Array<τ_0_0>, Builtin.RawPointer) +// CHECK: ([[ARRAY:%.*]], [[MEMORY:%.*]]) = destructure_tuple [[ALLOC_ARRAY]] // CHECK: [[VARIADIC_SECOND:%.*]] = function_ref @$s20scalar_to_tuple_args14variadicSecondyySi_SidtF // CHECK: apply [[VARIADIC_SECOND]]([[X]], [[ARRAY]]) variadicSecond(x) diff --git a/test/SILGen/sil_locations.swift b/test/SILGen/sil_locations.swift index 60814ac210fbe..850f58dae20c5 100644 --- a/test/SILGen/sil_locations.swift +++ b/test/SILGen/sil_locations.swift @@ -261,7 +261,7 @@ func tuple_element(_ x: (Int, Float)) { func containers() -> ([Int], Dictionary) { return ([1, 2, 3], ["Ankeny": 1, "Burnside": 2, "Couch": 3]) // CHECK-LABEL: sil hidden [ossa] @$s13sil_locations10containers{{[_0-9a-zA-Z]*}}F - // CHECK: apply {{%.*}}<(String, Int)>({{%.*}}), loc "{{.*}}":[[@LINE-2]]:22 + // CHECK: apply {{%.*}}<(String, Int)>({{%.*}}), loc "{{.*}}":[[@LINE-2]]:23 // CHECK: string_literal utf8 "Ankeny", loc "{{.*}}":[[@LINE-4]]:23 diff --git a/test/SILGen/stored_property_default_arg.swift b/test/SILGen/stored_property_default_arg.swift index 62beda70a00a3..039418fd59578 100644 --- a/test/SILGen/stored_property_default_arg.swift +++ b/test/SILGen/stored_property_default_arg.swift @@ -7,14 +7,15 @@ struct A { var c: Bool = false } +// CHECK-LABEL: sil hidden [ossa] @$s27stored_property_default_arg17checkConcreteTypeyyF : $@convention(thin) () -> () { +func checkConcreteType() { // CHECK: function_ref variable initialization expression of A.c // CHECK-NEXT: [[C1_REF:%.*]] = function_ref @$s27stored_property_default_arg1AV1cSbvpfi : $@convention(thin) () -> Bool // CHECK-NEXT: [[C1:%.*]] = apply [[C1_REF]]() : $@convention(thin) () -> Bool // CHECK-NEXT: function_ref A.init(b:c:) // CHECK-NEXT: [[A1_REF:%.*]] = function_ref @$s27stored_property_default_arg1AV1b1cACSi_SbtcfC : $@convention(method) (Int, Bool, @thin A.Type) -> A // CHECK-NEXT: {{.*}} = apply [[A1_REF]]({{.*}}, [[C1]], {{.*}}) : $@convention(method) (Int, Bool, @thin A.Type) -> A - -let d = A(b: 1) + let d = A(b: 1) // CHECK: function_ref variable initialization expression of A.b // CHECK-NEXT: [[B1_REF:%.*]] = function_ref @$s27stored_property_default_arg1AV1bSivpfi : $@convention(thin) () -> Int @@ -22,40 +23,43 @@ let d = A(b: 1) // CHECK-NEXT: function_ref A.init(b:c:) // CHECK-NEXT: [[A2_REF:%.*]] = function_ref @$s27stored_property_default_arg1AV1b1cACSi_SbtcfC : $@convention(method) (Int, Bool, @thin A.Type) -> A // CHECK-NEXT: {{.*}} = apply [[A2_REF]]([[B1]], {{.*}}, {{.*}}) : $@convention(method) (Int, Bool, @thin A.Type) -> A - -let e = A(c: true) + let e = A(c: true) +} struct F { var g: T var h: Int = 0 } +// CHECK-LABEL: sil hidden [ossa] @$s27stored_property_default_arg16checkGenericTypeyyF : $@convention(thin) () -> () { +func checkGenericType() { // CHECK: function_ref variable initialization expression of F.h // CHECK-NEXT: [[H1_REF:%.*]] = function_ref @$s27stored_property_default_arg1FV1hSivpfi : $@convention(thin) <τ_0_0> () -> Int // CHECK-NEXT: [[H1:%.*]] = apply [[H1_REF]]() : $@convention(thin) <τ_0_0> () -> Int // CHECK-NEXT: function_ref F.init(g:h:) // CHECK-NEXT: [[F1_REF:%.*]] = function_ref @$s27stored_property_default_arg1FV1g1hACyxGx_SitcfC : $@convention(method) <τ_0_0> (@in τ_0_0, Int, @thin F<τ_0_0>.Type) -> @out F<τ_0_0> // CHECK-NEXT: {{.*}} = apply [[F1_REF]]({{.*}}, {{.*}}, [[H1]], {{.*}}) : $@convention(method) <τ_0_0> (@in τ_0_0, Int, @thin F<τ_0_0>.Type) -> @out F<τ_0_0> - -let i = F(g: 128) + let i = F(g: 128) +} struct J { lazy var k: Bool = false lazy var l: Int = 0 } +// CHECK-LABEL: sil hidden [ossa] @$s27stored_property_default_arg16checkOptionalNilyyF : $@convention(thin) () -> () { +func checkOptionalNil() { // CHECK: {{.*}} = metatype $@thin Optional.Type // CHECK-NEXT: [[L1_REF:%.*]] = enum $Optional, #Optional.none!enumelt // CHECK-NEXT: function_ref J.init(k:l:) // CHECK-NEXT: [[J1_REF:%.*]] = function_ref @$s27stored_property_default_arg1JV1k1lACSbSg_SiSgtcfC : $@convention(method) (Optional, Optional, @thin J.Type) -> J // CHECK-NEXT: {{.*}} = apply [[J1_REF]]({{.*}}, [[L1_REF]], {{.*}}) : $@convention(method) (Optional, Optional, @thin J.Type) -> J - -let m = J(k: true) + let m = J(k: true) // CHECK: {{.*}} = metatype $@thin Optional.Type // CHECK-NEXT: [[K1_REF:%.*]] = enum $Optional, #Optional.none!enumelt -// CHECK-NEXT: function_ref J.init(k:l:) +// CHECK: function_ref J.init(k:l:) // CHECK-NEXT: [[J2_REF:%.*]] = function_ref @$s27stored_property_default_arg1JV1k1lACSbSg_SiSgtcfC : $@convention(method) (Optional, Optional, @thin J.Type) -> J // CHECK-NEXT: {{.*}} = apply [[J2_REF]]([[K1_REF]], {{.*}}, {{.*}}) : $@convention(method) (Optional, Optional, @thin J.Type) -> J - -let n = J(l: 316) + let n = J(l: 316) +}