Merge pull request #9933 from jckarter/partial-key-path-application
Support application of AnyKeyPath/PartialKeyPath.
diff --git a/benchmark/single-source/Substring.swift b/benchmark/single-source/Substring.swift
index cb520fd..011866c 100644
--- a/benchmark/single-source/Substring.swift
+++ b/benchmark/single-source/Substring.swift
@@ -59,3 +59,155 @@
}
}
+private func equivalentWithDistinctBuffers() -> (String, Substring) {
+ var s0 = longWide
+ withUnsafeMutablePointer(to: &s0) { blackHole($0) }
+ s0 += "!"
+
+ // These two should be equal but with distinct buffers, both refcounted.
+ let a = Substring(s0).dropFirst()
+ let b = String(a)
+ return (b, a)
+}
+
+@inline(never)
+public func run_EqualStringSubstring(_ N: Int) {
+ let (a, b) = equivalentWithDistinctBuffers()
+ for _ in 1...N*500 {
+ blackHole(a == b)
+ }
+}
+
+@inline(never)
+public func run_EqualSubstringString(_ N: Int) {
+ let (a, b) = equivalentWithDistinctBuffers()
+ for _ in 1...N*500 {
+ blackHole(b == a)
+ }
+}
+
+@inline(never)
+public func run_EqualSubstringSubstring(_ N: Int) {
+ let (_, a) = equivalentWithDistinctBuffers()
+ let (_, b) = equivalentWithDistinctBuffers()
+ for _ in 1...N*500 {
+ blackHole(a == b)
+ }
+}
+
+@inline(never)
+public func run_EqualSubstringSubstringGenericEquatable(_ N: Int) {
+ let (_, a) = equivalentWithDistinctBuffers()
+ let (_, b) = equivalentWithDistinctBuffers()
+ func check<T>(_ x: T, _ y: T) where T : Equatable {
+ blackHole(x == y)
+ }
+ for _ in 1...N*500 {
+ check(a, b)
+ }
+}
+
+/*
+func checkEqual<T, U>(_ x: T, _ y: U)
+where T : StringProtocol, U : StringProtocol {
+ blackHole(x == y)
+}
+
+@inline(never)
+public func run _EqualStringSubstringGenericStringProtocol(_ N: Int) {
+ let (a, b) = equivalentWithDistinctBuffers()
+ for _ in 1...N*500 {
+ checkEqual(a, b)
+ }
+}
+
+@inline(never)
+public func run _EqualSubstringStringGenericStringProtocol(_ N: Int) {
+ let (a, b) = equivalentWithDistinctBuffers()
+ for _ in 1...N*500 {
+ checkEqual(b, a)
+ }
+}
+
+@inline(never)
+public func run _EqualSubstringSubstringGenericStringProtocol(_ N: Int) {
+ let (_, a) = equivalentWithDistinctBuffers()
+ let (_, b) = equivalentWithDistinctBuffers()
+ for _ in 1...N*500 {
+ checkEqual(a, b)
+ }
+}
+*/
+
+//===----------------------------------------------------------------------===//
+
+/*
+@inline(never)
+public func run _LessStringSubstring(_ N: Int) {
+ let (a, b) = equivalentWithDistinctBuffers()
+ for _ in 1...N*500 {
+ blackHole(a < b)
+ }
+}
+
+@inline(never)
+public func run _LessSubstringString(_ N: Int) {
+ let (a, b) = equivalentWithDistinctBuffers()
+ for _ in 1...N*500 {
+ blackHole(b < a)
+ }
+}
+*/
+
+@inline(never)
+public func run_LessSubstringSubstring(_ N: Int) {
+ let (_, a) = equivalentWithDistinctBuffers()
+ let (_, b) = equivalentWithDistinctBuffers()
+ for _ in 1...N*500 {
+ blackHole(a < b)
+ }
+}
+
+@inline(never)
+public func run_LessSubstringSubstringGenericComparable(_ N: Int) {
+ let (_, a) = equivalentWithDistinctBuffers()
+ let (_, b) = equivalentWithDistinctBuffers()
+ func check<T>(_ x: T, _ y: T) where T : Comparable {
+ blackHole(x < y)
+ }
+ for _ in 1...N*500 {
+ check(a, b)
+ }
+}
+
+/*
+func checkLess<T, U>(_ x: T, _ y: U)
+where T : StringProtocol, U : StringProtocol {
+ blackHole(x < y)
+}
+
+@inline(never)
+public func run _LessStringSubstringGenericStringProtocol(_ N: Int) {
+ let (a, b) = equivalentWithDistinctBuffers()
+ for _ in 1...N*500 {
+ checkLess(a, b)
+ }
+}
+
+@inline(never)
+public func run _LessSubstringStringGenericStringProtocol(_ N: Int) {
+ let (a, b) = equivalentWithDistinctBuffers()
+ for _ in 1...N*500 {
+ checkLess(b, a)
+ }
+}
+
+@inline(never)
+public func run _LessSubstringSubstringGenericStringProtocol(_ N: Int) {
+ let (_, a) = equivalentWithDistinctBuffers()
+ let (_, b) = equivalentWithDistinctBuffers()
+ for _ in 1...N*500 {
+ checkLess(a, b)
+ }
+}
+*/
diff --git a/benchmark/utils/main.swift b/benchmark/utils/main.swift
index 70a90a7..420e753 100644
--- a/benchmark/utils/main.swift
+++ b/benchmark/utils/main.swift
@@ -229,6 +229,10 @@
addTo(&precommitTests, "DropWhileCountableRangeLazy", run_DropWhileCountableRangeLazy)
addTo(&precommitTests, "DropWhileSequence", run_DropWhileSequence)
addTo(&precommitTests, "DropWhileSequenceLazy", run_DropWhileSequenceLazy)
+addTo(&precommitTests, "EqualStringSubstring", run_EqualStringSubstring)
+addTo(&precommitTests, "EqualSubstringString", run_EqualSubstringString)
+addTo(&precommitTests, "EqualSubstringSubstring", run_EqualSubstringSubstring)
+addTo(&precommitTests, "EqualSubstringSubstringGenericEquatable", run_EqualSubstringSubstringGenericEquatable)
addTo(&precommitTests, "ErrorHandling", run_ErrorHandling)
addTo(&precommitTests, "GlobalClass", run_GlobalClass)
addTo(&precommitTests, "Hanoi", run_Hanoi)
@@ -239,6 +243,8 @@
addTo(&precommitTests, "Join", run_Join)
addTo(&precommitTests, "LazilyFilteredArrays", run_LazilyFilteredArrays)
addTo(&precommitTests, "LazilyFilteredRange", run_LazilyFilteredRange)
+addTo(&precommitTests, "LessSubstringSubstring", run_LessSubstringSubstring)
+addTo(&precommitTests, "LessSubstringSubstringGenericComparable", run_LessSubstringSubstringGenericComparable)
addTo(&precommitTests, "LinkedList", run_LinkedList)
addTo(&precommitTests, "MapReduce", run_MapReduce)
addTo(&precommitTests, "MapReduceAnyCollection", run_MapReduceAnyCollection)
diff --git a/docs/ABI.rst b/docs/ABI.rst
index 58e2b5d..a3a3fc6 100644
--- a/docs/ABI.rst
+++ b/docs/ABI.rst
@@ -826,7 +826,8 @@
global ::= protocol-conformance entity 'TW' // protocol witness thunk
global ::= context identifier identifier 'TB' // property behavior initializer thunk (not used currently)
global ::= context identifier identifier 'Tb' // property behavior setter thunk (not used currently)
- global ::= global 'T_' specialization // reset substitutions before demangling specialization
+ global ::= global specialization // function specialization
+ global ::= global 'Tm' // merged function
global ::= entity // some identifiable thing
global ::= type type generic-signature? 'T' REABSTRACT-THUNK-TYPE // reabstraction thunk helper function
diff --git a/include/swift/AST/Attr.def b/include/swift/AST/Attr.def
index d96613b..22b0dbb 100644
--- a/include/swift/AST/Attr.def
+++ b/include/swift/AST/Attr.def
@@ -286,6 +286,11 @@
OnClass | NotSerialized | LongAttribute,
/*Not serialized */ 70)
+// HACK: Attribute needed to preserve source compatibility by downgrading errors
+// due to an SDK change in Dispatch
+SIMPLE_DECL_ATTR(_downgrade_exhaustivity_check, DowngradeExhaustivityCheck,
+ OnEnumElement | LongAttribute | UserInaccessible, 71)
+
#undef TYPE_ATTR
#undef DECL_ATTR_ALIAS
#undef SIMPLE_DECL_ATTR
diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def
index 0292fb5..46660fa 100644
--- a/include/swift/AST/DiagnosticsSema.def
+++ b/include/swift/AST/DiagnosticsSema.def
@@ -3724,6 +3724,10 @@
WARNING(redundant_particular_case,none,
"case is already handled by previous patterns; consider removing it",())
+// HACK: Downgrades the above to warnings if any of the cases is marked
+// @_downgrade_exhaustivity_check.
+WARNING(non_exhaustive_switch_warn_swift3,none, "switch must be exhaustive", ())
+
#ifndef DIAG_NO_UNDEF
# if defined(DIAG)
# undef DIAG
diff --git a/include/swift/AST/Expr.h b/include/swift/AST/Expr.h
index a6933fb..2482540 100644
--- a/include/swift/AST/Expr.h
+++ b/include/swift/AST/Expr.h
@@ -179,10 +179,9 @@
friend class UnresolvedDeclRefExpr;
unsigned : NumExprBits;
unsigned DeclRefKind : 2;
- unsigned IsSpecialized : 1;
unsigned FunctionRefKind : 2;
};
- enum { NumUnresolvedDeclRefExprBits = NumExprBits + 5 };
+ enum { NumUnresolvedDeclRefExprBits = NumExprBits + 4 };
static_assert(NumUnresolvedDeclRefExprBits <= 32, "fits in an unsigned");
class MemberRefExprBitfields {
@@ -272,14 +271,6 @@
enum { NumOverloadSetRefExprBits = NumExprBits + 2};
static_assert(NumOverloadSetRefExprBits <= 32, "fits in an unsigned");
- class OverloadedDeclRefExprBitfields {
- friend class OverloadedDeclRefExpr;
- unsigned : NumOverloadSetRefExprBits;
- unsigned IsSpecialized : 1;
- };
- enum { NumOverloadedDeclRefExprBits = NumOverloadSetRefExprBits + 1 };
- static_assert(NumOverloadedDeclRefExprBits <= 32, "fits in an unsigned");
-
class BooleanLiteralExprBitfields {
friend class BooleanLiteralExpr;
unsigned : NumLiteralExprBits;
@@ -432,7 +423,6 @@
DynamicSubscriptExprBitfields DynamicSubscriptExprBits;
UnresolvedMemberExprBitfields UnresolvedMemberExprBits;
OverloadSetRefExprBitfields OverloadSetRefExprBits;
- OverloadedDeclRefExprBitfields OverloadedDeclRefExprBits;
BooleanLiteralExprBitfields BooleanLiteralExprBits;
MagicIdentifierLiteralExprBitfields MagicIdentifierLiteralExprBits;
ObjectLiteralExprBitfields ObjectLiteralExprBits;
@@ -1249,27 +1239,15 @@
/// DeclRefExpr - A reference to a value, "x".
class DeclRefExpr : public Expr {
- /// This is used when the reference is specialized, e.g "GenCls<Int>", to
- /// hold information about the generic arguments.
- struct SpecializeInfo {
- ConcreteDeclRef D;
- ArrayRef<TypeRepr*> GenericArgs;
- };
-
- /// \brief The declaration pointer or SpecializeInfo pointer if it was
- /// explicitly specialized with <...>.
- llvm::PointerUnion<ConcreteDeclRef, SpecializeInfo *> DOrSpecialized;
+ /// \brief The declaration pointer.
+ ConcreteDeclRef D;
DeclNameLoc Loc;
- SpecializeInfo *getSpecInfo() const {
- return DOrSpecialized.dyn_cast<SpecializeInfo*>();
- }
-
public:
DeclRefExpr(ConcreteDeclRef D, DeclNameLoc Loc, bool Implicit,
AccessSemantics semantics = AccessSemantics::Ordinary,
Type Ty = Type())
- : Expr(ExprKind::DeclRef, Implicit, Ty), DOrSpecialized(D), Loc(Loc) {
+ : Expr(ExprKind::DeclRef, Implicit, Ty), D(D), Loc(Loc) {
DeclRefExprBits.Semantics = (unsigned) semantics;
DeclRefExprBits.FunctionRefKind =
static_cast<unsigned>(Loc.isCompound() ? FunctionRefKind::Compound
@@ -1289,29 +1267,9 @@
/// Retrieve the concrete declaration reference.
ConcreteDeclRef getDeclRef() const {
- if (auto Spec = getSpecInfo())
- return Spec->D;
- return DOrSpecialized.get<ConcreteDeclRef>();
+ return D;
}
- void setSpecialized();
-
- /// \brief Determine whether this declaration reference was immediately
- /// specialized by <...>.
- bool isSpecialized() const { return getSpecInfo() != nullptr; }
-
- /// Set the generic arguments.
- ///
- /// This copies the array using ASTContext's allocator.
- void setGenericArgs(ArrayRef<TypeRepr*> GenericArgs);
-
- /// Returns the generic arguments if it was specialized or an empty array
- /// otherwise.
- ArrayRef<TypeRepr *> getGenericArgs() const {
- if (auto Spec = getSpecInfo())
- return Spec->GenericArgs;
- return ArrayRef<TypeRepr *>();
- }
SourceRange getSourceRange() const { return Loc.getSourceRange(); }
SourceLoc getLoc() const { return Loc.getBaseNameLoc(); }
DeclNameLoc getNameLoc() const { return Loc; }
@@ -1507,25 +1465,17 @@
public:
OverloadedDeclRefExpr(ArrayRef<ValueDecl*> Decls, DeclNameLoc Loc,
- bool isSpecialized,
FunctionRefKind functionRefKind,
bool Implicit, Type Ty = Type())
: OverloadSetRefExpr(ExprKind::OverloadedDeclRef, Decls, functionRefKind,
Implicit, Ty),
Loc(Loc) {
- OverloadedDeclRefExprBits.IsSpecialized = isSpecialized;
}
DeclNameLoc getNameLoc() const { return Loc; }
SourceLoc getLoc() const { return Loc.getBaseNameLoc(); }
SourceRange getSourceRange() const { return Loc.getSourceRange(); }
- /// \brief Determine whether this declaration reference was immediately
- /// specialized by <...>.
- bool isSpecialized() const {
- return OverloadedDeclRefExprBits.IsSpecialized;
- }
-
static bool classof(const Expr *E) {
return E->getKind() == ExprKind::OverloadedDeclRef;
}
@@ -1545,7 +1495,6 @@
: Expr(ExprKind::UnresolvedDeclRef, /*Implicit=*/loc.isInvalid()),
Name(name), Loc(loc) {
UnresolvedDeclRefExprBits.DeclRefKind = static_cast<unsigned>(refKind);
- UnresolvedDeclRefExprBits.IsSpecialized = false;
UnresolvedDeclRefExprBits.FunctionRefKind =
static_cast<unsigned>(Loc.isCompound() ? FunctionRefKind::Compound
: FunctionRefKind::Unapplied);
@@ -1558,14 +1507,6 @@
return static_cast<DeclRefKind>(UnresolvedDeclRefExprBits.DeclRefKind);
}
- void setSpecialized(bool specialized) {
- UnresolvedDeclRefExprBits.IsSpecialized = specialized;
- }
-
- /// \brief Determine whether this declaration reference was immediately
- /// specialized by <...>.
- bool isSpecialized() const { return UnresolvedDeclRefExprBits.IsSpecialized; }
-
/// Retrieve the kind of function reference.
FunctionRefKind getFunctionRefKind() const {
return static_cast<FunctionRefKind>(
diff --git a/include/swift/AST/Initializer.h b/include/swift/AST/Initializer.h
index 3b4ca5c..754f5a6 100644
--- a/include/swift/AST/Initializer.h
+++ b/include/swift/AST/Initializer.h
@@ -70,17 +70,21 @@
class PatternBindingInitializer : public Initializer {
PatternBindingDecl *Binding;
+ // created lazily for 'self' lookup from lazy property initializer
+ ParamDecl *SelfParam;
+
friend class ASTContext; // calls reset on unused contexts
void reset(DeclContext *parent) {
setParent(parent);
Binding = nullptr;
+ SelfParam = nullptr;
}
public:
explicit PatternBindingInitializer(DeclContext *parent)
: Initializer(InitializerKind::PatternBinding, parent),
- Binding(nullptr) {
+ Binding(nullptr), SelfParam(nullptr) {
SpareBits = 0;
}
@@ -95,6 +99,8 @@
unsigned getBindingIndex() const { return SpareBits; }
+ ParamDecl *getImplicitSelfDecl();
+
static bool classof(const DeclContext *DC) {
if (auto init = dyn_cast<Initializer>(DC))
return classof(init);
diff --git a/include/swift/AST/LazyResolver.h b/include/swift/AST/LazyResolver.h
index d5652ed..3f8f8c9 100644
--- a/include/swift/AST/LazyResolver.h
+++ b/include/swift/AST/LazyResolver.h
@@ -82,9 +82,6 @@
/// Bind an extension to its extended type.
virtual void bindExtension(ExtensionDecl *ext) = 0;
- /// Introduce the accessors for a 'lazy' variable.
- virtual void introduceLazyVarAccessors(VarDecl *var) = 0;
-
/// Resolve the type of an extension.
///
/// This can be called to ensure that the members of an extension can be
@@ -151,10 +148,6 @@
Principal.bindExtension(ext);
}
- void introduceLazyVarAccessors(VarDecl *var) override {
- Principal.introduceLazyVarAccessors(var);
- }
-
void resolveExtension(ExtensionDecl *ext) override {
Principal.resolveExtension(ext);
}
diff --git a/include/swift/Basic/Mangler.h b/include/swift/Basic/Mangler.h
index 7c97e7b..a358532 100644
--- a/include/swift/Basic/Mangler.h
+++ b/include/swift/Basic/Mangler.h
@@ -94,7 +94,10 @@
Mangler() : Buffer(Storage) { }
- /// Adds the mangling prefix.
+ /// Begins a new mangling but does not add the mangling prefix.
+ void beginManglingWithoutPrefix();
+
+ /// Begins a new mangling but and adds the mangling prefix.
void beginMangling();
/// Finish the mangling of the symbol and return the mangled name.
diff --git a/include/swift/Demangling/DemangleNodes.def b/include/swift/Demangling/DemangleNodes.def
index 21261f1..822120f 100644
--- a/include/swift/Demangling/DemangleNodes.def
+++ b/include/swift/Demangling/DemangleNodes.def
@@ -101,6 +101,7 @@
NODE(LazyProtocolWitnessTableCacheVariable)
NODE(LocalDeclName)
CONTEXT_NODE(MaterializeForSet)
+NODE(MergedFunction)
NODE(Metatype)
NODE(MetatypeRepresentation)
NODE(Metaclass)
diff --git a/include/swift/Demangling/Demangler.h b/include/swift/Demangling/Demangler.h
index 773e460..23d9d94 100644
--- a/include/swift/Demangling/Demangler.h
+++ b/include/swift/Demangling/Demangler.h
@@ -286,16 +286,11 @@
/// It de-mangles a string and it also owns the returned node-tree. This means
/// The nodes of the tree only live as long as the Demangler itself.
class Demangler : public NodeFactory {
-private:
+protected:
StringRef Text;
size_t Pos = 0;
- struct NodeWithPos {
- NodePointer Node;
- size_t Pos;
- };
-
- Vector<NodeWithPos> NodeStack;
+ Vector<NodePointer> NodeStack;
Vector<NodePointer> Substitutions;
Vector<unsigned> PendingSubstitutions;
@@ -334,18 +329,18 @@
}
void pushNode(NodePointer Nd) {
- NodeStack.push_back({ Nd, Pos }, *this);
+ NodeStack.push_back(Nd, *this);
}
NodePointer popNode() {
- return NodeStack.pop_back_val().Node;
+ return NodeStack.pop_back_val();
}
NodePointer popNode(Node::Kind kind) {
if (NodeStack.empty())
return nullptr;
- Node::Kind NdKind = NodeStack.back().Node->getKind();
+ Node::Kind NdKind = NodeStack.back()->getKind();
if (NdKind != kind)
return nullptr;
@@ -356,7 +351,7 @@
if (NodeStack.empty())
return nullptr;
- Node::Kind NdKind = NodeStack.back().Node->getKind();
+ Node::Kind NdKind = NodeStack.back()->getKind();
if (!pred(NdKind))
return nullptr;
@@ -381,7 +376,7 @@
return createWithChild(kind, popNode(Node::Kind::Type));
}
- void parseAndPushNodes();
+ bool parseAndPushNodes();
NodePointer changeKind(NodePointer Node, Node::Kind NewKind);
diff --git a/include/swift/Migrator/FixitFilter.h b/include/swift/Migrator/FixitFilter.h
index 161ed44..0f94fb8 100644
--- a/include/swift/Migrator/FixitFilter.h
+++ b/include/swift/Migrator/FixitFilter.h
@@ -102,7 +102,6 @@
// Fixits from warnings/notes that should be applied.
if (Info.ID == diag::forced_downcast_coercion.ID ||
Info.ID == diag::forced_downcast_noop.ID ||
- Info.ID == diag::variable_never_mutated.ID ||
Info.ID == diag::function_type_no_parens.ID ||
Info.ID == diag::convert_let_to_var.ID ||
Info.ID == diag::parameter_extraneous_double_up.ID ||
diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp
index b7c864a..9204df2 100644
--- a/lib/AST/ASTDumper.cpp
+++ b/lib/AST/ASTDumper.cpp
@@ -840,6 +840,8 @@
void visitEnumElementDecl(EnumElementDecl *EED) {
printCommon(EED, "enum_element_decl");
+ if (EED->getAttrs().hasAttribute<DowngradeExhaustivityCheckAttr>())
+ OS << "@_downgrade_exhaustivity_check";
PrintWithColorRAII(OS, ParenthesisColor) << ')';
}
@@ -1792,13 +1794,7 @@
PrintWithColorRAII(OS, AccessibilityColor)
<< " " << getAccessSemanticsString(E->getAccessSemantics());
PrintWithColorRAII(OS, ExprModifierColor)
- << " function_ref=" << getFunctionRefKindStr(E->getFunctionRefKind())
- << " specialized=" << (E->isSpecialized()? "yes" : "no");
-
- for (auto TR : E->getGenericArgs()) {
- OS << '\n';
- printRec(TR);
- }
+ << " function_ref=" << getFunctionRefKindStr(E->getFunctionRefKind());
PrintWithColorRAII(OS, ParenthesisColor) << ')';
}
void visitSuperRefExpr(SuperRefExpr *E) {
@@ -1827,7 +1823,6 @@
printCommon(E, "overloaded_decl_ref_expr")
<< " name=" << E->getDecls()[0]->getName()
<< " #decls=" << E->getDecls().size()
- << " specialized=" << (E->isSpecialized()? "yes" : "no")
<< " function_ref=" << getFunctionRefKindStr(E->getFunctionRefKind());
for (ValueDecl *D : E->getDecls()) {
@@ -1841,7 +1836,6 @@
printCommon(E, "unresolved_decl_ref_expr");
PrintWithColorRAII(OS, IdentifierColor) << " name=" << E->getName();
PrintWithColorRAII(OS, ExprModifierColor)
- << " specialized=" << (E->isSpecialized()? "yes" : "no")
<< " function_ref=" << getFunctionRefKindStr(E->getFunctionRefKind());
PrintWithColorRAII(OS, ParenthesisColor) << ')';
}
diff --git a/lib/AST/ASTMangler.cpp b/lib/AST/ASTMangler.cpp
index e48fd02..d09ff4d 100644
--- a/lib/AST/ASTMangler.cpp
+++ b/lib/AST/ASTMangler.cpp
@@ -386,6 +386,7 @@
}
std::string ASTMangler::mangleTypeAsContextUSR(const NominalTypeDecl *type) {
+ beginManglingWithoutPrefix();
llvm::SaveAndRestore<bool> allowUnnamedRAII(AllowNamelessEntities, true);
appendContext(type);
return finalize();
@@ -393,6 +394,7 @@
std::string ASTMangler::mangleDeclAsUSR(const ValueDecl *Decl,
StringRef USRPrefix) {
+ beginManglingWithoutPrefix();
llvm::SaveAndRestore<bool> allowUnnamedRAII(AllowNamelessEntities, true);
Buffer << USRPrefix;
bindGenericParameters(Decl->getDeclContext());
@@ -419,6 +421,7 @@
AddressorKind addressorKind,
const ValueDecl *decl,
StringRef USRPrefix) {
+ beginManglingWithoutPrefix();
llvm::SaveAndRestore<bool> allowUnnamedRAII(AllowNamelessEntities, true);
Buffer << USRPrefix;
appendAccessorEntity(kind, addressorKind, decl, /*isStatic*/ false);
diff --git a/lib/AST/ASTScope.cpp b/lib/AST/ASTScope.cpp
index 2ca2f44..e40a5a1 100644
--- a/lib/AST/ASTScope.cpp
+++ b/lib/AST/ASTScope.cpp
@@ -1903,28 +1903,17 @@
}
break;
- case ASTScopeKind::PatternInitializer:
- // FIXME: This causes recursion that we cannot yet handle.
-#if false
+ case ASTScopeKind::PatternInitializer: {
// 'self' is available within the pattern initializer of a 'lazy' variable.
- if (auto singleVar = patternBinding.decl->getSingleVar()) {
- if (singleVar->getAttrs().hasAttribute<LazyAttr>() &&
- singleVar->getDeclContext()->isTypeContext()) {
- // If there is no getter (yet), add them.
- if (!singleVar->getGetter()) {
- ASTContext &ctx = singleVar->getASTContext();
- if (auto resolver = ctx.getLazyResolver())
- resolver->introduceLazyVarAccessors(singleVar);
- }
-
- // Add the getter's 'self'.
- if (auto getter = singleVar->getGetter())
- if (auto self = getter->getImplicitSelfDecl())
- result.push_back(self);
- }
+ auto *initContext = cast_or_null<PatternBindingInitializer>(
+ patternBinding.decl->getPatternList()[0].getInitContext());
+ if (initContext) {
+ if (auto *selfParam = initContext->getImplicitSelfDecl())
+ result.push_back(selfParam);
}
-#endif
+
break;
+ }
case ASTScopeKind::Closure:
// Note: Parameters all at once is different from functions, but it's not
diff --git a/lib/AST/ASTWalker.cpp b/lib/AST/ASTWalker.cpp
index 832492f..f17ad77 100644
--- a/lib/AST/ASTWalker.cpp
+++ b/lib/AST/ASTWalker.cpp
@@ -429,10 +429,6 @@
}
Expr *visitDeclRefExpr(DeclRefExpr *E) {
- for (auto Ty : E->getGenericArgs()) {
- if (doIt(Ty))
- return nullptr;
- }
return E;
}
diff --git a/lib/AST/Attr.cpp b/lib/AST/Attr.cpp
index e782469..bb065bb 100644
--- a/lib/AST/Attr.cpp
+++ b/lib/AST/Attr.cpp
@@ -506,6 +506,10 @@
Printer.printAttrName("@_staticInitializeObjCMetadata");
break;
+ case DAK_DowngradeExhaustivityCheck:
+ Printer.printAttrName("@_downgrade_exhaustivity_check");
+ break;
+
case DAK_Count:
llvm_unreachable("exceed declaration attribute kinds");
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index 5cf5e04..7568292 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -986,6 +986,25 @@
return PBD;
}
+ParamDecl *PatternBindingInitializer::getImplicitSelfDecl() {
+ if (SelfParam)
+ return SelfParam;
+
+ if (auto singleVar = getBinding()->getSingleVar()) {
+ auto *DC = singleVar->getDeclContext();
+ if (singleVar->getAttrs().hasAttribute<LazyAttr>() &&
+ DC->isTypeContext()) {
+ bool isInOut = !DC->getDeclaredTypeOfContext()->hasReferenceSemantics();
+ SelfParam = ParamDecl::createSelf(SourceLoc(), DC,
+ singleVar->isStatic(),
+ isInOut);
+ SelfParam->setDeclContext(this);
+ }
+ }
+
+ return SelfParam;
+}
+
static bool patternContainsVarDeclBinding(const Pattern *P, const VarDecl *VD) {
bool Result = false;
P->forEachVariable([&](VarDecl *FoundVD) {
@@ -3916,9 +3935,12 @@
}
bool VarDecl::isSelfParameter() const {
- if (isa<ParamDecl>(this))
+ if (isa<ParamDecl>(this)) {
if (auto *AFD = dyn_cast<AbstractFunctionDecl>(getDeclContext()))
return AFD->getImplicitSelfDecl() == this;
+ if (auto *PBI = dyn_cast<PatternBindingInitializer>(getDeclContext()))
+ return PBI->getImplicitSelfDecl() == this;
+ }
return false;
}
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index dcfc680..952bbde 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -1308,25 +1308,6 @@
llvm_unreachable("unspecified literal");
}
-void DeclRefExpr::setSpecialized() {
- if (isSpecialized())
- return;
-
- ConcreteDeclRef ref = getDeclRef();
- void *Mem = ref.getDecl()->getASTContext().Allocate(sizeof(SpecializeInfo),
- alignof(SpecializeInfo));
- auto Spec = new (Mem) SpecializeInfo;
- Spec->D = ref;
- DOrSpecialized = Spec;
-}
-
-void DeclRefExpr::setGenericArgs(ArrayRef<TypeRepr*> GenericArgs) {
- ValueDecl *D = getDecl();
- assert(D);
- setSpecialized();
- getSpecInfo()->GenericArgs = D->getASTContext().AllocateCopy(GenericArgs);
-}
-
ConstructorDecl *OtherConstructorDeclRefExpr::getDecl() const {
return cast_or_null<ConstructorDecl>(Ctor.getDecl());
}
diff --git a/lib/AST/NameLookup.cpp b/lib/AST/NameLookup.cpp
index d76c708..04fc0f2 100644
--- a/lib/AST/NameLookup.cpp
+++ b/lib/AST/NameLookup.cpp
@@ -510,29 +510,11 @@
// Pattern binding initializers are only interesting insofar as they
// affect lookup in an enclosing nominal type or extension thereof.
if (auto *bindingInit = dyn_cast<PatternBindingInitializer>(dc)) {
- if (auto binding = bindingInit->getBinding()) {
- // Look for 'self' for a lazy variable initializer.
- if (auto singleVar = binding->getSingleVar())
- // We only care about lazy variables.
- if (singleVar->getAttrs().hasAttribute<LazyAttr>()) {
+ // Lazy variable initializer contexts have a 'self' parameter for
+ // instance member lookup.
+ if (auto *selfParam = bindingInit->getImplicitSelfDecl())
+ selfDecl = selfParam;
- // 'self' will be listed in the local bindings.
- for (auto local : localBindings) {
- auto param = dyn_cast<ParamDecl>(local);
- if (!param) continue;
-
-
- // If we have a variable that's the implicit self of its enclosing
- // context, mark it as 'self'.
- if (auto func = dyn_cast<FuncDecl>(param->getDeclContext())) {
- if (param == func->getImplicitSelfDecl()) {
- selfDecl = param;
- break;
- }
- }
- }
- }
- }
continue;
}
@@ -646,17 +628,46 @@
Type ExtendedType;
bool isTypeLookup = false;
- // If this declcontext is an initializer for a static property, then we're
- // implicitly doing a static lookup into the parent declcontext.
- if (auto *PBI = dyn_cast<PatternBindingInitializer>(DC))
- if (!DC->getParent()->isModuleScopeContext()) {
- if (auto *PBD = PBI->getBinding()) {
- isTypeLookup = PBD->isStatic();
- DC = DC->getParent();
- }
+ if (auto *PBI = dyn_cast<PatternBindingInitializer>(DC)) {
+ auto *PBD = PBI->getBinding();
+ assert(PBD);
+
+ // Lazy variable initializer contexts have a 'self' parameter for
+ // instance member lookup.
+ if (auto *selfParam = PBI->getImplicitSelfDecl()) {
+ Consumer.foundDecl(selfParam,
+ DeclVisibilityKind::FunctionParameter);
+ if (!Results.empty())
+ return;
+
+ DC = DC->getParent();
+
+ BaseDecl = selfParam;
+ ExtendedType = DC->getSelfTypeInContext();
+ MetaBaseDecl = DC->getAsNominalTypeOrNominalTypeExtensionContext();
+
+ isTypeLookup = PBD->isStatic();
}
-
- if (auto *AFD = dyn_cast<AbstractFunctionDecl>(DC)) {
+ // Initializers for stored properties of types perform static
+ // lookup into the surrounding context.
+ else if (PBD->getDeclContext()->isTypeContext()) {
+ DC = DC->getParent();
+
+ ExtendedType = DC->getSelfTypeInContext();
+ MetaBaseDecl = DC->getAsNominalTypeOrNominalTypeExtensionContext();
+ BaseDecl = MetaBaseDecl;
+
+ isTypeLookup = PBD->isStatic(); // FIXME
+
+ isCascadingUse = DC->isCascadingContextForLookup(false);
+ }
+ // Otherwise, we have an initializer for a global or local property.
+ // There's not much to find here, we'll keep going up to a parent
+ // context.
+
+ if (!isCascadingUse.hasValue())
+ isCascadingUse = DC->isCascadingContextForLookup(false);
+ } else if (auto *AFD = dyn_cast<AbstractFunctionDecl>(DC)) {
// Look for local variables; normally, the parser resolves these
// for us, but it can't do the right thing inside local types.
// FIXME: when we can parse and typecheck the function body partially
@@ -690,9 +701,12 @@
if (FD->isStatic())
isTypeLookup = true;
- // If we're not in the body of the function, the base declaration
+ // If we're not in the body of the function (for example, we
+ // might be type checking a default argument expression and
+ // performing name lookup from there), the base declaration
// is the nominal type, not 'self'.
- if (Loc.isValid() &&
+ if (!AFD->isImplicit() &&
+ Loc.isValid() &&
AFD->getBodySourceRange().isValid() &&
!SM.rangeContainsTokenLoc(AFD->getBodySourceRange(), Loc)) {
BaseDecl = MetaBaseDecl;
diff --git a/lib/Basic/Mangler.cpp b/lib/Basic/Mangler.cpp
index da5c924..71eac3f 100644
--- a/lib/Basic/Mangler.cpp
+++ b/lib/Basic/Mangler.cpp
@@ -110,12 +110,16 @@
#endif
}
-void Mangler::beginMangling() {
+void Mangler::beginManglingWithoutPrefix() {
Storage.clear();
Substitutions.clear();
StringSubstitutions.clear();
Words.clear();
SubstMerging.clear();
+}
+
+void Mangler::beginMangling() {
+ beginManglingWithoutPrefix();
Buffer << MANGLING_PREFIX_STR;
}
diff --git a/lib/Demangling/Demangler.cpp b/lib/Demangling/Demangler.cpp
index ff368e2..553615b 100644
--- a/lib/Demangling/Demangler.cpp
+++ b/lib/Demangling/Demangler.cpp
@@ -100,6 +100,7 @@
case Node::Kind::VTableAttribute:
case Node::Kind::PartialApplyForwarder:
case Node::Kind::PartialApplyObjCForwarder:
+ case Node::Kind::MergedFunction:
return true;
default:
return false;
@@ -233,15 +234,11 @@
// If any other prefixes are accepted, please update Mangler::verify.
+ if (!parseAndPushNodes())
+ return nullptr;
+
NodePointer topLevel = createNode(Node::Kind::Global);
- parseAndPushNodes();
-
- // Let a trailing '_' be part of the not demangled suffix.
- popNode(Node::Kind::FirstElementMarker);
-
- size_t EndPos = (NodeStack.empty() ? 0 : NodeStack.back().Pos);
-
NodePointer Parent = topLevel;
while (NodePointer FuncAttr = popNode(isFunctionAttr)) {
Parent->addChild(FuncAttr, *this);
@@ -249,8 +246,7 @@
FuncAttr->getKind() == Node::Kind::PartialApplyObjCForwarder)
Parent = FuncAttr;
}
- for (const NodeWithPos &NWP : NodeStack) {
- NodePointer Nd = NWP.Node;
+ for (Node *Nd : NodeStack) {
switch (Nd->getKind()) {
case Node::Kind::Type:
Parent->addChild(Nd->getFirstChild(), *this);
@@ -263,10 +259,6 @@
if (topLevel->getNumChildren() == 0)
return nullptr;
- if (EndPos < Text.size()) {
- topLevel->addChild(createNode(Node::Kind::Suffix, Text.substr(EndPos)), *this);
- }
-
return topLevel;
}
@@ -281,15 +273,16 @@
return createNode(Node::Kind::Suffix, Text);
}
-void Demangler::parseAndPushNodes() {
+bool Demangler::parseAndPushNodes() {
int Idx = 0;
- while (!Text.empty()) {
+ while (Pos < Text.size()) {
NodePointer Node = demangleOperator();
if (!Node)
- break;
+ return false;
pushNode(Node);
Idx++;
}
+ return true;
}
NodePointer Demangler::addChild(NodePointer Parent, NodePointer Child) {
@@ -1219,6 +1212,7 @@
case 'd': return createNode(Node::Kind::DirectMethodReferenceAttribute);
case 'a': return createNode(Node::Kind::PartialApplyObjCForwarder);
case 'A': return createNode(Node::Kind::PartialApplyForwarder);
+ case 'm': return createNode(Node::Kind::MergedFunction);
case 'V': {
NodePointer Base = popNode(isEntity);
NodePointer Derived = popNode(isEntity);
diff --git a/lib/Demangling/NodeDumper.cpp b/lib/Demangling/NodeDumper.cpp
index be2929d..fdcc6c8 100644
--- a/lib/Demangling/NodeDumper.cpp
+++ b/lib/Demangling/NodeDumper.cpp
@@ -62,8 +62,8 @@
void Demangler::dump() {
for (unsigned Idx = 0; Idx < NodeStack.size(); ++Idx) {
- fprintf(stderr, "NodeStack[%u] at position %zd:\n", Idx, NodeStack[Idx].Pos);
- NodeStack[Idx].Node->dump();
+ fprintf(stderr, "NodeStack[%u]:\n", Idx);
+ NodeStack[Idx]->dump();
fprintf(stderr, "\n");
}
fprintf(stderr, "Position = %zd:\n%.*s\n%*s\n", Pos,
diff --git a/lib/Demangling/NodePrinter.cpp b/lib/Demangling/NodePrinter.cpp
index 7c57e44..fe322e6 100644
--- a/lib/Demangling/NodePrinter.cpp
+++ b/lib/Demangling/NodePrinter.cpp
@@ -347,6 +347,7 @@
case Node::Kind::LocalDeclName:
case Node::Kind::PrivateDeclName:
case Node::Kind::MaterializeForSet:
+ case Node::Kind::MergedFunction:
case Node::Kind::Metaclass:
case Node::Kind::NativeOwningAddressor:
case Node::Kind::NativeOwningMutableAddressor:
@@ -1238,6 +1239,11 @@
print(Node->getChild(Node->getNumChildren() - 1));
return nullptr;
}
+ case Node::Kind::MergedFunction:
+ if (!Options.ShortenThunk) {
+ Printer << "merged ";
+ }
+ return nullptr;
case Node::Kind::GenericTypeMetadataPattern:
Printer << "generic type metadata pattern for ";
print(Node->getChild(0));
diff --git a/lib/Demangling/OldRemangler.cpp b/lib/Demangling/OldRemangler.cpp
index 8089ebe..e933875 100644
--- a/lib/Demangling/OldRemangler.cpp
+++ b/lib/Demangling/OldRemangler.cpp
@@ -653,6 +653,10 @@
mangleSingleChildNode(node); // global
}
+void Remangler::mangleMergedFunction(Node *node) {
+ Out << "Tm";
+}
+
void Remangler::mangleDirectness(Node *node) {
auto getChar = [](Directness d) -> char {
switch (d) {
diff --git a/lib/Demangling/Remangler.cpp b/lib/Demangling/Remangler.cpp
index 7abeb0d..afa2671 100644
--- a/lib/Demangling/Remangler.cpp
+++ b/lib/Demangling/Remangler.cpp
@@ -1063,6 +1063,7 @@
case Node::Kind::DynamicAttribute:
case Node::Kind::VTableAttribute:
case Node::Kind::DirectMethodReferenceAttribute:
+ case Node::Kind::MergedFunction:
mangleInReverseOrder = true;
break;
default:
@@ -1368,6 +1369,10 @@
Buffer << "Ta";
}
+void Remangler::mangleMergedFunction(Node *node) {
+ Buffer << "Tm";
+}
+
void Remangler::manglePostfixOperator(Node *node) {
mangleIdentifierImpl(node, /*isOperator*/ true);
Buffer << "oP";
diff --git a/lib/LLVMPasses/LLVMMergeFunctions.cpp b/lib/LLVMPasses/LLVMMergeFunctions.cpp
index 55ad969..5185bc3 100644
--- a/lib/LLVMPasses/LLVMMergeFunctions.cpp
+++ b/lib/LLVMPasses/LLVMMergeFunctions.cpp
@@ -861,7 +861,7 @@
// a name which can be demangled in a meaningful way.
Function *NewFunction = Function::Create(funcType,
FirstF->getLinkage(),
- FirstF->getName() + "_merged");
+ FirstF->getName() + "Tm");
NewFunction->copyAttributesFrom(FirstF);
// NOTE: this function is not externally available, do ensure that we reset
// the DLL storage
diff --git a/lib/Migrator/TupleSplatMigratorPass.cpp b/lib/Migrator/TupleSplatMigratorPass.cpp
index 2aedb1e..b058a5a 100644
--- a/lib/Migrator/TupleSplatMigratorPass.cpp
+++ b/lib/Migrator/TupleSplatMigratorPass.cpp
@@ -58,15 +58,15 @@
if (!Expr->hasAnonymousClosureVars())
return;
References.clear();
- for(auto *Param: *Expr->getParameters()) {
+ for (auto *Param: *Expr->getParameters()) {
References[Param] = {};
}
Expr->walk(*this);
}
void forEachReference(llvm::function_ref<void(Expr*, ParamDecl*)> Callback) {
- for(auto Entry: References) {
- for(auto *Expr : Entry.getSecond()) {
+ for (auto Entry: References) {
+ for (auto *Expr : Entry.getSecond()) {
Callback(Expr, Entry.getFirst());
}
}
diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp
index c6a0b44..ea4b2d9 100644
--- a/lib/Parse/ParseExpr.cpp
+++ b/lib/Parse/ParseExpr.cpp
@@ -2063,15 +2063,11 @@
return parseExprEditorPlaceholder(IdentTok, name.getBaseName());
auto refKind = DeclRefKind::Ordinary;
- auto unresolved = new (Context) UnresolvedDeclRefExpr(name, refKind, loc);
- unresolved->setSpecialized(hasGenericArgumentList);
- E = unresolved;
+ E = new (Context) UnresolvedDeclRefExpr(name, refKind, loc);
} else if (auto TD = dyn_cast<TypeDecl>(D)) {
E = TypeExpr::createForDecl(loc.getBaseNameLoc(), TD, /*implicit*/false);
} else {
- auto declRef = new (Context) DeclRefExpr(D, loc, /*Implicit=*/false);
- declRef->setGenericArgs(args);
- E = declRef;
+ E = new (Context) DeclRefExpr(D, loc, /*Implicit=*/false);
}
if (hasGenericArgumentList) {
diff --git a/lib/SIL/DynamicCasts.cpp b/lib/SIL/DynamicCasts.cpp
index 626cb05..2bf4152 100644
--- a/lib/SIL/DynamicCasts.cpp
+++ b/lib/SIL/DynamicCasts.cpp
@@ -89,15 +89,24 @@
if (source == target)
return DynamicCastFeasibility::WillSucceed;
- auto *SourceNominalTy = source.getAnyNominal();
-
- if (!SourceNominalTy)
- return DynamicCastFeasibility::MaySucceed;
-
auto *TargetProtocol = target.getAnyNominal();
if (!TargetProtocol)
return DynamicCastFeasibility::MaySucceed;
+ auto *SourceNominalTy = source.getAnyNominal();
+
+ if (!SourceNominalTy) {
+ if (auto Archetype = dyn_cast<ArchetypeType>(source)) {
+ auto SourceProtocols = Archetype->getConformsTo();
+ // Check all protocols implemented by the archetype.
+ for (auto *Protocol : SourceProtocols) {
+ if (Protocol == TargetProtocol)
+ return DynamicCastFeasibility::WillSucceed;
+ }
+ }
+ return DynamicCastFeasibility::MaySucceed;
+ }
+
auto SourceProtocols = SourceNominalTy->getAllProtocols();
// Check all protocols implemented by the type.
@@ -330,11 +339,8 @@
if (source->hasArchetype() || source.isExistentialType() ||
target->hasArchetype() || target.isExistentialType()) {
- auto *SourceNominalTy = source.getAnyNominal();
-
// Check conversions from non-protocol types into protocol types.
if (!source.isExistentialType() &&
- SourceNominalTy &&
target.isExistentialType())
return classifyDynamicCastToProtocol(source, target, isWholeModuleOpts);
diff --git a/lib/SILGen/SILGenLValue.cpp b/lib/SILGen/SILGenLValue.cpp
index 5941a3d..b5132b1 100644
--- a/lib/SILGen/SILGenLValue.cpp
+++ b/lib/SILGen/SILGenLValue.cpp
@@ -859,7 +859,7 @@
if (auto *dre1 = dyn_cast<DeclRefExpr>(e1)) {
auto *dre2 = cast<DeclRefExpr>(e2);
return dre1->getDecl() == dre2->getDecl() &&
- dre1->getGenericArgs() == dre2->getGenericArgs();
+ dre1->getType()->isEqual(dre2->getType());
}
// Compare a variety of literals.
diff --git a/lib/SILOptimizer/Mandatory/DiagnoseUnreachable.cpp b/lib/SILOptimizer/Mandatory/DiagnoseUnreachable.cpp
index 3afefba..f3301a6 100644
--- a/lib/SILOptimizer/Mandatory/DiagnoseUnreachable.cpp
+++ b/lib/SILOptimizer/Mandatory/DiagnoseUnreachable.cpp
@@ -541,13 +541,17 @@
}
}
+ auto *Scope = NoReturnCall->getDebugScope();
recursivelyDeleteTriviallyDeadInstructions(ToBeDeleted, true);
NumInstructionsRemoved += ToBeDeleted.size();
// Add an unreachable terminator. The terminator has an invalid source
// location to signal to the DataflowDiagnostic pass that this code does
// not correspond to user code.
+ // Share the scope with the preceding BB. This causes the debug info to be
+ // much smaller and easier to read, but otherwise has no effect.
SILBuilder B(&BB);
+ B.setCurrentDebugScope(Scope);
B.createUnreachable(ArtificialUnreachableLocation());
return true;
diff --git a/lib/SILOptimizer/Utils/Local.cpp b/lib/SILOptimizer/Utils/Local.cpp
index e4c9d7d..638a3e5 100644
--- a/lib/SILOptimizer/Utils/Local.cpp
+++ b/lib/SILOptimizer/Utils/Local.cpp
@@ -2458,6 +2458,104 @@
}
}
+/// TODO: Move to emitSuccessfulIndirectUnconditionalCast?
+///
+/// Peephole to avoid runtime calls:
+/// unconditional_checked_cast_addr T in %0 : $*T to P in %1 : $*P
+/// ->
+/// %addr = init_existential_addr %1 : $*P, T
+/// copy_addr %0 to %addr
+///
+/// where T is a type statically known to conform to P.
+///
+/// In caase P is a class existential type, it generates:
+/// %val = load %0 : $*T
+/// %existential = init_existential_ref %val : $T, $T, P
+/// store %existential to %1 : $*P
+///
+/// Returns true if the optimization was possible and false otherwise.
+static bool optimizeStaticallyKnownProtocolConformance(
+ UnconditionalCheckedCastAddrInst *Inst) {
+ auto Loc = Inst->getLoc();
+ auto Src = Inst->getSrc();
+ auto Dest = Inst->getDest();
+ auto SourceType = Inst->getSourceType();
+ auto TargetType = Inst->getTargetType();
+ auto &Mod = Inst->getModule();
+
+ if (TargetType->isAnyExistentialType() &&
+ !SourceType->isAnyExistentialType()) {
+ auto &Ctx = Mod.getASTContext();
+ auto *SM = Mod.getSwiftModule();
+
+ auto Proto = dyn_cast<ProtocolDecl>(TargetType->getAnyNominal());
+ if (Proto) {
+ auto Conformance = SM->lookupConformance(SourceType, Proto, nullptr);
+ if (Conformance.hasValue()) {
+ // SourceType is a non-existential type conforming to a
+ // protocol represented by the TargetType.
+ SILBuilder B(Inst);
+ SmallVector<ProtocolConformanceRef, 1> NewConformances;
+ NewConformances.push_back(Conformance.getValue());
+ ArrayRef<ProtocolConformanceRef> Conformances =
+ Ctx.AllocateCopy(NewConformances);
+
+ auto ExistentialRepr =
+ Dest->getType().getPreferredExistentialRepresentation(Mod,
+ SourceType);
+
+ switch (ExistentialRepr) {
+ default:
+ return false;
+ case ExistentialRepresentation::Opaque: {
+ auto ExistentialAddr = B.createInitExistentialAddr(
+ Loc, Dest, SourceType, Src->getType().getObjectType(),
+ Conformances);
+ B.createCopyAddr(
+ Loc, Src, ExistentialAddr,
+ (Inst->getConsumptionKind() != CastConsumptionKind::CopyOnSuccess)
+ ? IsTake_t::IsTake
+ : IsTake_t::IsNotTake,
+ IsInitialization_t::IsInitialization);
+ break;
+ }
+ case ExistentialRepresentation::Class: {
+ auto Value = B.createLoad(Loc, Src,
+ swift::LoadOwnershipQualifier::Unqualified);
+ if (Inst->getConsumptionKind() == CastConsumptionKind::CopyOnSuccess)
+ B.createRetainValue(Loc, Value, B.getDefaultAtomicity());
+ auto Existential =
+ B.createInitExistentialRef(Loc, Dest->getType().getObjectType(),
+ SourceType, Value, Conformances);
+ B.createStore(Loc, Existential, Dest,
+ swift::StoreOwnershipQualifier::Unqualified);
+ break;
+ }
+ case ExistentialRepresentation::Boxed: {
+ auto AllocBox = B.createAllocExistentialBox(Loc, Dest->getType(),
+ SourceType, Conformances);
+ auto Projection =
+ B.createProjectExistentialBox(Loc, Src->getType(), AllocBox);
+ auto Value = B.createLoad(Loc, Src,
+ swift::LoadOwnershipQualifier::Unqualified);
+ if (Inst->getConsumptionKind() == CastConsumptionKind::CopyOnSuccess)
+ B.createRetainValue(Loc, Value, B.getDefaultAtomicity());
+ B.createStore(Loc, Value, Projection,
+ swift::StoreOwnershipQualifier::Unqualified);
+ B.createStore(Loc, AllocBox, Dest,
+ swift::StoreOwnershipQualifier::Unqualified);
+ break;
+ }
+ };
+
+ Inst->replaceAllUsesWithUndef();
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
SILInstruction *
CastOptimizer::
optimizeUnconditionalCheckedCastAddrInst(UnconditionalCheckedCastAddrInst *Inst) {
@@ -2512,18 +2610,24 @@
if (Feasibility == DynamicCastFeasibility::WillSucceed ||
Feasibility == DynamicCastFeasibility::MaySucceed) {
+ // Check if a result of a cast is unused. If this is the case, the cast can
+ // be removed even if the cast may fail at runtime.
+ // Swift optimizer does not claim to be crash-preserving.
bool ResultNotUsed = isa<AllocStackInst>(Dest);
DestroyAddrInst *DestroyDestInst = nullptr;
- for (auto Use : Dest->getUses()) {
- auto *User = Use->getUser();
- if (isa<DeallocStackInst>(User) || User == Inst)
- continue;
- if (isa<DestroyAddrInst>(User) && !DestroyDestInst) {
- DestroyDestInst = cast<DestroyAddrInst>(User);
- continue;
+ if (ResultNotUsed) {
+ for (auto Use : Dest->getUses()) {
+ auto *User = Use->getUser();
+ if (isa<DeallocStackInst>(User) || User == Inst)
+ continue;
+ if (isa<DestroyAddrInst>(User) && !DestroyDestInst) {
+ DestroyDestInst = cast<DestroyAddrInst>(User);
+ continue;
+ }
+ ResultNotUsed = false;
+ DestroyDestInst = nullptr;
+ break;
}
- ResultNotUsed = false;
- break;
}
if (ResultNotUsed) {
@@ -2544,23 +2648,33 @@
return nullptr;
}
- // Try to apply the bridged casts optimizations
+ // Try to apply the bridged casts optimizations.
auto NewI = optimizeBridgedCasts(Inst, Inst->getConsumptionKind(),
false, Src, Dest, SourceType,
TargetType, nullptr, nullptr);
if (NewI) {
- WillSucceedAction();
- return nullptr;
+ WillSucceedAction();
+ return nullptr;
+ }
+
+ if (Feasibility == DynamicCastFeasibility::MaySucceed)
+ return nullptr;
+
+ assert(Feasibility == DynamicCastFeasibility::WillSucceed);
+
+ if (optimizeStaticallyKnownProtocolConformance(Inst)) {
+ EraseInstAction(Inst);
+ WillSucceedAction();
+ return nullptr;
}
if (isBridgingCast(SourceType, TargetType))
return nullptr;
SILBuilderWithScope Builder(Inst);
- if (!emitSuccessfulIndirectUnconditionalCast(Builder, Mod.getSwiftModule(),
- Loc, Inst->getConsumptionKind(),
- Src, SourceType,
- Dest, TargetType, Inst)) {
+ if (!emitSuccessfulIndirectUnconditionalCast(
+ Builder, Mod.getSwiftModule(), Loc, Inst->getConsumptionKind(), Src,
+ SourceType, Dest, TargetType, Inst)) {
// No optimization was possible.
return nullptr;
}
diff --git a/lib/SILOptimizer/Utils/SpecializationMangler.cpp b/lib/SILOptimizer/Utils/SpecializationMangler.cpp
index d133c81..7134e4b 100644
--- a/lib/SILOptimizer/Utils/SpecializationMangler.cpp
+++ b/lib/SILOptimizer/Utils/SpecializationMangler.cpp
@@ -19,16 +19,37 @@
using namespace Mangle;
void SpecializationMangler::beginMangling() {
- ASTMangler::beginMangling();
+ ASTMangler::beginManglingWithoutPrefix();
if (Serialized)
ArgOpBuffer << 'q';
ArgOpBuffer << char(uint8_t(Pass) + '0');
}
+namespace {
+
+/// Utility class for demangling specialization attributes.
+class AttributeDemangler : public Demangle::Demangler {
+public:
+ void demangleAndAddAsChildren(StringRef MangledSpecialization,
+ NodePointer Parent) {
+ init(MangledSpecialization);
+ if (!parseAndPushNodes()) {
+ llvm::errs() << "Can't demangle: " << MangledSpecialization << '\n';
+ abort();
+ }
+ for (Node *Nd : NodeStack) {
+ addChild(Parent, Nd);
+ }
+ }
+};
+
+} // namespace
+
std::string SpecializationMangler::finalize() {
StringRef MangledSpecialization(Storage.data(), Storage.size());
- Demangle::Demangler D;
- NodePointer TopLevel = D.demangleSymbol(MangledSpecialization);
+ AttributeDemangler D;
+ NodePointer TopLevel = D.createNode(Node::Kind::Global);
+ D.demangleAndAddAsChildren(MangledSpecialization, TopLevel);
StringRef FuncName = Function->getName();
NodePointer FuncTopLevel = nullptr;
@@ -41,8 +62,6 @@
FuncTopLevel->addChild(D.createNode(Node::Kind::Identifier, FuncName), D);
}
for (NodePointer FuncChild : *FuncTopLevel) {
- assert(FuncChild->getKind() != Node::Kind::Suffix ||
- FuncChild->getText() == "merged");
TopLevel->addChild(FuncChild, D);
}
std::string mangledName = Demangle::mangleNode(TopLevel);
diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp
index 5ef9dd0..05dc57b 100644
--- a/lib/Sema/CSApply.cpp
+++ b/lib/Sema/CSApply.cpp
@@ -72,10 +72,8 @@
return;
TypeSubstitutionMap subs;
- for (const auto &opened : openedTypes->second) {
- subs[opened.first->castTo<GenericTypeParamType>()] =
- getFixedType(opened.second);
- }
+ for (const auto &opened : openedTypes->second)
+ subs[opened.first] = getFixedType(opened.second);
auto &tc = getConstraintSystem().getTypeChecker();
@@ -441,8 +439,7 @@
public:
/// \brief Build a reference to the given declaration.
Expr *buildDeclRef(ValueDecl *decl, DeclNameLoc loc, Type openedType,
- ConstraintLocatorBuilder locator,
- bool specialized, bool implicit,
+ ConstraintLocatorBuilder locator, bool implicit,
FunctionRefKind functionRefKind,
AccessSemantics semantics) {
// Determine the declaration selected for this overloaded reference.
@@ -2373,7 +2370,7 @@
// FIXME: Cannibalize the existing DeclRefExpr rather than allocating a
// new one?
return buildDeclRef(decl, expr->getNameLoc(), selected->openedFullType,
- locator, expr->isSpecialized(),
+ locator,
expr->isImplicit(),
expr->getFunctionRefKind(),
expr->getAccessSemantics());
@@ -2393,7 +2390,6 @@
}
Expr *visitOtherConstructorDeclRefExpr(OtherConstructorDeclRefExpr *expr) {
- assert(!expr->getDeclRef().isSpecialized());
cs.setType(expr, expr->getDecl()->getInitializerInterfaceType());
return expr;
}
@@ -2410,7 +2406,7 @@
auto decl = choice.getDecl();
return buildDeclRef(decl, expr->getNameLoc(), selected.openedFullType,
- locator, expr->isSpecialized(), expr->isImplicit(),
+ locator, expr->isImplicit(),
choice.getFunctionRefKind(),
AccessSemantics::Ordinary);
}
@@ -2423,16 +2419,6 @@
Expr *visitUnresolvedSpecializeExpr(UnresolvedSpecializeExpr *expr) {
// Our specializations should have resolved the subexpr to the right type.
- if (auto DRE = dyn_cast<DeclRefExpr>(expr->getSubExpr())) {
- assert(DRE->getGenericArgs().empty() ||
- DRE->getGenericArgs().size() == expr->getUnresolvedParams().size());
- if (DRE->getGenericArgs().empty()) {
- SmallVector<TypeRepr *, 8> GenArgs;
- for (auto TL : expr->getUnresolvedParams())
- GenArgs.push_back(TL.getTypeRepr());
- DRE->setGenericArgs(GenArgs);
- }
- }
return expr->getSubExpr();
}
@@ -7612,12 +7598,11 @@
Expr *Solution::coerceToType(Expr *expr, Type toType,
ConstraintLocator *locator,
bool ignoreTopLevelInjection,
- bool skipClosures,
Optional<Pattern*> typeFromPattern) const {
auto &cs = getConstraintSystem();
ExprRewriter rewriter(cs, *this,
/*suppressDiagnostics=*/false,
- /*skipClosures=*/skipClosures);
+ /*skipClosures=*/false);
Expr *result = rewriter.coerceToType(expr, toType, locator, typeFromPattern);
if (!result)
return nullptr;
diff --git a/lib/Sema/CSDiag.cpp b/lib/Sema/CSDiag.cpp
index 03dc2ef..0477ee6 100644
--- a/lib/Sema/CSDiag.cpp
+++ b/lib/Sema/CSDiag.cpp
@@ -4737,7 +4737,7 @@
continue;
OverloadChoice choice(base ? base->getInterfaceType() : nullptr,
- candidate, false, UDE->getFunctionRefKind());
+ candidate, UDE->getFunctionRefKind());
if (base) { // Let's group all of the candidates have a common base.
candidates[base].push_back(choice);
@@ -5694,7 +5694,6 @@
SmallVector<OverloadChoice, 2> choices;
for (auto &unviable : results.UnviableCandidates)
choices.push_back(OverloadChoice(baseType, unviable.first,
- /*isSpecialized=*/false,
UDE->getFunctionRefKind()));
CalleeCandidateInfo unviableCandidates(baseType, choices, hasTrailingClosure,
diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp
index 98fb72c..e80325c 100644
--- a/lib/Sema/CSGen.cpp
+++ b/lib/Sema/CSGen.cpp
@@ -1019,8 +1019,7 @@
CS.getConstraintLocator(expr, ConstraintLocator::Member);
auto tv = CS.createTypeVariable(memberLocator, TVO_CanBindToLValue);
- OverloadChoice choice(CS.getType(base), decl, /*isSpecialized=*/false,
- functionRefKind);
+ OverloadChoice choice(CS.getType(base), decl, functionRefKind);
auto locator = CS.getConstraintLocator(expr, ConstraintLocator::Member);
CS.addBindOverloadConstraint(tv, choice, locator, CurDC);
return tv;
@@ -1121,8 +1120,7 @@
// a known subscript here. This might be cleaner if we split off a new
// UnresolvedSubscriptExpr from SubscriptExpr.
if (auto decl = declOrNull) {
- OverloadChoice choice(baseTy, decl, /*isSpecialized=*/false,
- FunctionRefKind::DoubleApply);
+ OverloadChoice choice(baseTy, decl, FunctionRefKind::DoubleApply);
CS.addBindOverloadConstraint(fnTy, choice, memberLocator,
CurDC);
} else {
@@ -1314,7 +1312,6 @@
auto tv = CS.createTypeVariable(locator, TVO_CanBindToLValue);
CS.resolveOverload(locator, tv,
OverloadChoice(Type(), E->getDecl(),
- E->isSpecialized(),
E->getFunctionRefKind()),
CurDC);
@@ -1391,7 +1388,6 @@
continue;
choices.push_back(OverloadChoice(Type(), decls[i],
- expr->isSpecialized(),
expr->getFunctionRefKind()));
}
@@ -3342,8 +3338,15 @@
createMemberConstraint(Req, ConstraintKind::ConformsTo);
break;
case RequirementKind::Layout:
- // FIXME FIXME FIXME
- createMemberConstraint(Req, ConstraintKind::ConformsTo);
+ if (Req.getLayoutConstraint()->isClass()) {
+ auto First = resolveType(Req.getFirstType());
+ CS.addConstraint(ConstraintKind::ConformsTo, First,
+ CS.getASTContext().getAnyObjectType(),
+ Loc);
+ }
+
+ // Nothing else can appear outside of @_specialize yet, and Sema
+ // doesn't know how to check.
break;
case RequirementKind::Superclass:
createMemberConstraint(Req, ConstraintKind::Subtype);
diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp
index 33868bb..a4bff05 100644
--- a/lib/Sema/CSSimplify.cpp
+++ b/lib/Sema/CSSimplify.cpp
@@ -2999,8 +2999,7 @@
}
}
- result.addViable(OverloadChoice(baseTy, ctor, /*isSpecialized=*/false,
- functionRefKind));
+ result.addViable(OverloadChoice(baseTy, ctor, functionRefKind));
}
@@ -3160,9 +3159,7 @@
OverloadChoice::getDeclViaUnwrappedOptional(ovlBaseTy, cand,
functionRefKind));
} else {
- result.addViable(OverloadChoice(ovlBaseTy, cand,
- /*isSpecialized=*/false,
- functionRefKind));
+ result.addViable(OverloadChoice(ovlBaseTy, cand, functionRefKind));
}
};
diff --git a/lib/Sema/CodeSynthesis.cpp b/lib/Sema/CodeSynthesis.cpp
index db5ae5d..c2428f5 100644
--- a/lib/Sema/CodeSynthesis.cpp
+++ b/lib/Sema/CodeSynthesis.cpp
@@ -22,6 +22,7 @@
#include "swift/AST/Availability.h"
#include "swift/AST/Expr.h"
#include "swift/AST/GenericEnvironment.h"
+#include "swift/AST/Initializer.h"
#include "swift/AST/ParameterList.h"
#include "swift/AST/ProtocolConformance.h"
#include "swift/Basic/Defer.h"
@@ -89,13 +90,14 @@
}
static Type getTypeOfStorage(AbstractStorageDecl *storage,
- TypeChecker &TC,
bool wantInterfaceType) {
- if (auto var = dyn_cast<VarDecl>(storage))
- return TC.getTypeOfRValue(var, wantInterfaceType);
+ if (auto var = dyn_cast<VarDecl>(storage)) {
+ auto type = (wantInterfaceType
+ ? var->getInterfaceType()
+ : var->getType());
+ return type->getReferenceStorageReferent();
+ }
- // None of the transformations done by getTypeOfRValue are
- // necessary for subscripts.
auto subscript = cast<SubscriptDecl>(storage);
auto type = subscript->getElementInterfaceType();
if (!wantInterfaceType)
@@ -142,10 +144,25 @@
SmallVector<ParameterList*, 2> getterParams;
// The implicit 'self' argument if in a type context.
- if (storage->getDeclContext()->isTypeContext())
- getterParams.push_back(ParameterList::createSelf(loc,
- storage->getDeclContext(),
- /*isStatic*/false));
+ if (storage->getDeclContext()->isTypeContext()) {
+ ParamDecl *selfDecl;
+
+ // For lazy properties, steal the 'self' from the initializer context.
+ if (storage->getAttrs().hasAttribute<LazyAttr>()) {
+ auto *varDecl = cast<VarDecl>(storage);
+ auto *bindingDecl = varDecl->getParentPatternBinding();
+ auto *bindingInit = cast<PatternBindingInitializer>(
+ bindingDecl->getPatternEntryForVarDecl(varDecl).getInitContext());
+
+ selfDecl = bindingInit->getImplicitSelfDecl();
+ } else {
+ selfDecl = ParamDecl::createSelf(loc,
+ storage->getDeclContext(),
+ /*isStatic*/false);
+ }
+
+ getterParams.push_back(ParameterList::create(TC.Context, selfDecl));
+ }
// Add an index-forwarding clause.
getterParams.push_back(buildIndexForwardingParamList(storage, {}));
@@ -156,7 +173,7 @@
staticLoc = var->getLoc();
}
- auto storageInterfaceType = getTypeOfStorage(storage, TC, true);
+ auto storageInterfaceType = getTypeOfStorage(storage, true);
auto getter = FuncDecl::create(
TC.Context, staticLoc, StaticSpellingKind::None, loc, Identifier(), loc,
@@ -199,8 +216,8 @@
}
// Add a "(value : T, indices...)" argument list.
- auto storageType = getTypeOfStorage(storage, TC, false);
- auto storageInterfaceType = getTypeOfStorage(storage, TC, true);
+ auto storageType = getTypeOfStorage(storage, false);
+ auto storageInterfaceType = getTypeOfStorage(storage, true);
valueDecl = buildLetArgument(storage->getLoc(),
storage->getDeclContext(), "value",
storageType,
@@ -615,7 +632,7 @@
// We support @NSCopying on class types (which conform to NSCopying),
// protocols which conform, and option types thereof.
- Type UnderlyingType = TC.getTypeOfRValue(VD, /*want interface type*/false);
+ Type UnderlyingType = VD->getType()->getReferenceStorageReferent();
bool isOptional = false;
if (Type optionalEltTy = UnderlyingType->getAnyOptionalObjectType()) {
@@ -1145,7 +1162,6 @@
// realize that they are in the getter function.
InitValue->walk(RecontextualizeClosures(Get));
-
Pattern *Tmp2PBDPattern = new (Ctx) NamedPattern(Tmp2VD, /*implicit*/true);
Tmp2PBDPattern = new (Ctx) TypedPattern(Tmp2PBDPattern,
TypeLoc::withoutLoc(VD->getType()),
@@ -1672,10 +1688,6 @@
addMaterializeForSet(storage, TC);
}
-void TypeChecker::introduceLazyVarAccessors(VarDecl *var) {
- maybeAddAccessorsToVariable(var, *this);
-}
-
void swift::maybeAddAccessorsToVariable(VarDecl *var, TypeChecker &TC) {
if (var->getGetter())
return;
@@ -1930,8 +1942,10 @@
accessLevel = std::min(accessLevel, var->getFormalAccess());
- auto varType = tc.getTypeOfRValue(var, false);
- auto varInterfaceType = tc.getTypeOfRValue(var, true);
+ auto varType = var->getType()
+ ->getReferenceStorageReferent();
+ auto varInterfaceType = var->getInterfaceType()
+ ->getReferenceStorageReferent();
// If var is a lazy property, its value is provided for the underlying
// storage. We thus take an optional of the properties type. We only
diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp
index 8a07b816..4a07f2e 100644
--- a/lib/Sema/ConstraintSystem.cpp
+++ b/lib/Sema/ConstraintSystem.cpp
@@ -499,14 +499,12 @@
auto resultTy = openType(genericFn->getResult(), replacements);
// Build the resulting (non-generic) function type.
- type = FunctionType::get(inputTy, resultTy,
- FunctionType::ExtInfo().
- withThrows(genericFn->throws()));
- } else {
- type = openType(funcType, replacements);
+ funcType = FunctionType::get(inputTy, resultTy,
+ FunctionType::ExtInfo().
+ withThrows(genericFn->throws()));
}
- return removeArgumentLabels(type, numArgumentLabelsToRemove);
+ return removeArgumentLabels(funcType, numArgumentLabelsToRemove);
}
Optional<Type> ConstraintSystem::isArrayType(Type type) {
@@ -603,6 +601,80 @@
return type;
}
+/// Does a var or subscript produce an l-value?
+///
+/// \param baseType - the type of the base on which this object
+/// is being accessed; must be null if and only if this is not
+/// a type member
+static bool doesStorageProduceLValue(TypeChecker &TC,
+ AbstractStorageDecl *storage,
+ Type baseType, DeclContext *useDC,
+ const DeclRefExpr *base = nullptr) {
+ // Unsettable storage decls always produce rvalues.
+ if (!storage->isSettable(useDC, base))
+ return false;
+
+ if (TC.Context.LangOpts.EnableAccessControl &&
+ !storage->isSetterAccessibleFrom(useDC))
+ return false;
+
+ // If there is no base, or if the base isn't being used, it is settable.
+ // This is only possible for vars.
+ if (auto var = dyn_cast<VarDecl>(storage)) {
+ if (!baseType || var->isStatic())
+ return true;
+ }
+
+ // If the base is an lvalue, then a reference produces an lvalue.
+ if (baseType->is<LValueType>())
+ return true;
+
+ // Stored properties of reference types produce lvalues.
+ if (baseType->hasReferenceSemantics() && storage->hasStorage())
+ return true;
+
+ // So the base is an rvalue type. The only way an accessor can
+ // produce an lvalue is if we have a property where both the
+ // getter and setter are nonmutating.
+ return !storage->hasStorage() &&
+ !storage->isGetterMutating() &&
+ storage->isSetterNonMutating();
+}
+
+Type TypeChecker::getUnopenedTypeOfReference(VarDecl *value, Type baseType,
+ DeclContext *UseDC,
+ const DeclRefExpr *base,
+ bool wantInterfaceType) {
+ validateDecl(value);
+ if (value->isInvalid())
+ return ErrorType::get(Context);
+
+ Type requestedType = (wantInterfaceType
+ ? value->getInterfaceType()
+ : value->getType());
+
+ requestedType = requestedType->getLValueOrInOutObjectType()
+ ->getReferenceStorageReferent();
+
+ // If we're dealing with contextual types, and we referenced this type from
+ // a different context, map the type.
+ if (!wantInterfaceType && requestedType->hasArchetype()) {
+ auto valueDC = value->getDeclContext();
+ if (valueDC != UseDC) {
+ Type mapped = valueDC->mapTypeOutOfContext(requestedType);
+ requestedType = UseDC->mapTypeIntoContext(mapped);
+ }
+ }
+
+ // Qualify storage declarations with an lvalue when appropriate.
+ // Otherwise, they yield rvalues (and the access must be a load).
+ if (doesStorageProduceLValue(*this, value, baseType, UseDC, base)) {
+ return LValueType::get(requestedType);
+ }
+
+ return requestedType;
+}
+
void ConstraintSystem::recordOpenedTypes(
ConstraintLocatorBuilder locator,
const OpenedTypeMap &replacements) {
@@ -675,7 +747,6 @@
std::pair<Type, Type>
ConstraintSystem::getTypeOfReference(ValueDecl *value,
- bool isSpecialized,
FunctionRefKind functionRefKind,
ConstraintLocatorBuilder locator,
const DeclRefExpr *base) {
@@ -717,12 +788,34 @@
return { openedType, openedFnType->getResult() };
}
- // If we have a type declaration, resolve it within the current context.
+ // Unqualified reference to a local or global function.
+ if (auto funcDecl = dyn_cast<AbstractFunctionDecl>(value)) {
+ OpenedTypeMap replacements;
+
+ auto funcType = funcDecl->getInterfaceType()->castTo<AnyFunctionType>();
+ auto openedType =
+ openFunctionType(
+ funcType,
+ getNumRemovedArgumentLabels(TC.Context, funcDecl,
+ /*isCurriedInstanceReference=*/false,
+ functionRefKind),
+ locator, replacements,
+ funcDecl->getInnermostDeclContext(),
+ funcDecl->getDeclContext(),
+ /*skipProtocolSelfConstraint=*/false);
+
+ // If we opened up any type variables, record the replacements.
+ recordOpenedTypes(locator, replacements);
+
+ return { openedType, openedType };
+ }
+
+ // Unqualified reference to a type.
if (auto typeDecl = dyn_cast<TypeDecl>(value)) {
// Resolve the reference to this type declaration in our current context.
- auto type = getTypeChecker().resolveTypeInContext(typeDecl, DC,
- TR_InExpression,
- isSpecialized);
+ auto type = TC.resolveTypeInContext(typeDecl, DC,
+ TR_InExpression,
+ /*isSpecialized=*/false);
// Open the type.
type = openUnboundGenericType(type, locator);
@@ -736,18 +829,22 @@
return { type, type };
}
+ // Only remaining case: unqualified reference to a property.
+ auto *varDecl = cast<VarDecl>(value);
+
// Determine the type of the value, opening up that type if necessary.
- bool wantInterfaceType = true;
- if (isa<VarDecl>(value))
- wantInterfaceType = !value->getDeclContext()->isLocalContext();
- Type valueType = TC.getUnopenedTypeOfReference(value, Type(), DC, base,
+ bool wantInterfaceType = !varDecl->getDeclContext()->isLocalContext();
+ Type valueType = TC.getUnopenedTypeOfReference(varDecl, Type(), DC, base,
wantInterfaceType);
+ assert(!valueType->hasUnboundGenericType() &&
+ !valueType->hasTypeParameter());
+
// If this is a let-param whose type is a type variable, this is an untyped
// closure param that may be bound to an inout type later. References to the
// param should have lvalue type instead. Express the relationship with a new
// constraint.
- if (auto *param = dyn_cast<ParamDecl>(value)) {
+ if (auto *param = dyn_cast<ParamDecl>(varDecl)) {
if (param->isLet() && valueType->is<TypeVariableType>()) {
Type paramType = valueType;
valueType = createTypeVariable(getConstraintLocator(locator),
@@ -757,28 +854,6 @@
}
}
- // Adjust the type of the reference.
- if (auto funcType = valueType->getAs<AnyFunctionType>()) {
- OpenedTypeMap replacements;
-
- valueType =
- openFunctionType(
- funcType,
- getNumRemovedArgumentLabels(TC.Context, value,
- /*isCurriedInstanceReference=*/false,
- functionRefKind),
- locator, replacements,
- value->getInnermostDeclContext(),
- value->getDeclContext(),
- /*skipProtocolSelfConstraint=*/false);
-
- // If we opened up any type variables, record the replacements.
- recordOpenedTypes(locator, replacements);
- } else {
- assert(!valueType->hasUnboundGenericType() &&
- !valueType->hasTypeParameter());
- }
-
return { valueType, valueType };
}
@@ -996,8 +1071,7 @@
// If the base is a module type, just use the type of the decl.
if (baseObjTy->is<ModuleType>()) {
- return getTypeOfReference(value, /*isSpecialized=*/false,
- functionRefKind, locator, base);
+ return getTypeOfReference(value, functionRefKind, locator, base);
}
// Don't open existentials when accessing typealias members of
@@ -1005,17 +1079,24 @@
if (auto *alias = dyn_cast<TypeAliasDecl>(value)) {
if (baseObjTy->isExistentialType()) {
auto memberTy = alias->getDeclaredInterfaceType();
+ // If we end up with a protocol typealias here, it's underlying
+ // type must be fully concrete.
+ assert(!memberTy->hasTypeParameter());
auto openedType = FunctionType::get(baseObjTy, memberTy);
return { openedType, memberTy };
}
}
- // Handle associated type lookup as a special case, horribly.
- // FIXME: This is an awful hack.
- if (isa<AssociatedTypeDecl>(value)) {
- // Refer to a member of the archetype directly.
- auto archetype = baseObjTy->castTo<ArchetypeType>();
- Type memberTy = archetype->getNestedType(value->getName());
+ if (auto *typeDecl = dyn_cast<TypeDecl>(value)) {
+ assert(!isa<ModuleDecl>(typeDecl) && "Nested module?");
+
+ auto memberTy = TC.substMemberTypeWithBase(DC->getParentModule(),
+ typeDecl, baseObjTy);
+
+ // Open the type if it was a reference to a generic type.
+ memberTy = openUnboundGenericType(memberTy, locator);
+
+ // Wrap it in a metatype.
memberTy = MetatypeType::get(memberTy);
auto openedType = FunctionType::get(baseObjTy, memberTy);
@@ -1035,48 +1116,68 @@
getNumRemovedArgumentLabels(TC.Context, value, isCurriedInstanceReference,
functionRefKind);
+ AnyFunctionType *funcType;
+
if (isa<AbstractFunctionDecl>(value) ||
isa<EnumElementDecl>(value)) {
// This is the easy case.
- auto funcType = value->getInterfaceType()->getAs<AnyFunctionType>();
-
- openedType = openFunctionType(funcType, numRemovedArgumentLabels,
- locator, replacements, innerDC, outerDC,
- /*skipProtocolSelfConstraint=*/true);
+ funcType = value->getInterfaceType()->castTo<AnyFunctionType>();
} else {
- // If we're not coming from something function-like, prepend the type
- // for 'self' to the type.
- assert(isa<AbstractStorageDecl>(value) ||
- isa<TypeDecl>(value));
+ // For a property, build a type (Self) -> PropType.
+ // For a subscript, build a type (Self) -> (Indices...) -> ElementType.
+ //
+ // If the access is mutating, wrap the storage type in an lvalue type.
+ Type refType;
+ if (auto *subscript = dyn_cast<SubscriptDecl>(value)) {
+ auto elementTy = subscript->getElementInterfaceType();
- openedType = TC.getUnopenedTypeOfReference(value, baseTy, useDC, base,
- /*wantInterfaceType=*/true);
+ if (doesStorageProduceLValue(TC, subscript, baseTy, useDC, base))
+ elementTy = LValueType::get(elementTy);
- // Remove argument labels, if needed.
- openedType = removeArgumentLabels(openedType, numRemovedArgumentLabels);
+ // See ConstraintSystem::resolveOverload() -- optional and dynamic
+ // subscripts are a special case, because the optionality is
+ // applied to the result type and not the type of the reference.
+ if (!isRequirementOrWitness(locator)) {
+ if (subscript->getAttrs().hasAttribute<OptionalAttr>())
+ elementTy = OptionalType::get(elementTy->getRValueType());
+ else if (isDynamicResult) {
+ elementTy = ImplicitlyUnwrappedOptionalType::get(
+ elementTy->getRValueType());
+ }
+ }
- // Open up the generic parameter list for the container.
- openGeneric(innerDC, outerDC, innerDC->getGenericSignatureOfContext(),
- /*skipProtocolSelfConstraint=*/true,
- locator, replacements);
+ auto indicesTy = subscript->getIndicesInterfaceType();
+ refType = FunctionType::get(indicesTy, elementTy,
+ AnyFunctionType::ExtInfo());
+ } else {
+ refType = TC.getUnopenedTypeOfReference(cast<VarDecl>(value),
+ baseTy, useDC, base,
+ /*wantInterfaceType=*/true);
+ }
- // Open up the type of the member.
- openedType = openType(openedType, replacements);
+ auto selfTy = outerDC->getSelfInterfaceType();
- // Determine the object type of 'self'.
- auto selfTy = openType(outerDC->getSelfInterfaceType(),
- replacements);
-
- // If self is a struct, properly qualify it based on our base
- // qualification. If we have an lvalue coming in, we expect an inout.
+ // If self is a value type and the base type is an lvalue, wrap it in an
+ // inout type.
if (!outerDC->getDeclaredTypeOfContext()->hasReferenceSemantics() &&
baseTy->is<LValueType>() &&
!selfTy->hasError())
selfTy = InOutType::get(selfTy);
- openedType = FunctionType::get(selfTy, openedType);
+ // If the storage is generic, add a generic signature.
+ if (auto *sig = innerDC->getGenericSignatureOfContext()) {
+ funcType = GenericFunctionType::get(sig, selfTy, refType,
+ AnyFunctionType::ExtInfo());
+ } else {
+ funcType = FunctionType::get(selfTy, refType,
+ AnyFunctionType::ExtInfo());
+ }
}
+ openedType = openFunctionType(funcType, numRemovedArgumentLabels,
+ locator, replacements, innerDC, outerDC,
+ /*skipProtocolSelfConstraint=*/true);
+
if (!outerDC->getAsProtocolOrProtocolExtensionContext()) {
// Class methods returning Self as well as constructors get the
// result replaced with the base object type.
@@ -1122,27 +1223,9 @@
// Compute the type of the reference.
Type type;
- if (auto subscript = dyn_cast<SubscriptDecl>(value)) {
- // For a subscript, turn the element type into an (@unchecked)
- // optional or lvalue, depending on whether the result type is
- // optional/dynamic, is settable, or is not.
- auto fnType = openedFnType->getResult()->castTo<FunctionType>();
- auto elementTy = fnType->getResult();
- if (!isRequirementOrWitness(locator)) {
- if (subscript->getAttrs().hasAttribute<OptionalAttr>())
- elementTy = OptionalType::get(elementTy->getRValueType());
- else if (isDynamicResult) {
- elementTy = ImplicitlyUnwrappedOptionalType::get(
- elementTy->getRValueType());
- }
- }
-
- type = FunctionType::get(fnType->getInput(), elementTy);
- } else if (!value->isInstanceMember() || isInstance) {
- // For a constructor, enum element, static method, static property,
- // or an instance method referenced through an instance, we've consumed the
- // curried 'self' already. For a type, strip off the 'self' we artificially
- // added.
+ if (!value->isInstanceMember() || isInstance) {
+ // For a static member referenced through a metatype or an instance
+ // member referenced through an instance, strip off the 'self'.
type = openedFnType->getResult();
} else if (isDynamicResult && isa<AbstractFunctionDecl>(value)) {
// For a dynamic result referring to an instance function through
@@ -1380,7 +1463,6 @@
} else {
std::tie(openedFullType, refType)
= getTypeOfReference(choice.getDecl(),
- choice.isSpecialized(),
choice.getFunctionRefKind(), locator);
}
diff --git a/lib/Sema/ConstraintSystem.h b/lib/Sema/ConstraintSystem.h
index eefaf33..26adfc0 100644
--- a/lib/Sema/ConstraintSystem.h
+++ b/lib/Sema/ConstraintSystem.h
@@ -575,9 +575,6 @@
/// on a suspicious top-level optional injection (because the caller already
/// diagnosed it).
///
- /// \param skipClosures Whether to skip bodies of non-single expression
- /// closures.
- ///
/// \param typeFromPattern Optionally, the caller can specify the pattern
/// from where the toType is derived, so that we can deliver better fixit.
///
@@ -585,7 +582,6 @@
Expr *coerceToType(Expr *expr, Type toType,
ConstraintLocator *locator,
bool ignoreTopLevelInjection = false,
- bool skipClosures = false,
Optional<Pattern*> typeFromPattern = None) const;
/// \brief Convert the given expression to a logic value.
@@ -1959,13 +1955,10 @@
///
/// \param decl The declarations whose type is being computed.
///
- /// \param isSpecialized Whether this declaration is immediately specialized.
- ///
/// \returns a pair containing the full opened type (if applicable) and
/// opened type of a reference to declaration.
std::pair<Type, Type> getTypeOfReference(
ValueDecl *decl,
- bool isSpecialized,
FunctionRefKind functionRefKind,
ConstraintLocatorBuilder locator,
const DeclRefExpr *base = nullptr);
diff --git a/lib/Sema/OverloadChoice.h b/lib/Sema/OverloadChoice.h
index 635715a..ee9f0a2 100644
--- a/lib/Sema/OverloadChoice.h
+++ b/lib/Sema/OverloadChoice.h
@@ -65,8 +65,6 @@
///
class OverloadChoice {
enum : unsigned {
- /// Indicates whether this overload was immediately specialized.
- IsSpecializedBit = 0x01,
/// Indicates whether this declaration was bridged, turning a
/// "Decl" kind into "DeclViaBridge" kind.
IsBridgedBit = 0x02,
@@ -81,9 +79,7 @@
};
/// \brief The base type to be used when referencing the declaration
- /// along with two bits: the low bit indicates whether this overload
- /// was immediately specialized and the second lowest bit indicates
- /// whether the declaration was bridged.
+ /// along with the two bits above.
llvm::PointerIntPair<Type, 3, unsigned> BaseAndBits;
/// \brief Either the declaration pointer (if the low bit is clear) or the
@@ -99,9 +95,9 @@
: BaseAndBits(nullptr, 0), DeclOrKind(0),
TheFunctionRefKind(FunctionRefKind::Unapplied) {}
- OverloadChoice(Type base, ValueDecl *value, bool isSpecialized,
+ OverloadChoice(Type base, ValueDecl *value,
FunctionRefKind functionRefKind)
- : BaseAndBits(base, isSpecialized ? IsSpecializedBit : 0),
+ : BaseAndBits(base, 0),
TheFunctionRefKind(functionRefKind) {
assert(!base || !base->hasTypeParameter());
assert((reinterpret_cast<uintptr_t>(value) & (uintptr_t)0x03) == 0 &&
@@ -178,14 +174,6 @@
/// \brief Retrieve the base type used to refer to the declaration.
Type getBaseType() const { return BaseAndBits.getPointer(); }
-
- /// \brief Determine whether the referenced declaration was immediately
- /// specialized with <...>.
- ///
- /// This value only has meaning when there is no base type.
- bool isSpecialized() const {
- return BaseAndBits.getInt() & IsSpecializedBit;
- }
/// \brief Determines the kind of overload choice this is.
OverloadChoiceKind getKind() const {
diff --git a/lib/Sema/TypeCheckAttr.cpp b/lib/Sema/TypeCheckAttr.cpp
index 6c657b3..a43c95e 100644
--- a/lib/Sema/TypeCheckAttr.cpp
+++ b/lib/Sema/TypeCheckAttr.cpp
@@ -107,6 +107,7 @@
IGNORED_ATTR(NSKeyedArchiverClassName)
IGNORED_ATTR(StaticInitializeObjCMetadata)
IGNORED_ATTR(NSKeyedArchiverEncodeNonGenericSubclassesOnly)
+ IGNORED_ATTR(DowngradeExhaustivityCheck)
#undef IGNORED_ATTR
// @noreturn has been replaced with a 'Never' return type.
@@ -784,6 +785,7 @@
IGNORED_ATTR(ObjCMembers)
IGNORED_ATTR(StaticInitializeObjCMetadata)
IGNORED_ATTR(NSKeyedArchiverEncodeNonGenericSubclassesOnly)
+ IGNORED_ATTR(DowngradeExhaustivityCheck)
#undef IGNORED_ATTR
void visitAvailableAttr(AvailableAttr *attr);
diff --git a/lib/Sema/TypeCheckConstraints.cpp b/lib/Sema/TypeCheckConstraints.cpp
index d974bcb..1035ea5 100644
--- a/lib/Sema/TypeCheckConstraints.cpp
+++ b/lib/Sema/TypeCheckConstraints.cpp
@@ -581,8 +581,7 @@
}
return buildRefExpr(ResultValues, DC, UDRE->getNameLoc(),
- UDRE->isImplicit(), UDRE->isSpecialized(),
- UDRE->getFunctionRefKind());
+ UDRE->isImplicit(), UDRE->getFunctionRefKind());
}
ResultValues.clear();
@@ -1631,6 +1630,10 @@
return false;
}
+Expr *ExprTypeCheckListener::foundSolution(Solution &solution, Expr *expr) {
+ return expr;
+}
+
Expr *ExprTypeCheckListener::appliedSolution(Solution &solution, Expr *expr) {
return expr;
}
@@ -1864,14 +1867,24 @@
expr->setType(ErrorType::get(Context));
return false;
}
-
- // Apply the solution to the expression.
+
+ auto result = expr;
auto &solution = viable[0];
+ if (listener) {
+ result = listener->foundSolution(solution, result);
+ if (!result)
+ return true;
+ }
+
+ if (options.contains(TypeCheckExprFlags::SkipApplyingSolution))
+ return false;
+
+ // Apply the solution to the expression.
bool isDiscarded = options.contains(TypeCheckExprFlags::IsDiscarded);
bool skipClosures = options.contains(TypeCheckExprFlags::SkipMultiStmtClosures);
- auto result = cs.applySolution(solution, expr, convertType.getType(),
- isDiscarded, suppressDiagnostics,
- skipClosures);
+ result = cs.applySolution(solution, result, convertType.getType(),
+ isDiscarded, suppressDiagnostics,
+ skipClosures);
if (!result) {
// Failure already diagnosed, above, as part of applying the solution.
return true;
@@ -2111,26 +2124,25 @@
}
bool TypeChecker::typeCheckBinding(Pattern *&pattern, Expr *&initializer,
- DeclContext *DC, bool skipClosures) {
+ DeclContext *DC, bool skipApplyingSolution) {
/// Type checking listener for pattern binding initializers.
class BindingListener : public ExprTypeCheckListener {
Pattern *&pattern;
Expr *&initializer;
- DeclContext *DC;
- bool skipClosures;
/// The locator we're using.
ConstraintLocator *Locator;
/// The type of the initializer.
Type InitType;
-
+
public:
- explicit BindingListener(Pattern *&pattern, Expr *&initializer,
- DeclContext *DC, bool skipClosures)
- : pattern(pattern), initializer(initializer), DC(DC),
- skipClosures(skipClosures) { }
+ explicit BindingListener(Pattern *&pattern, Expr *&initializer)
+ : pattern(pattern), initializer(initializer),
+ Locator(nullptr) { }
+
+ Type getInitType() const { return InitType; }
bool builtConstraints(ConstraintSystem &cs, Expr *expr) override {
// Save the locator we're using for the expression.
@@ -2150,44 +2162,32 @@
return false;
}
- Expr *appliedSolution(Solution &solution, Expr *expr) override {
+ Expr *foundSolution(Solution &solution, Expr *expr) override {
// Figure out what type the constraints decided on.
- auto &cs = solution.getConstraintSystem();
- auto &tc = cs.getTypeChecker();
InitType = solution.simplifyType(InitType);
+ // Just keep going.
+ return expr;
+ }
+
+ Expr *appliedSolution(Solution &solution, Expr *expr) override {
// Convert the initializer to the type of the pattern.
// ignoreTopLevelInjection = Binding->isConditional()
expr = solution.coerceToType(expr, InitType, Locator,
- false /* ignoreTopLevelInjection */,
- skipClosures);
+ false /* ignoreTopLevelInjection */);
if (!expr) {
return nullptr;
}
- // Force the initializer to be materializable.
- // FIXME: work this into the constraint system
- expr = tc.coerceToMaterializable(expr);
+ assert(expr->getType()->isEqual(InitType));
- // Apply the solution to the pattern as well.
- Type patternType = expr->getType();
-
- TypeResolutionOptions options;
- options |= TR_OverrideType;
- options |= TR_InExpression;
- if (isa<EditorPlaceholderExpr>(expr->getSemanticsProvidingExpr())) {
- options |= TR_EditorPlaceholder;
- }
- if (tc.coercePatternToType(pattern, DC, patternType, options)) {
- return nullptr;
- }
initializer = expr;
return expr;
}
};
assert(initializer && "type-checking an uninitialized binding?");
- BindingListener listener(pattern, initializer, DC, skipClosures);
+ BindingListener listener(pattern, initializer);
TypeLoc contextualType;
auto contextualPurpose = CTP_Unused;
@@ -2209,18 +2209,34 @@
// Type-check the initializer.
TypeCheckExprOptions flags = TypeCheckExprFlags::ConvertTypeIsOnlyAHint;
- if (skipClosures)
- flags |= TypeCheckExprFlags::SkipMultiStmtClosures;
+ if (skipApplyingSolution)
+ flags |= TypeCheckExprFlags::SkipApplyingSolution;
bool hadError = typeCheckExpression(initializer, DC, contextualType,
contextualPurpose,
flags,
&listener);
-
- if (hadError && !initializer->getType()) {
- initializer->setType(ErrorType::get(Context));
+
+ if (!hadError) {
+ TypeResolutionOptions options;
+ options |= TR_OverrideType;
+ options |= TR_InExpression;
+ if (isa<EditorPlaceholderExpr>(initializer->getSemanticsProvidingExpr())) {
+ options |= TR_EditorPlaceholder;
+ }
+
+ // Apply the solution to the pattern as well.
+ if (coercePatternToType(pattern, DC, listener.getInitType(), options)) {
+ return true;
+ }
}
+ if (hadError && !initializer->getType())
+ initializer->setType(ErrorType::get(Context));
+
+ // If the type of the pattern is inferred, assign error types to the pattern
+ // and its variables, to prevent it from being referenced by the constraint
+ // system.
if (hadError &&
(!pattern->hasType() ||
pattern->getType()->hasUnboundGenericType())) {
@@ -2242,7 +2258,7 @@
bool TypeChecker::typeCheckPatternBinding(PatternBindingDecl *PBD,
unsigned patternNumber,
- bool skipClosures) {
+ bool skipApplyingSolution) {
Pattern *pattern = PBD->getPattern(patternNumber);
Expr *init = PBD->getInit(patternNumber);
@@ -2262,11 +2278,10 @@
DC = initContext;
}
- bool hadError = typeCheckBinding(pattern, init, DC, skipClosures);
+ bool hadError = typeCheckBinding(pattern, init, DC, skipApplyingSolution);
PBD->setPattern(patternNumber, pattern, initContext);
PBD->setInit(patternNumber, init);
-
// If we entered an initializer context, contextualize any
// auto-closures we might have created.
if (initContext) {
@@ -2600,7 +2615,8 @@
// If the pattern didn't get a type, it's because we ran into some
// unknown types along the way. We'll need to check the initializer.
auto init = elt.getInitializer();
- hadError |= typeCheckBinding(pattern, init, dc, /*skipClosures*/false);
+ hadError |= typeCheckBinding(pattern, init, dc,
+ /*skipApplyingSolution*/false);
elt.setPattern(pattern);
elt.setInitializer(init);
hadAnyFalsable |= pattern->isRefutablePattern();
@@ -2657,8 +2673,7 @@
// Build the 'expr ~= var' expression.
// FIXME: Compound name locations.
auto *matchOp = buildRefExpr(choices, DC, DeclNameLoc(EP->getLoc()),
- /*Implicit=*/true, /*isSpecialized=*/false,
- FunctionRefKind::Compound);
+ /*Implicit=*/true, FunctionRefKind::Compound);
auto *matchVarRef = new (Context) DeclRefExpr(matchVar,
DeclNameLoc(EP->getLoc()),
/*Implicit=*/true);
@@ -2917,7 +2932,6 @@
Expr *result = solution.coerceToType(expr, type,
cs.getConstraintLocator(expr),
/*ignoreTopLevelInjection*/false,
- /*skipClosures*/false,
typeFromPattern);
if (!result) {
return true;
diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp
index 7ce273b..6994a3d 100644
--- a/lib/Sema/TypeCheckDecl.cpp
+++ b/lib/Sema/TypeCheckDecl.cpp
@@ -1198,11 +1198,11 @@
// If the pattern didn't get a type or if it contains an unbound generic type,
// we'll need to check the initializer.
if (!pattern->hasType() || pattern->getType()->hasUnboundGenericType()) {
- bool skipClosures = false;
+ bool skipApplyingSolution = false;
if (auto var = binding->getSingleVar())
- skipClosures = var->getAttrs().hasAttribute<LazyAttr>();
+ skipApplyingSolution = var->getAttrs().hasAttribute<LazyAttr>();
- if (tc.typeCheckPatternBinding(binding, entryNumber, skipClosures))
+ if (tc.typeCheckPatternBinding(binding, entryNumber, skipApplyingSolution))
return;
}
@@ -4047,7 +4047,7 @@
if (!IsFirstPass) {
for (unsigned i = 0, e = PBD->getNumPatternEntries(); i != e; ++i) {
if (!PBD->isInitializerChecked(i) && PBD->getInit(i))
- TC.typeCheckPatternBinding(PBD, i, /*skipClosures*/false);
+ TC.typeCheckPatternBinding(PBD, i, /*skipApplyingSolution*/false);
}
}
@@ -4078,7 +4078,7 @@
// If we got a default initializer, install it and re-type-check it
// to make sure it is properly coerced to the pattern type.
PBD->setInit(i, defaultInit);
- TC.typeCheckPatternBinding(PBD, i, /*skipClosures*/false);
+ TC.typeCheckPatternBinding(PBD, i, /*skipApplyingSolution*/false);
}
}
}
@@ -6142,6 +6142,7 @@
UNINTERESTING_ATTR(NSKeyedArchiverClassName)
UNINTERESTING_ATTR(StaticInitializeObjCMetadata)
UNINTERESTING_ATTR(NSKeyedArchiverEncodeNonGenericSubclassesOnly)
+ UNINTERESTING_ATTR(DowngradeExhaustivityCheck)
#undef UNINTERESTING_ATTR
void visitAvailableAttr(AvailableAttr *attr) {
diff --git a/lib/Sema/TypeCheckExpr.cpp b/lib/Sema/TypeCheckExpr.cpp
index 20eff06..3005be9 100644
--- a/lib/Sema/TypeCheckExpr.cpp
+++ b/lib/Sema/TypeCheckExpr.cpp
@@ -492,23 +492,6 @@
return makeBinOp(TC, op1.op, LHS, RHS, op1.precedence, S.empty());
}
-Type TypeChecker::getTypeOfRValue(ValueDecl *value, bool wantInterfaceType) {
-
- Type type;
- if (wantInterfaceType) {
- if (!value->hasInterfaceType())
- validateDecl(value);
- type = value->getInterfaceType();
- } else {
- auto *var = cast<VarDecl>(value);
- if (!var->hasType())
- validateDecl(var);
- type = var->getType();
- }
-
- return type->getLValueOrInOutObjectType()->getReferenceStorageReferent();
-}
-
bool TypeChecker::requireOptionalIntrinsics(SourceLoc loc) {
if (Context.hasOptionalIntrinsics(this)) return false;
@@ -530,94 +513,6 @@
return true;
}
-/// Does a var or subscript produce an l-value?
-///
-/// \param baseType - the type of the base on which this object
-/// is being accessed; must be null if and only if this is not
-/// a type member
-static bool doesStorageProduceLValue(TypeChecker &TC,
- AbstractStorageDecl *storage,
- Type baseType, DeclContext *useDC,
- const DeclRefExpr *base = nullptr) {
- // Unsettable storage decls always produce rvalues.
- if (!storage->isSettable(useDC, base))
- return false;
-
- if (TC.Context.LangOpts.EnableAccessControl &&
- !storage->isSetterAccessibleFrom(useDC))
- return false;
-
- // If there is no base, or if the base isn't being used, it is settable.
- // This is only possible for vars.
- if (auto var = dyn_cast<VarDecl>(storage)) {
- if (!baseType || var->isStatic())
- return true;
- }
-
- // If the base is an lvalue, then a reference produces an lvalue.
- if (baseType->is<LValueType>())
- return true;
-
- // Stored properties of reference types produce lvalues.
- if (baseType->hasReferenceSemantics() && storage->hasStorage())
- return true;
-
- // So the base is an rvalue type. The only way an accessor can
- // produce an lvalue is if we have a property where both the
- // getter and setter are nonmutating.
- return !storage->hasStorage() &&
- !storage->isGetterMutating() &&
- storage->isSetterNonMutating();
-}
-
-Type TypeChecker::getUnopenedTypeOfReference(ValueDecl *value, Type baseType,
- DeclContext *UseDC,
- const DeclRefExpr *base,
- bool wantInterfaceType) {
- validateDecl(value);
- if (value->isInvalid())
- return ErrorType::get(Context);
-
- Type requestedType = getTypeOfRValue(value, wantInterfaceType);
-
- // If we're dealing with contextual types, and we referenced this type from
- // a different context, map the type.
- if (!wantInterfaceType && requestedType->hasArchetype()) {
- auto valueDC = value->getDeclContext();
- if (valueDC != UseDC) {
- Type mapped = valueDC->mapTypeOutOfContext(requestedType);
- requestedType = UseDC->mapTypeIntoContext(mapped);
- }
- }
-
- // Qualify storage declarations with an lvalue when appropriate.
- // Otherwise, they yield rvalues (and the access must be a load).
- if (auto *storage = dyn_cast<AbstractStorageDecl>(value)) {
- if (doesStorageProduceLValue(*this, storage, baseType, UseDC, base)) {
- // Vars are simply lvalues of their rvalue type.
- if (isa<VarDecl>(storage))
- return LValueType::get(requestedType);
-
- // Subscript decls have function type. For the purposes of later type
- // checker consumption, model this as returning an lvalue.
- assert(isa<SubscriptDecl>(storage));
- auto *RFT = requestedType->castTo<AnyFunctionType>();
- return FunctionType::get(RFT->getInput(),
- LValueType::get(RFT->getResult()),
- RFT->getExtInfo());
- }
-
- // FIXME: Fix downstream callers.
- if (auto *genericFn = requestedType->getAs<GenericFunctionType>()) {
- return FunctionType::get(genericFn->getInput(),
- genericFn->getResult(),
- genericFn->getExtInfo());
- }
- }
-
- return requestedType;
-}
-
Expr *TypeChecker::buildCheckedRefExpr(VarDecl *value, DeclContext *UseDC,
DeclNameLoc loc, bool Implicit) {
auto type = getUnopenedTypeOfReference(value, Type(), UseDC);
@@ -627,22 +522,16 @@
Expr *TypeChecker::buildRefExpr(ArrayRef<ValueDecl *> Decls,
DeclContext *UseDC, DeclNameLoc NameLoc,
- bool Implicit, bool isSpecialized,
- FunctionRefKind functionRefKind) {
+ bool Implicit, FunctionRefKind functionRefKind) {
assert(!Decls.empty() && "Must have at least one declaration");
if (Decls.size() == 1 && !isa<ProtocolDecl>(Decls[0]->getDeclContext())) {
AccessSemantics semantics = Decls[0]->getAccessSemanticsFromContext(UseDC);
- auto result = new (Context) DeclRefExpr(Decls[0], NameLoc, Implicit,
- semantics);
- if (isSpecialized)
- result->setSpecialized();
- return result;
+ return new (Context) DeclRefExpr(Decls[0], NameLoc, Implicit, semantics);
}
Decls = Context.AllocateCopy(Decls);
auto result = new (Context) OverloadedDeclRefExpr(Decls, NameLoc,
- isSpecialized,
functionRefKind,
Implicit);
return result;
diff --git a/lib/Sema/TypeCheckPattern.cpp b/lib/Sema/TypeCheckPattern.cpp
index 6b224dd..0c2eb88 100644
--- a/lib/Sema/TypeCheckPattern.cpp
+++ b/lib/Sema/TypeCheckPattern.cpp
@@ -1108,7 +1108,7 @@
NP->getDecl()->setLet(false);
}
if (var->getAttrs().hasAttribute<OwnershipAttr>())
- type = getTypeOfRValue(var, false);
+ type = var->getType()->getReferenceStorageReferent();
else if (!var->isInvalid())
type = var->getType();
P->setType(type);
diff --git a/lib/Sema/TypeCheckProtocol.cpp b/lib/Sema/TypeCheckProtocol.cpp
index 02ffb2d..49dd244 100644
--- a/lib/Sema/TypeCheckProtocol.cpp
+++ b/lib/Sema/TypeCheckProtocol.cpp
@@ -1193,19 +1193,16 @@
witnessLocator = cs->getConstraintLocator(
static_cast<Expr *>(nullptr),
LocatorPathElt(ConstraintLocator::Witness, witness));
- OpenedTypeMap witnessReplacements;
if (witness->getDeclContext()->isTypeContext()) {
std::tie(openedFullWitnessType, openWitnessType)
= cs->getTypeOfMemberReference(selfTy, witness, dc,
/*isDynamicResult=*/false,
FunctionRefKind::DoubleApply,
witnessLocator,
- /*base=*/nullptr,
- &witnessReplacements);
+ /*base=*/nullptr);
} else {
std::tie(openedFullWitnessType, openWitnessType)
= cs->getTypeOfReference(witness,
- /*isSpecialized=*/false,
FunctionRefKind::DoubleApply,
witnessLocator,
/*base=*/nullptr);
@@ -6017,7 +6014,7 @@
/// Infer the attribute tostatic-initialize the Objective-C metadata for the
/// given class, if needed.
static void inferStaticInitializeObjCMetadata(ClassDecl *classDecl,
- bool requiresNSCodingAttr) {
+ bool requiresNSCodingAttr) {
// If we already have the attribute, there's nothing to do.
if (classDecl->getAttrs().hasAttribute<StaticInitializeObjCMetadataAttr>())
return;
diff --git a/lib/Sema/TypeCheckREPL.cpp b/lib/Sema/TypeCheckREPL.cpp
index 532d82a..abd1711 100644
--- a/lib/Sema/TypeCheckREPL.cpp
+++ b/lib/Sema/TypeCheckREPL.cpp
@@ -97,15 +97,13 @@
Expr *buildPrintRefExpr(SourceLoc loc) {
assert(!C.PrintDecls.empty());
return TC.buildRefExpr(C.PrintDecls, DC, DeclNameLoc(loc),
- /*Implicit=*/true, /*isSpecialized=*/false,
- FunctionRefKind::Compound);
+ /*Implicit=*/true, FunctionRefKind::Compound);
}
Expr *buildDebugPrintlnRefExpr(SourceLoc loc) {
assert(!C.DebugPrintlnDecls.empty());
return TC.buildRefExpr(C.DebugPrintlnDecls, DC, DeclNameLoc(loc),
- /*Implicit=*/true, /*isSpecialized=*/false,
- FunctionRefKind::Compound);
+ /*Implicit=*/true, FunctionRefKind::Compound);
}
};
} // unnamed namespace
@@ -119,7 +117,6 @@
void StmtBuilder::printReplExpr(VarDecl *Arg, SourceLoc Loc) {
Expr *DebugPrintlnFn = buildDebugPrintlnRefExpr(Loc);
Expr *ArgRef = TC.buildRefExpr(Arg, DC, DeclNameLoc(Loc), /*Implicit=*/true,
- /*isSpecialized=*/false,
FunctionRefKind::Compound);
addToBody(CallExpr::createImplicit(Context, DebugPrintlnFn, { ArgRef }, { }));
}
diff --git a/lib/Sema/TypeCheckSwitchStmt.cpp b/lib/Sema/TypeCheckSwitchStmt.cpp
index 252891e..93cfaf6 100644
--- a/lib/Sema/TypeCheckSwitchStmt.cpp
+++ b/lib/Sema/TypeCheckSwitchStmt.cpp
@@ -83,8 +83,8 @@
explicit Space(Type T)
: Kind(SpaceKind::Type), TypeAndVal(T, false), Head(Identifier()),
Spaces({}){}
- explicit Space(Type T, Identifier H, SmallVectorImpl<Space> &SP)
- : Kind(SpaceKind::Constructor), TypeAndVal(T, false), Head(H),
+ explicit Space(Type T, Identifier H, bool downgrade, SmallVectorImpl<Space> &SP)
+ : Kind(SpaceKind::Constructor), TypeAndVal(T, downgrade), Head(H),
Spaces(SP.begin(), SP.end()) {}
explicit Space(SmallVectorImpl<Space> &SP)
: Kind(SpaceKind::Disjunct), TypeAndVal(Type(), false),
@@ -101,6 +101,12 @@
void dump() const LLVM_ATTRIBUTE_USED;
bool isEmpty() const { return getKind() == SpaceKind::Empty; }
+
+ bool canDowngrade() const {
+ assert(getKind() == SpaceKind::Constructor
+ && "Wrong kind of space tried to access downgrade");
+ return TypeAndVal.getInt();
+ }
Type getType() const {
assert((getKind() == SpaceKind::Type
@@ -585,7 +591,8 @@
SmallVector<Space, 4> copyParams(this->getSpaces().begin(),
this->getSpaces().end());
copyParams[idx] = s1.minus(s2, TC);
- Space CS(this->getType(), this->Head, copyParams);
+ Space CS(this->getType(), this->getHead(), this->canDowngrade(),
+ copyParams);
constrSpaces.push_back(CS);
}
@@ -721,7 +728,7 @@
return Space();
}
}
- return Space(getType(), Head, simplifiedSpaces);
+ return Space(getType(), Head, canDowngrade(), simplifiedSpaces);
}
case SpaceKind::Type: {
// If the decomposition of a space is empty, the space is empty.
@@ -813,7 +820,10 @@
constElemSpaces.push_back(Space(TTy->getUnderlyingType()));
}
}
- return Space(tp, eed->getName(), constElemSpaces);
+ return Space(tp, eed->getName(),
+ eed->getAttrs()
+ .getAttribute<DowngradeExhaustivityCheckAttr>(),
+ constElemSpaces);
});
} else if (auto *TTy = tp->castTo<TupleType>()) {
// Decompose each of the elements into its component type space.
@@ -824,7 +834,8 @@
return Space(ty.getType());
});
// Create an empty constructor head for the tuple space.
- arr.push_back(Space(tp, Identifier(), constElemSpaces));
+ arr.push_back(Space(tp, Identifier(), /*canDowngrade*/false,
+ constElemSpaces));
} else {
llvm_unreachable("Can't decompose type?");
}
@@ -851,6 +862,7 @@
return;
}
+ bool sawDowngradablePattern = false;
SmallVector<Space, 4> spaces;
for (unsigned i = 0, e = Switch->getCases().size(); i < e; ++i) {
auto *caseBlock = Switch->getCases()[i];
@@ -864,7 +876,8 @@
if (caseItem.isDefault())
return;
- auto projection = projectPattern(TC, caseItem.getPattern());
+ auto projection = projectPattern(TC, caseItem.getPattern(),
+ sawDowngradablePattern);
if (projection.isUseful()
&& projection.isSubspace(Space(spaces), TC)) {
TC.diagnose(caseItem.getStartLoc(),
@@ -874,7 +887,7 @@
spaces.push_back(projection);
}
}
-
+
Space totalSpace(Switch->getSubjectExpr()->getType());
Space coveredSpace(spaces);
auto uncovered = totalSpace.minus(coveredSpace, TC).simplify(TC);
@@ -904,43 +917,81 @@
uncovered = Space(spaces);
}
- diagnoseMissingCases(TC, Switch, /*justNeedsDefault*/ false, uncovered);
+ diagnoseMissingCases(TC, Switch, /*justNeedsDefault*/ false, uncovered,
+ sawDowngradablePattern);
+ }
+
+ // HACK: Search the space for any remaining cases that were labelled
+ // @_downgrade_exhaustivity_check.
+ static bool shouldDowngradeToWarning(const Space &masterSpace) {
+ switch (masterSpace.getKind()) {
+ case SpaceKind::Type:
+ case SpaceKind::BooleanConstant:
+ case SpaceKind::Empty:
+ return false;
+ // Traverse the constructor and its subspaces.
+ case SpaceKind::Constructor:
+ return masterSpace.canDowngrade()
+ || std::accumulate(masterSpace.getSpaces().begin(),
+ masterSpace.getSpaces().end(),
+ false,
+ [](bool acc, const Space &space) {
+ return acc || shouldDowngradeToWarning(space);
+ });
+ case SpaceKind::Disjunct:
+ // Traverse the disjunct's subspaces.
+ return std::accumulate(masterSpace.getSpaces().begin(),
+ masterSpace.getSpaces().end(),
+ false,
+ [](bool acc, const Space &space) {
+ return acc || shouldDowngradeToWarning(space);
+ });
+ }
}
- static void diagnoseMissingCases(TypeChecker &TC, const SwitchStmt *Switch,
- bool JustNeedsDefault,
- SpaceEngine::Space uncovered) {
- bool Empty = Switch->getCases().empty();
- SourceLoc StartLoc = Switch->getStartLoc();
- SourceLoc EndLoc = Switch->getEndLoc();
- StringRef Placeholder = getCodePlaceholder();
- llvm::SmallString<128> Buffer;
- llvm::raw_svector_ostream OS(Buffer);
+ static void diagnoseMissingCases(TypeChecker &TC, const SwitchStmt *SS,
+ bool justNeedsDefault,
+ Space uncovered,
+ bool sawDowngradablePattern = false) {
+ SourceLoc startLoc = SS->getStartLoc();
+ SourceLoc endLoc = SS->getEndLoc();
+ StringRef placeholder = getCodePlaceholder();
+ llvm::SmallString<128> buffer;
+ llvm::raw_svector_ostream OS(buffer);
bool InEditor = TC.Context.LangOpts.DiagnosticsEditorMode;
- if (JustNeedsDefault) {
- OS << tok::kw_default << ":\n" << Placeholder << "\n";
- if (Empty) {
- TC.Context.Diags.diagnose(StartLoc, diag::empty_switch_stmt)
- .fixItInsert(EndLoc, Buffer.str());
+ if (justNeedsDefault) {
+ OS << tok::kw_default << ":\n" << placeholder << "\n";
+ if (SS->getCases().empty()) {
+ TC.Context.Diags.diagnose(startLoc, diag::empty_switch_stmt)
+ .fixItInsert(endLoc, buffer.str());
} else {
- TC.Context.Diags.diagnose(StartLoc, diag::non_exhaustive_switch);
- TC.Context.Diags.diagnose(StartLoc, diag::missing_several_cases,
- uncovered.isEmpty()).fixItInsert(EndLoc,
- Buffer.str());
+ TC.Context.Diags.diagnose(startLoc, diag::non_exhaustive_switch);
+ TC.Context.Diags.diagnose(startLoc, diag::missing_several_cases,
+ uncovered.isEmpty()).fixItInsert(endLoc,
+ buffer.str());
}
return;
}
// If there's nothing else to diagnose, bail.
if (uncovered.isEmpty()) return;
-
+
+ auto mainDiagType = diag::non_exhaustive_switch;
+ if (TC.Context.isSwiftVersion3()) {
+ if (!sawDowngradablePattern && shouldDowngradeToWarning(uncovered)) {
+ mainDiagType = diag::non_exhaustive_switch_warn_swift3;
+ }
+ }
+
// If editing is enabled, emit a formatted error of the form:
//
// switch must be exhaustive, do you want to add missing cases?
- // case (.none, .some(_)): <#code#>
- // case (.some(_), .none): <#code#>
+ // case (.none, .some(_)):
+ // <#code#>
+ // case (.some(_), .none):
+ // <#code#>
//
// else:
//
@@ -949,31 +1000,45 @@
// missing case '(.none, .some(_))'
// missing case '(.some(_), .none)'
if (InEditor) {
- Buffer.clear();
+ buffer.clear();
+ SmallVector<Space, 8> emittedSpaces;
for (auto &uncoveredSpace : uncovered.getSpaces()) {
SmallVector<Space, 4> flats;
flatten(uncoveredSpace, flats);
for (auto &flat : flats) {
+ if (flat.isSubspace(Space(emittedSpaces), TC)) {
+ continue;
+ }
+
OS << tok::kw_case << " ";
flat.show(OS);
- OS << ":\n" << Placeholder << "\n";
+ OS << ":\n" << placeholder << "\n";
+
+ emittedSpaces.push_back(flat);
}
}
- TC.Context.Diags.diagnose(StartLoc, diag::non_exhaustive_switch);
- TC.Context.Diags.diagnose(StartLoc, diag::missing_several_cases, false)
- .fixItInsert(EndLoc, Buffer.str());
- } else {
- TC.Context.Diags.diagnose(StartLoc, diag::non_exhaustive_switch);
+ TC.diagnose(startLoc, diag::non_exhaustive_switch);
+ TC.diagnose(startLoc, diag::missing_several_cases, false)
+ .fixItInsert(endLoc, buffer.str());
+ } else {
+ TC.Context.Diags.diagnose(startLoc, mainDiagType);
+
+ SmallVector<Space, 8> emittedSpaces;
for (auto &uncoveredSpace : uncovered.getSpaces()) {
SmallVector<Space, 4> flats;
flatten(uncoveredSpace, flats);
for (auto &flat : flats) {
- Buffer.clear();
+ if (flat.isSubspace(Space(emittedSpaces), TC)) {
+ continue;
+ }
+
+ buffer.clear();
flat.show(OS);
- TC.Context.Diags.diagnose(StartLoc, diag::missing_particular_case,
- Buffer.str());
+ TC.diagnose(startLoc, diag::missing_particular_case, buffer.str());
+
+ emittedSpaces.push_back(flat);
}
}
}
@@ -993,7 +1058,7 @@
flats.push_back(space);
return;
}
-
+
// To recursively recover a pattern matrix from a bunch of disjuncts:
// 1) Unpack the arguments to the constructor under scrutiny.
// 2) Traverse each argument in turn.
@@ -1009,17 +1074,13 @@
SmallVector<Space, 4> columnVect;
flatten(subspace, columnVect);
- // Pattern matrices grow quasi-factorially in the size of the
- // input space.
- multiplier *= columnVect.size();
-
size_t startSize = matrix.size();
if (!matrix.empty() && columnVect.size() > 1) {
size_t oldCount = matrix.size();
- matrix.reserve(multiplier * oldCount);
+ matrix.reserve(oldCount * columnVect.size());
// Indexing starts at 1, we already have 'startSize'-many elements
// in the matrix; multiplies by 1 are no-ops.
- for (size_t i = 1; i < multiplier; ++i) {
+ for (size_t i = 1; i < columnVect.size(); ++i) {
std::copy_n(matrix.begin(), oldCount, std::back_inserter(matrix));
}
}
@@ -1054,11 +1115,16 @@
matrix[rowIdx].push_back(columnVect[colIdx]);
}
}
+
+ // Pattern matrices grow quasi-factorially in the size of the
+ // input space.
+ multiplier *= columnVect.size();
}
// Wrap the matrix rows into this constructor.
for (auto &row : matrix) {
- flats.push_back(Space(space.getType(), space.getHead(), row));
+ flats.push_back(Space(space.getType(), space.getHead(),
+ space.canDowngrade(), row));
}
}
break;
@@ -1077,7 +1143,8 @@
}
// Recursively project a pattern into a Space.
- static Space projectPattern(TypeChecker &TC, const Pattern *item) {
+ static Space projectPattern(TypeChecker &TC, const Pattern *item,
+ bool &sawDowngradablePattern) {
switch (item->getKind()) {
case PatternKind::Any:
case PatternKind::Named:
@@ -1109,28 +1176,39 @@
return Space();
case PatternKind::Var: {
auto *VP = cast<VarPattern>(item);
- return projectPattern(TC, VP->getSubPattern());
+ return projectPattern(TC, VP->getSubPattern(), sawDowngradablePattern);
}
case PatternKind::Paren: {
auto *PP = cast<ParenPattern>(item);
- return projectPattern(TC, PP->getSubPattern());
+ return projectPattern(TC, PP->getSubPattern(), sawDowngradablePattern);
}
case PatternKind::OptionalSome: {
auto *OSP = cast<OptionalSomePattern>(item);
SmallVector<Space, 1> payload = {
- projectPattern(TC, OSP->getSubPattern())
+ projectPattern(TC, OSP->getSubPattern(), sawDowngradablePattern)
};
- return Space(item->getType(), TC.Context.getIdentifier("some"), payload);
+ return Space(item->getType(), TC.Context.getIdentifier("some"), /*canDowngrade*/false,
+ payload);
}
case PatternKind::EnumElement: {
auto *VP = cast<EnumElementPattern>(item);
TC.validateDecl(item->getType()->getEnumOrBoundGenericEnum());
+
+ bool canDowngrade = false;
+ if (auto *eed = VP->getElementDecl()) {
+ if (eed->getAttrs().getAttribute<DowngradeExhaustivityCheckAttr>()) {
+ canDowngrade |= true;
+ sawDowngradablePattern |= true;
+ }
+ }
+
SmallVector<Space, 4> conArgSpace;
auto *SP = VP->getSubPattern();
if (!SP) {
// If there's no sub-pattern then there's no further recursive
// structure here. Yield the constructor space.
- return Space(item->getType(), VP->getName(), conArgSpace);
+ return Space(item->getType(), VP->getName(), canDowngrade,
+ conArgSpace);
}
switch (SP->getKind()) {
@@ -1139,9 +1217,11 @@
std::transform(TP->getElements().begin(), TP->getElements().end(),
std::back_inserter(conArgSpace),
[&](TuplePatternElt pate) {
- return projectPattern(TC, pate.getPattern());
+ return projectPattern(TC, pate.getPattern(),
+ sawDowngradablePattern);
});
- return Space(item->getType(), VP->getName(), conArgSpace);
+ return Space(item->getType(), VP->getName(), /*canDowngrade*/false,
+ conArgSpace);
}
case PatternKind::Paren: {
auto *PP = dyn_cast<ParenPattern>(SP);
@@ -1158,15 +1238,21 @@
conArgSpace.push_back(Space(ty.getType()));
}
} else {
- conArgSpace.push_back(projectPattern(TC, SP));
+ conArgSpace.push_back(projectPattern(TC, SP,
+ sawDowngradablePattern));
}
} else {
- conArgSpace.push_back(projectPattern(TC, SP));
+ conArgSpace.push_back(projectPattern(TC, SP,
+ sawDowngradablePattern));
}
- return Space(item->getType(), VP->getName(), conArgSpace);
+ // FIXME: This isn't *technically* correct, but we only use the
+ // downgradability of the master space, not the projected space,
+ // when reconstructing the missing pattern matrix.
+ return Space(item->getType(), VP->getName(), /*canDowngrade*/false,
+ conArgSpace);
}
default:
- return projectPattern(TC, SP);
+ return projectPattern(TC, SP, sawDowngradablePattern);
}
}
case PatternKind::Tuple: {
@@ -1175,9 +1261,10 @@
std::transform(TP->getElements().begin(), TP->getElements().end(),
std::back_inserter(conArgSpace),
[&](TuplePatternElt pate) {
- return projectPattern(TC, pate.getPattern());
+ return projectPattern(TC, pate.getPattern(), sawDowngradablePattern);
});
- return Space(item->getType(), Identifier(), conArgSpace);
+ return Space(item->getType(), Identifier(), /*canDowngrade*/false,
+ conArgSpace);
}
}
}
diff --git a/lib/Sema/TypeChecker.h b/lib/Sema/TypeChecker.h
index 79b3881..3e80f5d 100644
--- a/lib/Sema/TypeChecker.h
+++ b/lib/Sema/TypeChecker.h
@@ -224,6 +224,9 @@
/// Set if the client prefers fixits to be in the form of force unwrapping
/// or optional chaining to return an optional.
PreferForceUnwrapToOptional = 0x80,
+
+ /// If set, don't apply a solution.
+ SkipApplyingSolution = 0x100,
};
typedef OptionSet<TypeCheckExprFlags> TypeCheckExprOptions;
@@ -325,6 +328,13 @@
/// constraint system, or false otherwise.
virtual bool builtConstraints(constraints::ConstraintSystem &cs, Expr *expr);
+ /// Callback invoked once a solution has been found.
+ ///
+ /// The callback may further alter the expression, returning either a
+ /// new expression (to replace the result) or a null pointer to indicate
+ /// failure.
+ virtual Expr *foundSolution(constraints::Solution &solution, Expr *expr);
+
/// Callback invokes once the chosen solution has been applied to the
/// expression.
///
@@ -987,7 +997,7 @@
///
/// \param typeDecl The type declaration found by name lookup.
/// \param fromDC The declaration context in which the name lookup occurred.
- /// \param isSpecialized Whether this type is immediately specialized.
+ /// \param isSpecialized Whether the type will have generic arguments applied.
/// \param resolver The resolver for generic types.
///
/// \returns the resolved type.
@@ -1219,9 +1229,6 @@
handleExternalDecl(nominal);
}
- /// Introduce the accessors for a 'lazy' variable.
- void introduceLazyVarAccessors(VarDecl *var) override;
-
/// Infer default value witnesses for all requirements in the given protocol.
void inferDefaultWitnesses(ProtocolDecl *proto);
@@ -1667,9 +1674,9 @@
/// Type-check an initialized variable pattern declaration.
bool typeCheckBinding(Pattern *&P, Expr *&Init, DeclContext *DC,
- bool skipClosures);
+ bool skipApplyingSolution);
bool typeCheckPatternBinding(PatternBindingDecl *PBD, unsigned patternNumber,
- bool skipClosures);
+ bool skipApplyingSolution);
/// Type-check a for-each loop's pattern binding and sequence together.
bool typeCheckForEachBinding(DeclContext *dc, ForEachStmt *stmt);
@@ -1689,8 +1696,7 @@
static void contextualizeTopLevelCode(TopLevelContext &TLC,
ArrayRef<Decl*> topLevelDecls);
- /// Return the type-of-reference of the given value. This does not
- /// open values of polymorphic function type.
+ /// Return the type-of-reference of the given value.
///
/// \param baseType if non-null, return the type of a member reference to
/// this value when the base has the given type
@@ -1701,14 +1707,11 @@
/// \param base The optional base expression of this value reference
///
/// \param wantInterfaceType Whether we want the interface type, if available.
- Type getUnopenedTypeOfReference(ValueDecl *value, Type baseType,
+ Type getUnopenedTypeOfReference(VarDecl *value, Type baseType,
DeclContext *UseDC,
const DeclRefExpr *base = nullptr,
bool wantInterfaceType = false);
- /// Return the non-lvalue type-of-reference of the given value.
- Type getTypeOfRValue(ValueDecl *value, bool wantInterfaceType = false);
-
/// \brief Retrieve the default type for the given protocol.
///
/// Some protocols, particularly those that correspond to literals, have
@@ -2044,7 +2047,6 @@
/// the given set of declarations.
Expr *buildRefExpr(ArrayRef<ValueDecl *> Decls, DeclContext *UseDC,
DeclNameLoc NameLoc, bool Implicit,
- bool isSpecialized,
FunctionRefKind functionRefKind);
/// @}
diff --git a/stdlib/public/SDK/Foundation/NSStringAPI.swift b/stdlib/public/SDK/Foundation/NSStringAPI.swift
index 6464b71..585b6e2 100644
--- a/stdlib/public/SDK/Foundation/NSStringAPI.swift
+++ b/stdlib/public/SDK/Foundation/NSStringAPI.swift
@@ -1778,7 +1778,7 @@
fatalError("unavailable function can't be called")
}
- @available(*, unavailable, renamed: "componentsSeparated(by:)")
+ @available(*, unavailable, renamed: "components(separatedBy:)")
public func componentsSeparatedBy(_ separator: String) -> [String] {
fatalError("unavailable function can't be called")
}
diff --git a/stdlib/public/SwiftShims/LibcShims.h b/stdlib/public/SwiftShims/LibcShims.h
index 636c587..e631905 100644
--- a/stdlib/public/SwiftShims/LibcShims.h
+++ b/stdlib/public/SwiftShims/LibcShims.h
@@ -33,7 +33,7 @@
// This declaration is not universally correct. We verify its correctness for
// the current platform in the runtime code.
-#if defined(__linux__) && defined (__arm__) && !defined(__android__)
+#if defined(__linux__) && defined (__arm__) && !defined(__ANDROID__)
typedef int __swift_ssize_t;
#elif defined(_WIN32)
#if defined(_M_ARM) || defined(_M_IX86)
@@ -113,7 +113,9 @@
// TLS - thread local storage
-#if defined(__linux__)
+#if defined(__ANDROID__)
+typedef int __swift_pthread_key_t;
+#elif defined(__linux__)
typedef unsigned int __swift_pthread_key_t;
#else
typedef unsigned long __swift_pthread_key_t;
diff --git a/stdlib/public/SwiftShims/NSCharacterSetShims.h b/stdlib/public/SwiftShims/NSCharacterSetShims.h
index d7735d7..f38fbcc 100644
--- a/stdlib/public/SwiftShims/NSCharacterSetShims.h
+++ b/stdlib/public/SwiftShims/NSCharacterSetShims.h
@@ -15,27 +15,27 @@
NS_BEGIN_DECLS
NS_INLINE NS_RETURNS_RETAINED NS_NON_BRIDGED(NSCharacterSet *) _NSURLComponentsGetURLUserAllowedCharacterSet(void) {
- return NSCharacterSet.URLUserAllowedCharacterSet;
+ return NSCharacterSet.URLUserAllowedCharacterSet;
}
NS_INLINE NS_RETURNS_RETAINED NS_NON_BRIDGED(NSCharacterSet *) _NSURLComponentsGetURLPasswordAllowedCharacterSet(void) {
- return NSCharacterSet.URLPasswordAllowedCharacterSet;
+ return NSCharacterSet.URLPasswordAllowedCharacterSet;
}
NS_INLINE NS_RETURNS_RETAINED NS_NON_BRIDGED(NSCharacterSet *) _NSURLComponentsGetURLHostAllowedCharacterSet(void) {
- return NSCharacterSet.URLHostAllowedCharacterSet;
+ return NSCharacterSet.URLHostAllowedCharacterSet;
}
NS_INLINE NS_RETURNS_RETAINED NS_NON_BRIDGED(NSCharacterSet *) _NSURLComponentsGetURLPathAllowedCharacterSet(void) {
- return NSCharacterSet.URLPathAllowedCharacterSet;
+ return NSCharacterSet.URLPathAllowedCharacterSet;
}
NS_INLINE NS_RETURNS_RETAINED NS_NON_BRIDGED(NSCharacterSet *) _NSURLComponentsGetURLQueryAllowedCharacterSet(void) {
- return NSCharacterSet.URLQueryAllowedCharacterSet;
+ return NSCharacterSet.URLQueryAllowedCharacterSet;
}
NS_INLINE NS_RETURNS_RETAINED NS_NON_BRIDGED(NSCharacterSet *) _NSURLComponentsGetURLFragmentAllowedCharacterSet(void) {
- return NSCharacterSet.URLFragmentAllowedCharacterSet;
+ return NSCharacterSet.URLFragmentAllowedCharacterSet;
}
NS_END_DECLS
diff --git a/stdlib/public/core/Sequence.swift b/stdlib/public/core/Sequence.swift
index da84ba0..aa2de70 100644
--- a/stdlib/public/core/Sequence.swift
+++ b/stdlib/public/core/Sequence.swift
@@ -693,7 +693,7 @@
/// A sequence that only consumes up to `n` elements from an underlying
/// `Base` iterator.
///
-/// The underlying iterator's sequence may be infinite
+/// The underlying iterator's sequence may be infinite.
@_fixed_layout
@_versioned
internal struct _PrefixSequence<Base : IteratorProtocol>
diff --git a/stdlib/public/core/StringCharacterView.swift b/stdlib/public/core/StringCharacterView.swift
index d8d37d7..9052997 100644
--- a/stdlib/public/core/StringCharacterView.swift
+++ b/stdlib/public/core/StringCharacterView.swift
@@ -693,27 +693,18 @@
///
/// - Parameter newElements: A sequence of characters.
public mutating func append<S : Sequence>(contentsOf newElements: S)
- where S.Element == Character {
- reserveCapacity(_core.count + newElements.underestimatedCount)
- for c in newElements {
- self.append(c)
- }
- }
-
- /// Creates a new character view containing the characters in the given
- /// sequence.
- ///
- /// - Parameter characters: A sequence of characters.
- public init<S : Sequence>(_ characters: S)
where S.Element == Character {
- let v0 = characters as? _SwiftStringView
- if _fastPath(v0 != nil), let v = v0 {
- self = v._persistentContent.characters
+ if _fastPath(newElements is _SwiftStringView) {
+ let v = newElements as! _SwiftStringView
+ if _fastPath(_core.count == 0) {
+ _core = v._persistentContent._core
+ return
+ }
+ _core.append(v._ephemeralContent._core)
+ return
}
- else {
- self = String.CharacterView()
- self.append(contentsOf: characters)
- }
+ reserveCapacity(_core.count + newElements.underestimatedCount)
+ for c in newElements { self.append(c) }
}
}
diff --git a/stdlib/public/core/StringRangeReplaceableCollection.swift.gyb b/stdlib/public/core/StringRangeReplaceableCollection.swift.gyb
index 10126fc..f489634 100644
--- a/stdlib/public/core/StringRangeReplaceableCollection.swift.gyb
+++ b/stdlib/public/core/StringRangeReplaceableCollection.swift.gyb
@@ -36,16 +36,17 @@
self.init(repeating: String(repeatedValue), count: count)
}
- // FIXME(strings): doc comment
// This initializer disambiguates between the following intitializers, now
// that String conforms to Collection:
// - init<T>(_ value: T) where T : LosslessStringConvertible
// - init<S>(_ characters: S) where S : Sequence, S.Element == Character
- public init<T : StringProtocol>(_ other: T) {
- self.init(other.characters)
+ public init<S : Sequence & LosslessStringConvertible>(_ other: S)
+ where S.Element == Character {
+ self._core = CharacterView(other)._core
}
-
+
// This initializer satisfies the LosslessStringConvertible conformance
+ @available(swift, obsoleted: 4, message: "String.init(_:String) is no longer failable")
public init?(_ other: String) {
self.init(other._core)
}
diff --git a/stdlib/public/core/Substring.swift.gyb b/stdlib/public/core/Substring.swift.gyb
index ea02eb4..c0ccbe5 100644
--- a/stdlib/public/core/Substring.swift.gyb
+++ b/stdlib/public/core/Substring.swift.gyb
@@ -88,6 +88,10 @@
_slice = RangeReplaceableBidirectionalSlice()
}
+ internal init(_slice: RangeReplaceableBidirectionalSlice<String>) {
+ self._slice = _slice
+ }
+
/// Creates a substring with the specified bounds within the given string.
///
/// - Parameters:
@@ -455,53 +459,21 @@
}
}
-// The purpose of this protocol is backward compatibility with Swift 3 code,
-// where String subscripts returned String.
-// Since the Substring returning subscripts are introduced by the protocol
-// extension, they will be less specific than the String-returning ones
-// declared on the String type itself, thus avoiding ambiguity.
-public protocol _RangeSubscriptableString {
- associatedtype Index : Comparable
- func _subscript(_ bounds: Range<Index>) -> Substring
- func _subscript(_ bounds: ClosedRange<Index>) -> Substring
-}
-
-// Without the `where` subscripts will be ambiguous
-extension _RangeSubscriptableString where Self : RangeReplaceableCollection {
-% for Range in ['Range', 'ClosedRange']:
- public subscript(bounds: ${Range}<Index>) -> Substring {
- return _subscript(bounds)
- }
-% end
-}
-
-extension String : _RangeSubscriptableString {
-% for Range in ['Range', 'ClosedRange']:
- /// Accesses the text in the given range.
- ///
- /// - Complexity: O(*n*) if the underlying string is bridged from
- /// Objective-C, where *n* is the length of the string; otherwise, O(1).
- public func _subscript(_ bounds: ${Range}<Index>) -> Substring {
- return Substring(_base: String(self._core), bounds)
- }
-% end
-}
-
-extension Substring : _RangeSubscriptableString {
-% for Range in ['Range', 'ClosedRange']:
- public func _subscript(_ bounds: ${Range}<Index>) -> Substring {
- let subSlice = _slice[bounds]
- let bounds = (lower: subSlice.startIndex, upper: subSlice.endIndex)
-% if Range == 'ClosedRange':
- // Creating Substring using the half-open range, since subSlice already
- // handled the ClosedRange case.
-% end
- return Substring(_base: _slice._base, Range(uncheckedBounds: bounds))
- }
-% end
-}
-
+//===--- String/Substring Slicing Support ---------------------------------===//
+/// In Swift 3.2, in the absence of type context,
+///
+/// someString[someString.startIndex..<someString.endIndex]
+///
+/// was deduced to be of type `String`. Therefore have a more-specific
+/// Swift-3-only `subscript` overload on `String` (and `Substring`) that
+/// continues to produce `String`.
extension String {
+ @available(swift, introduced: 4)
+ public subscript(r: Range<Index>) -> Substring {
+ return Substring(
+ _slice: RangeReplaceableBidirectionalSlice(base: self, bounds: r))
+ }
+
@available(swift, obsoleted: 4)
public subscript(bounds: Range<Index>) -> String {
return String(characters[bounds])
@@ -514,6 +486,11 @@
}
extension Substring {
+ @available(swift, introduced: 4)
+ public subscript(r: Range<Index>) -> Substring {
+ return Substring(_slice: _slice[r])
+ }
+
@available(swift, obsoleted: 4)
public subscript(bounds: Range<Index>) -> String {
return String(characters[bounds])
@@ -524,3 +501,4 @@
return String(characters[bounds])
}
}
+//===----------------------------------------------------------------------===//
diff --git a/stdlib/public/core/ThreadLocalStorage.swift b/stdlib/public/core/ThreadLocalStorage.swift
index 32278da..cb213d5 100644
--- a/stdlib/public/core/ThreadLocalStorage.swift
+++ b/stdlib/public/core/ThreadLocalStorage.swift
@@ -1,3 +1,15 @@
+//===--- ThreadLocalStorage.swift -----------------------------------------===//
+//
+// This source file is part of the Swift.org open source project
+//
+// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
+// Licensed under Apache License v2.0 with Runtime Library Exception
+//
+// See https://swift.org/LICENSE.txt for license information
+// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
+//
+//===----------------------------------------------------------------------===//
+
import SwiftShims
// For testing purposes, a thread-safe counter to guarantee that destructors get
diff --git a/test/Constraints/array_literal.swift b/test/Constraints/array_literal.swift
index 4761468..91c624b 100644
--- a/test/Constraints/array_literal.swift
+++ b/test/Constraints/array_literal.swift
@@ -129,7 +129,7 @@
let a2: Array = [1, "a", 3.5]
// expected-error@-1{{heterogeneous collection literal could only be inferred to '[Any]'; add explicit type annotation if this is intentional}}
- let _: Int = a2 // expected-error{{value of type '[Any]'}}
+ let _: Int = a2 // expected-error{{value of type 'Array<Any>'}}
let a3 = [1, "a", nil, 3.5]
// expected-error@-1{{heterogeneous collection literal could only be inferred to '[Any?]'; add explicit type annotation if this is intentional}}
@@ -137,7 +137,7 @@
let a4: Array = [1, "a", nil, 3.5]
// expected-error@-1{{heterogeneous collection literal could only be inferred to '[Any?]'; add explicit type annotation if this is intentional}}
- let _: Int = a4 // expected-error{{value of type '[Any?]'}}
+ let _: Int = a4 // expected-error{{value of type 'Array<Any?>'}}
let a5 = []
// expected-error@-1{{empty collection literal requires an explicit type}}
diff --git a/test/Demangle/Inputs/manglings.txt b/test/Demangle/Inputs/manglings.txt
index ce5d0fd..600ac53 100644
--- a/test/Demangle/Inputs/manglings.txt
+++ b/test/Demangle/Inputs/manglings.txt
@@ -258,4 +258,5 @@
_T0Tk ---> _T0Tk
_T0A8 ---> _T0A8
_T0s30ReversedRandomAccessCollectionVyxGTfq3nnpf_nTfq1cn_nTfq4x_n ---> _T0s30ReversedRandomAccessCollectionVyxGTfq3nnpf_nTfq1cn_nTfq4x_n
+_T03abc6testitySiFTm ---> merged abc.testit(Swift.Int) -> ()
diff --git a/test/Demangle/Inputs/simplified-manglings.txt b/test/Demangle/Inputs/simplified-manglings.txt
index e537834..98399f6 100644
--- a/test/Demangle/Inputs/simplified-manglings.txt
+++ b/test/Demangle/Inputs/simplified-manglings.txt
@@ -203,3 +203,5 @@
_TTRXFo_oCSo13SKPhysicsBodydVSC7CGPointdVSC8CGVectordGSpV10ObjectiveC8ObjCBool___XFdCb_dS_dS0_dS1_dGSpS3____ ---> thunk for @callee_owned (@owned SKPhysicsBody, @unowned CGPoint, @unowned CGVector, @unowned UnsafeMutablePointer<ObjCBool>) -> ()
_T0So13SKPhysicsBodyCSC7CGPointVSC8CGVectorVSpy10ObjectiveC8ObjCBoolVGIxxyyy_AbdFSpyAIGIyByyyy_TR ---> thunk for @callee_owned (@owned SKPhysicsBody, @unowned CGPoint, @unowned CGVector, @unowned UnsafeMutablePointer<ObjCBool>) -> ()
_T04main1_yyF ---> _()
+_T03abc6testitySiFTm ---> testit(_:)
+
diff --git a/test/IDE/print_types.swift b/test/IDE/print_types.swift
index dba1c03..9b61ea5 100644
--- a/test/IDE/print_types.swift
+++ b/test/IDE/print_types.swift
@@ -57,14 +57,14 @@
_ = typealias1 ; typealias1 = 1
var optional1 = Optional<Int>.none
-// CHECK: VarDecl '''optional1''' Optional<Int>{{$}}
-// FULL: VarDecl '''optional1''' Swift.Optional<Swift.Int>{{$}}
+// CHECK: VarDecl '''optional1''' Int?{{$}}
+// FULL: VarDecl '''optional1''' Swift.Int?{{$}}
_ = optional1 ; optional1 = nil
var optional2 = Optional<[Int]>.none
_ = optional2 ; optional2 = nil
-// CHECK: VarDecl '''optional2''' Optional<[Int]>{{$}}
-// FULL: VarDecl '''optional2''' Swift.Optional<[Swift.Int]>{{$}}
+// CHECK: VarDecl '''optional2''' [Int]?{{$}}
+// FULL: VarDecl '''optional2''' [Swift.Int]?{{$}}
}
func testFuncType1() {}
diff --git a/test/Interpreter/repl.swift b/test/Interpreter/repl.swift
index 6f82de3..77654f0 100644
--- a/test/Interpreter/repl.swift
+++ b/test/Interpreter/repl.swift
@@ -148,7 +148,7 @@
// CHECK-NEXT: r
var vec = Array<String>()
-// CHECK: vec : Array<String> = []
+// CHECK: vec : [String] = []
// Error recovery
var a : [int]
diff --git a/test/LLVMPasses/merge_func.ll b/test/LLVMPasses/merge_func.ll
index 64f4485..7a9be33 100644
--- a/test/LLVMPasses/merge_func.ll
+++ b/test/LLVMPasses/merge_func.ll
@@ -9,7 +9,7 @@
; Test the most trivial example.
; CHECK-LABEL: define i32 @simple_func1(i32 %x, i32 %y)
-; CHECK: %1 = tail call i32 @simple_func1_merged(i32 %x, i32 %y, i32* @g1)
+; CHECK: %1 = tail call i32 @simple_func1Tm(i32 %x, i32 %y, i32* @g1)
; CHECK: ret i32 %1
define i32 @simple_func1(i32 %x, i32 %y) {
%sum = add i32 %x, %y
@@ -20,7 +20,7 @@
}
; CHECK-LABEL: define i32 @simple_func2(i32 %x, i32 %y)
-; CHECK: %1 = tail call i32 @simple_func1_merged(i32 %x, i32 %y, i32* @g2)
+; CHECK: %1 = tail call i32 @simple_func1Tm(i32 %x, i32 %y, i32* @g2)
; CHECK: ret i32 %1
define i32 @simple_func2(i32 %x, i32 %y) {
%sum = add i32 %x, %y
@@ -30,7 +30,7 @@
ret i32 %sum3
}
-; CHECK-LABEL: define internal i32 @simple_func1_merged(i32, i32, i32*)
+; CHECK-LABEL: define internal i32 @simple_func1Tm(i32, i32, i32*)
; CHECK: %l = load i32, i32* %2
; CHECK: ret
@@ -38,7 +38,7 @@
; Merge 3 functions with 3 types of differing instructions: load, store and call.
; CHECK-LABEL: define i32 @func1_of_3(i32 %x)
-; CHECK: %1 = tail call i32 @func1_of_3_merged(i32 %x, i32* @g1, i32* @g1, void (i32)* @callee1)
+; CHECK: %1 = tail call i32 @func1_of_3Tm(i32 %x, i32* @g1, i32* @g1, void (i32)* @callee1)
; CHECK: ret i32 %1
define i32 @func1_of_3(i32 %x) {
%l1 = load i32, i32* @g1, align 4
@@ -52,7 +52,7 @@
}
; CHECK-LABEL: define i32 @func2_of_3(i32 %x)
-; CHECK: %1 = tail call i32 @func1_of_3_merged(i32 %x, i32* @g2, i32* @g2, void (i32)* @callee2)
+; CHECK: %1 = tail call i32 @func1_of_3Tm(i32 %x, i32* @g2, i32* @g2, void (i32)* @callee2)
; CHECK: ret i32 %1
define i32 @func2_of_3(i32 %x) {
%l1 = load i32, i32* @g2, align 4
@@ -66,7 +66,7 @@
}
; CHECK-LABEL: define i32 @func3_of_3(i32 %x)
-; CHECK: %1 = tail call i32 @func1_of_3_merged(i32 %x, i32* @g3, i32* @g1, void (i32)* @callee3)
+; CHECK: %1 = tail call i32 @func1_of_3Tm(i32 %x, i32* @g3, i32* @g1, void (i32)* @callee3)
; CHECK: ret i32 %1
define i32 @func3_of_3(i32 %x) {
%l1 = load i32, i32* @g3, align 4
@@ -79,7 +79,7 @@
ret i32 %sum3
}
-; CHECK-LABEL: define internal i32 @func1_of_3_merged(i32, i32*, i32*, void (i32)*)
+; CHECK-LABEL: define internal i32 @func1_of_3Tm(i32, i32*, i32*, void (i32)*)
; CHECK: %l1 = load i32, i32* %1
; CHECK: %l2 = load i32, i32* %2
; CHECK: store i32 %sum2, i32* %1
@@ -93,7 +93,7 @@
; Preserve attributes
; CHECK-LABEL: define void @sret_func1(i32* sret %p, i32 %x, i32 %y)
-; CHECK: tail call void @sret_func1_merged(i32* sret %p, i32 %x, i32 %y, i32* @g1)
+; CHECK: tail call void @sret_func1Tm(i32* sret %p, i32 %x, i32 %y, i32* @g1)
; CHECK: ret void
define void @sret_func1(i32* sret %p, i32 %x, i32 %y) {
%sum = add i32 %x, %y
@@ -104,7 +104,7 @@
}
; CHECK-LABEL: define void @sret_func2(i32* sret %p, i32 %x, i32 %y)
-; CHECK: tail call void @sret_func1_merged(i32* sret %p, i32 %x, i32 %y, i32* @g2)
+; CHECK: tail call void @sret_func1Tm(i32* sret %p, i32 %x, i32 %y, i32* @g2)
; CHECK: ret void
define void @sret_func2(i32* sret %p, i32 %x, i32 %y) {
%sum = add i32 %x, %y
@@ -114,7 +114,7 @@
ret void
}
-; CHECK-LABEL: define internal void @sret_func1_merged(i32* sret, i32, i32, i32*)
+; CHECK-LABEL: define internal void @sret_func1Tm(i32* sret, i32, i32, i32*)
; CHECK: %l = load i32, i32* %3, align 4
; CHECK: store i32 %sum2, i32* %0
; CHECK: ret
@@ -124,7 +124,7 @@
; Instead merge those functions which match best.
; CHECK-LABEL: define i32 @func1_merged_with3(i32 %x)
-; CHECK: %1 = tail call i32 @func1_merged_with3_merged(i32 %x, i32* @g1)
+; CHECK: %1 = tail call i32 @func1_merged_with3Tm(i32 %x, i32* @g1)
; CHECK: ret i32 %1
define i32 @func1_merged_with3(i32 %x) {
%l1 = load i32, i32* @g1, align 4
@@ -141,7 +141,7 @@
}
; CHECK-LABEL: define i32 @func2_merged_with4(i32 %x)
-; CHECK: %1 = tail call i32 @func2_merged_with4_merged(i32 %x, i32* @g2)
+; CHECK: %1 = tail call i32 @func2_merged_with4Tm(i32 %x, i32* @g2)
; CHECK: ret i32 %1
define i32 @func2_merged_with4(i32 %x) {
%l1 = load i32, i32* @g2, align 4
@@ -158,7 +158,7 @@
}
; CHECK-LABEL: define i32 @func3_merged_with1(i32 %x)
-; CHECK: %1 = tail call i32 @func1_merged_with3_merged(i32 %x, i32* @g2)
+; CHECK: %1 = tail call i32 @func1_merged_with3Tm(i32 %x, i32* @g2)
; CHECK: ret i32 %1
define i32 @func3_merged_with1(i32 %x) {
%l1 = load i32, i32* @g2, align 4
@@ -174,7 +174,7 @@
ret i32 %sum5
}
-; CHECK-LABEL: define internal i32 @func1_merged_with3_merged(i32, i32*)
+; CHECK-LABEL: define internal i32 @func1_merged_with3Tm(i32, i32*)
; CHECK: load i32, i32* %1, align 4
; CHECK: load i32, i32* @g2, align 4
; CHECK: load i32, i32* @g3, align 4
@@ -183,7 +183,7 @@
; CHECK: ret i32
; CHECK-LABEL: define i32 @func4_merged_with2(i32 %x) {
-; CHECK: %1 = tail call i32 @func2_merged_with4_merged(i32 %x, i32* @g1)
+; CHECK: %1 = tail call i32 @func2_merged_with4Tm(i32 %x, i32* @g1)
; CHECK: ret i32 %1
define i32 @func4_merged_with2(i32 %x) {
%l1 = load i32, i32* @g1, align 4
@@ -205,7 +205,7 @@
; Also check that the calling convention is preserved.
; CHECK-LABEL: define fastcc i32 @callee1_a(i32 %x, i32 %y)
-; CHECK: %1 = tail call fastcc i32 @callee1_a_merged(i32 %x, i32 %y, i32* @g1)
+; CHECK: %1 = tail call fastcc i32 @callee1_aTm(i32 %x, i32 %y, i32* @g1)
; CHECK: ret i32 %1
define fastcc i32 @callee1_a(i32 %x, i32 %y) {
%sum = add i32 %x, %y
@@ -216,7 +216,7 @@
}
; CHECK-LABEL: define fastcc i32 @callee1_b(i32 %x, i32 %y)
-; CHECK: %1 = tail call fastcc i32 @callee1_a_merged(i32 %x, i32 %y, i32* @g2)
+; CHECK: %1 = tail call fastcc i32 @callee1_aTm(i32 %x, i32 %y, i32* @g2)
; CHECK: ret i32 %1
define fastcc i32 @callee1_b(i32 %x, i32 %y) {
%sum = add i32 %x, %y
@@ -226,8 +226,8 @@
ret i32 %sum3
}
-; CHECK-LABEL: define internal fastcc i32 @callee1_a_merged(i32, i32, i32*)
-; CHECK: call i32 @callee2_a_merged(i32 %sum2, i32 %1, i32* %2)
+; CHECK-LABEL: define internal fastcc i32 @callee1_aTm(i32, i32, i32*)
+; CHECK: call i32 @callee2_aTm(i32 %sum2, i32 %1, i32* %2)
; CHECK: ret
; CHECK-NOT: @callee2_a(
@@ -249,7 +249,7 @@
}
; CHECK-LABEL: define i32 @caller_a(i32 %x, i32 %y)
-; CHECK: %1 = tail call i32 @caller_a_merged(i32 %x, i32 %y, i32* @g1)
+; CHECK: %1 = tail call i32 @caller_aTm(i32 %x, i32 %y, i32* @g1)
; CHECK: ret i32 %1
define i32 @caller_a(i32 %x, i32 %y) {
%sum = add i32 %x, %y
@@ -260,7 +260,7 @@
}
; CHECK-LABEL: define i32 @caller_b(i32 %x, i32 %y)
-; CHECK: %1 = tail call i32 @caller_a_merged(i32 %x, i32 %y, i32* @g2)
+; CHECK: %1 = tail call i32 @caller_aTm(i32 %x, i32 %y, i32* @g2)
; CHECK: ret i32 %1
define i32 @caller_b(i32 %x, i32 %y) {
%sum = add i32 %x, %y
@@ -270,8 +270,8 @@
ret i32 %sum3
}
-; CHECK-LABEL: define internal i32 @caller_a_merged(i32, i32, i32*)
-; CHECK: call fastcc i32 @callee1_a_merged(i32 %sum2, i32 %1, i32* %2)
+; CHECK-LABEL: define internal i32 @caller_aTm(i32, i32, i32*)
+; CHECK: call fastcc i32 @callee1_aTm(i32 %sum2, i32 %1, i32* %2)
; CHECK: ret
@@ -327,7 +327,7 @@
; Check self recursive functions
; CHECK-LABEL: define internal void @recursive1(i32 %x, i32 %y)
-; CHECK: tail call void @recursive1_merged(i32 %x, i32 %y, i32* @g1, void (i32, i32)* @recursive1)
+; CHECK: tail call void @recursive1Tm(i32 %x, i32 %y, i32* @g1, void (i32, i32)* @recursive1)
; CHECK: ret void
define internal void @recursive1(i32 %x, i32 %y) {
br i1 undef, label %bb1, label %bb2
@@ -342,7 +342,7 @@
}
; CHECK-LABEL: define internal void @recursive2(i32 %x, i32 %y)
-; CHECK: tail call void @recursive1_merged(i32 %x, i32 %y, i32* @g2, void (i32, i32)* @recursive2)
+; CHECK: tail call void @recursive1Tm(i32 %x, i32 %y, i32* @g2, void (i32, i32)* @recursive2)
; CHECK: ret void
define internal void @recursive2(i32 %x, i32 %y) {
br i1 undef, label %bb1, label %bb2
@@ -355,14 +355,14 @@
bb2:
ret void
}
-; CHECK-LABEL: define internal void @recursive1_merged(i32, i32, i32*, void (i32, i32)*)
+; CHECK-LABEL: define internal void @recursive1Tm(i32, i32, i32*, void (i32, i32)*)
; CHECK: load i32, i32* %2
; CHECK: call void %3(i32 %0, i32 %1)
; CHECK: ret void
; CHECK-LABEL: define internal void @another_recursive_func(i32 %x)
-; CHECK: tail call void @another_recursive_func_merged(i32 %x, i32* @g1, void (i32)* @another_recursive_func)
+; CHECK: tail call void @another_recursive_funcTm(i32 %x, i32* @g1, void (i32)* @another_recursive_func)
; CHECK: ret void
define internal void @another_recursive_func(i32 %x) {
br i1 undef, label %bb1, label %bb2
@@ -377,7 +377,7 @@
}
; CHECK-NOT: @not_really_recursive(
-; CHECK-LABEL: define internal void @another_recursive_func_merged(i32, i32*, void (i32)*)
+; CHECK-LABEL: define internal void @another_recursive_funcTm(i32, i32*, void (i32)*)
; CHECK: store i32 %0, i32* %1
; CHECK: call void %2(i32 %0)
; CHECK: ret void
@@ -398,7 +398,7 @@
; CHECK: call void @recursive1(i32 %x, i32 %x)
; CHECK: call void @recursive2(i32 %x, i32 %x)
; CHECK: call void @another_recursive_func(i32 %x)
-; CHECK: call void @another_recursive_func_merged(i32 %x, i32* @g2, void (i32)* @callee1)
+; CHECK: call void @another_recursive_funcTm(i32 %x, i32* @g2, void (i32)* @callee1)
; CHECK: ret void
define void @call_recursive_funcs(i32 %x) {
call void @recursive1(i32 %x, i32 %x)
diff --git a/test/LLVMPasses/merge_func_coff.ll b/test/LLVMPasses/merge_func_coff.ll
index df8f60d..67c12f5 100644
--- a/test/LLVMPasses/merge_func_coff.ll
+++ b/test/LLVMPasses/merge_func_coff.ll
@@ -18,6 +18,6 @@
ret i32 %sum3
}
-; CHECK-NOT: define internal dllexport i32 @f_merged(i32, i32)
-; CHECK-LABEL: define internal i32 @f_merged(i32, i32)
+; CHECK-NOT: define internal dllexport i32 @fTm(i32, i32)
+; CHECK-LABEL: define internal i32 @fTm(i32, i32)
diff --git a/test/Migrator/no_var_to_let.swift b/test/Migrator/no_var_to_let.swift
new file mode 100644
index 0000000..796702f
--- /dev/null
+++ b/test/Migrator/no_var_to_let.swift
@@ -0,0 +1,14 @@
+// RUN: %target-swift-frontend -typecheck %s -swift-version 3
+// RUN: rm -rf %t && mkdir -p %t && %target-swift-frontend -c -update-code -primary-file %s -emit-migrated-file-path %t/no_var_to_let.swift.result -swift-version 3 -o /dev/null
+// RUN: diff -u %s %t/no_var_to_let.swift.result
+// RUN: %target-swift-frontend -typecheck %s -swift-version 4
+
+// Note that the diff run line indicates that there should be no change.
+
+// The compiler should not suggest `let` instead of `var` here because
+// it is a compile error to say `for let ...`.
+// rdar://problem/32390726
+
+for var i in 0..<10 {
+ _ = i + 1
+}
diff --git a/test/NameBinding/name_lookup.swift b/test/NameBinding/name_lookup.swift
index 416ca70..b8b0aef 100644
--- a/test/NameBinding/name_lookup.swift
+++ b/test/NameBinding/name_lookup.swift
@@ -528,7 +528,7 @@
// <rdar://problem/16954496> lazy properties must use "self." in their body, and can weirdly refer to class variables directly
class r16954496 {
func bar() {}
- lazy var x: Array<(r16954496) -> () -> Void> = [bar]
+ lazy var x: Array<() -> Void> = [bar]
}
diff --git a/test/NameBinding/scope_map.swift b/test/NameBinding/scope_map.swift
index 4067a15..ba3fc5c 100644
--- a/test/NameBinding/scope_map.swift
+++ b/test/NameBinding/scope_map.swift
@@ -460,8 +460,7 @@
// CHECK-SEARCHES-NEXT: ClassDecl name=LazyProperties
// CHECK-SEARCHES-NEXT: Initializer PatternBinding {{.*}} #0
-// FIXME: Re-enable the binding below
-// CHECK-SEARCHES-NOT: Local bindings: self
+// CHECK-SEARCHES-NEXT: Local bindings: self
// CHECK-SEARCHES-LABEL: ***Complete scope map***
// CHECK-SEARCHES-NEXT: SourceFile {{.*}} '{{.*}}scope_map.swift' [1:1 - [[EOF:[0-9]+:[0-9]+]]] unexpanded
diff --git a/test/SILGen/downgrade_exhaustivity_swift3.swift b/test/SILGen/downgrade_exhaustivity_swift3.swift
new file mode 100644
index 0000000..f0be6c1
--- /dev/null
+++ b/test/SILGen/downgrade_exhaustivity_swift3.swift
@@ -0,0 +1,48 @@
+// RUN: %target-swift-frontend -swift-version 3 -emit-silgen %s | %FileCheck %s
+
+enum Downgradable {
+ case spoon
+ case hat
+ @_downgrade_exhaustivity_check
+ case fork
+}
+
+// CHECK-LABEL: sil hidden @_T029downgrade_exhaustivity_swift343testDowngradableOmittedPatternIsUnreachableyAA0E0OSg3pat_tF
+func testDowngradableOmittedPatternIsUnreachable(pat : Downgradable?) {
+ // CHECK: switch_enum {{%.*}} : $Downgradable, case #Downgradable.spoon!enumelt: [[CASE1:bb[0-9]+]], case #Downgradable.hat!enumelt: [[CASE2:bb[0-9]+]], default [[DEFAULT_CASE:bb[0-9]+]]
+ switch pat! {
+ // CHECK: [[CASE1]]:
+ case .spoon:
+ break
+ // CHECK: [[CASE2]]:
+ case .hat:
+ break
+ // CHECK: [[DEFAULT_CASE]]:
+ // CHECK-NEXT: unreachable
+ }
+
+ // CHECK: switch_enum {{%[0-9]+}} : $Downgradable, case #Downgradable.spoon!enumelt: {{bb[0-9]+}}, case #Downgradable.hat!enumelt: {{bb[0-9]+}}, default [[TUPLE_DEFAULT_CASE_1:bb[0-9]+]]
+ // CHECK: switch_enum [[Y:%[0-9]+]] : $Downgradable, case #Downgradable.spoon!enumelt: {{bb[0-9]+}}, case #Downgradable.hat!enumelt: {{bb[0-9]+}}, default [[TUPLE_DEFAULT_CASE_2:bb[0-9]+]]
+ switch (pat!, pat!) {
+ case (.spoon, .spoon):
+ break
+ case (.spoon, .hat):
+ break
+ case (.hat, .spoon):
+ break
+ case (.hat, .hat):
+ break
+ // CHECK: [[TUPLE_DEFAULT_CASE_2]]:
+ // CHECK-NEXT: unreachable
+
+ // CHECK: switch_enum [[Y]] : $Downgradable, case #Downgradable.spoon!enumelt: {{bb[0-9]+}}, case #Downgradable.hat!enumelt: {{bb[0-9]+}}, default [[TUPLE_DEFAULT_CASE_3:bb[0-9]+]]
+
+ // CHECK: [[TUPLE_DEFAULT_CASE_3]]:
+ // CHECK-NEXT: unreachable
+
+ // CHECK: [[TUPLE_DEFAULT_CASE_1]]:
+ // CHECK-NEXT: unreachable
+ }
+
+}
+
diff --git a/test/SILOptimizer/constant_propagation.sil b/test/SILOptimizer/constant_propagation.sil
index 90d483a..48e9e17 100644
--- a/test/SILOptimizer/constant_propagation.sil
+++ b/test/SILOptimizer/constant_propagation.sil
@@ -1,6 +1,7 @@
// RUN: %target-sil-opt -assume-parsing-unqualified-ownership-sil -enable-sil-verify-all %s -diagnostic-constant-propagation | %FileCheck %s
// RUN: %target-sil-opt -assume-parsing-unqualified-ownership-sil -enable-sil-verify-all %s -performance-constant-propagation | %FileCheck %s
+import Swift
import Builtin
struct UInt {
@@ -692,3 +693,254 @@
dealloc_stack %31 : $*AnObject
br bb1
}
+
+public protocol P {
+}
+
+public protocol PP {
+}
+
+struct X : P {
+}
+
+struct Y<T>: P {
+ var x : T
+}
+
+class Z: P {
+ init()
+}
+
+// Do not optimize casts to unrelated protocols.
+// CHECK-LABEL: sil @dont_replace_unconditional_check_cast_addr_for_type_to_unrelated_existential
+// CHECK: unconditional_checked_cast_addr
+// CHECK: end sil function 'dont_replace_unconditional_check_cast_addr_for_type_to_unrelated_existential'
+sil @dont_replace_unconditional_check_cast_addr_for_type_to_unrelated_existential : $@convention(thin) (@in X) -> (@out PP) {
+bb0(%0 : $*PP, %1 : $*X):
+ unconditional_checked_cast_addr take_always X in %1 : $*X to PP in %0 : $*PP
+ %2 = tuple ()
+ return %2 : $()
+}
+
+// Do not optimize casts between existentials.
+// CHECK-LABEL: sil @dont_replace_unconditional_check_cast_addr_for_existential_to_existential
+// CHECK: unconditional_checked_cast_addr
+// CHECK: end sil function 'dont_replace_unconditional_check_cast_addr_for_existential_to_existential'
+sil @dont_replace_unconditional_check_cast_addr_for_existential_to_existential : $@convention(thin) (@in PP) -> (@out P) {
+bb0(%0 : $*P, %1 : $*PP):
+ unconditional_checked_cast_addr take_always PP in %1 : $*PP to P in %0 : $*P
+ %2 = tuple ()
+ return %2 : $()
+}
+
+// Check that an unconditional_checked_cast_addr from a non-existential loadable type to a protocol
+// can be replaced by a more efficient code sequence if it is statitcally known that this
+// type conforms to this protocol.
+// CHECK-LABEL: sil @replace_unconditional_check_cast_addr_for_type_to_existential
+// CHECK-NOT: unconditional_checked_cast_addr
+// CHECK: init_existential
+// CHECK-NOT: store
+// CHECK: copy_addr
+// CHECK-NOT: destroy_addr
+// CHECK-NOT: unconditional_checked_cast_addr
+sil @replace_unconditional_check_cast_addr_for_type_to_existential : $@convention(thin) (@in X) -> (@out P) {
+bb0(%0 : $*P, %1 : $*X):
+ unconditional_checked_cast_addr take_always X in %1 : $*X to P in %0 : $*P
+ %2 = tuple ()
+ return %2 : $()
+}
+
+// CHECK-LABEL: sil @replace_unconditional_check_cast_addr_for_class_to_existential
+// CHECK-NOT: unconditional_checked_cast_addr
+// CHECK: init_existential_addr
+// CHECK-NOT: unconditional_checked_cast_addr
+sil @replace_unconditional_check_cast_addr_for_class_to_existential : $@convention(thin) (@in Z) -> (@out P) {
+bb0(%0 : $*P, %1 : $*Z):
+ unconditional_checked_cast_addr take_always Z in %1 : $*Z to P in %0 : $*P
+ %2 = tuple ()
+ return %2 : $()
+}
+
+// CHECK-LABEL: sil @replace_unconditional_check_cast_addr_for_archetype_to_existential
+// CHECK-NOT: unconditional_checked_cast_addr
+// CHECK: init_existential_addr
+// CHECK-NOT: unconditional_checked_cast_addr
+sil @replace_unconditional_check_cast_addr_for_archetype_to_existential : $@convention(thin) <X:P> (@in X) -> (@out P) {
+bb0(%0 : $*P, %1 : $*X):
+ unconditional_checked_cast_addr take_always X in %1 : $*X to P in %0 : $*P
+ %2 = tuple ()
+ return %2 : $()
+}
+
+// CHECK-LABEL: sil @replace_unconditional_check_cast_addr_for_generic_type_to_existential
+// CHECK-NOT: unconditional_checked_cast_addr
+// CHECK: init_existential_addr
+// CHECK-NOT: unconditional_checked_cast_addr
+sil @replace_unconditional_check_cast_addr_for_generic_type_to_existential : $@convention(thin) <X:P> (@in Y<X>) -> (@out P) {
+bb0(%0 : $*P, %1 : $*Y<X>):
+ unconditional_checked_cast_addr take_always Y<X> in %1 : $*Y<X> to P in %0 : $*P
+ %2 = tuple ()
+ return %2 : $()
+}
+
+protocol Q : class {
+}
+
+class V : Q {
+ init()
+}
+
+class W<T>: Q {
+ var x : T
+ init()
+}
+
+// CHECK-LABEL: sil @replace_unconditional_check_cast_addr_for_type_to_class_existential
+// CHECK-NOT: unconditional_checked_cast_addr
+// CHECK-NOT: retain_value
+// CHECK: init_existential_ref
+// CHECK-NOT: retain_value
+// CHECK-NOT: unconditional_checked_cast_addr
+// CHECK: return
+sil @replace_unconditional_check_cast_addr_for_type_to_class_existential : $@convention(thin) (@in V) -> (@out Q) {
+bb0(%0 : $*Q, %1 : $*V):
+ unconditional_checked_cast_addr take_always V in %1 : $*V to Q in %0 : $*Q
+ %2 = tuple ()
+ return %2 : $()
+}
+
+// CHECK-LABEL: sil @replace_unconditional_check_cast_addr_for_type_to_class_existential_copy_on_success
+// CHECK-NOT: unconditional_checked_cast_addr
+// CHECK: retain_value
+// CHECK: init_existential_ref
+// CHECK-NOT: retain_value
+// CHECK-NOT: unconditional_checked_cast_addr
+// CHECK: return
+sil @replace_unconditional_check_cast_addr_for_type_to_class_existential_copy_on_success : $@convention(thin) (@in V) -> (@out Q) {
+bb0(%0 : $*Q, %1 : $*V):
+ unconditional_checked_cast_addr copy_on_success V in %1 : $*V to Q in %0 : $*Q
+ %2 = tuple ()
+ return %2 : $()
+}
+
+// CHECK-LABEL: sil @replace_unconditional_check_cast_addr_for_archetype_to_class_existential
+// CHECK-NOT: unconditional_checked_cast_addr
+// CHECK-NOT: retain_value
+// CHECK: init_existential_ref
+// CHECK-NOT: retain_value
+// CHECK-NOT: unconditional_checked_cast_addr
+// CHECK: return
+sil @replace_unconditional_check_cast_addr_for_archetype_to_class_existential : $@convention(thin) <X:Q> (@in X) -> (@out Q) {
+bb0(%0 : $*Q, %1 : $*X):
+ unconditional_checked_cast_addr take_always X in %1 : $*X to Q in %0 : $*Q
+ %2 = tuple ()
+ return %2 : $()
+}
+
+// CHECK-LABEL: sil @replace_unconditional_check_cast_addr_to_class_existential
+// CHECK-NOT: unconditional_checked_cast_addr
+// CHECK-NOT: retain_value
+// CHECK: init_existential_ref
+// CHECK-NOT: retain_value
+// CHECK-NOT: unconditional_checked_cast_addr
+// CHECK: return
+sil @replace_unconditional_check_cast_addr_to_class_existential : $@convention(thin) <X:Q> (@in W<X>) -> (@out Q) {
+bb0(%0 : $*Q, %1 : $*W<X>):
+ unconditional_checked_cast_addr take_always W<X> in %1 : $*W<X> to Q in %0 : $*Q
+ %2 = tuple ()
+ return %2 : $()
+}
+
+public protocol MyError : Error {
+}
+
+public class E1 : MyError {
+ init()
+}
+
+public class E2<T> : MyError {
+ init()
+}
+
+// CHECK-LABEL: sil @replace_unconditional_check_cast_addr_for_type_to_myerror_existential
+// CHECK-NOT: unconditional_checked_cast_addr
+// CHECK: init_existential_addr
+// CHECK-NOT: unconditional_checked_cast_addr
+// CHECK: return
+sil @replace_unconditional_check_cast_addr_for_type_to_myerror_existential : $@convention(thin) (@in E1) -> (@out MyError) {
+bb0(%0 : $*MyError, %1 : $*E1):
+ unconditional_checked_cast_addr take_always E1 in %1 : $*E1 to MyError in %0 : $*MyError
+ %2 = tuple ()
+ return %2 : $()
+}
+
+// CHECK-LABEL: sil @replace_unconditional_check_cast_addr_for_type_to_myerror_existential_copy_on_success
+// CHECK-NOT: unconditional_checked_cast_addr
+// CHECK: init_existential_addr
+// There should be no [take] in copy_addr!
+// CHECK: copy_addr %{{.}} to [initialization]
+// CHECK-NOT: unconditional_checked_cast_addr
+// CHECK: return
+sil @replace_unconditional_check_cast_addr_for_type_to_myerror_existential_copy_on_success : $@convention(thin) (@in E1) -> (@out MyError) {
+bb0(%0 : $*MyError, %1 : $*E1):
+ unconditional_checked_cast_addr copy_on_success E1 in %1 : $*E1 to MyError in %0 : $*MyError
+ %2 = tuple ()
+ return %2 : $()
+}
+
+// CHECK-LABEL: sil @replace_unconditional_check_cast_addr_for_archetype_to_myerror_existentia
+// CHECK-NOT: unconditional_checked_cast_addr
+// CHECK: init_existential_addr
+// CHECK-NOT: unconditional_checked_cast_addr
+// CHECK: return
+sil @replace_unconditional_check_cast_addr_for_archetype_to_myerror_existential : $@convention(thin) <X:MyError> (@in X) -> (@out MyError) {
+bb0(%0 : $*MyError, %1 : $*X):
+ unconditional_checked_cast_addr take_always X in %1 : $*X to MyError in %0 : $*MyError
+ %2 = tuple ()
+ return %2 : $()
+}
+
+// CHECK-LABEL: sil @replace_unconditional_check_cast_addr_to_myerror_existential
+// CHECK-NOT: unconditional_checked_cast_addr
+// CHECK: init_existential_addr
+// CHECK-NOT: unconditional_checked_cast_addr
+// CHECK: return
+sil @replace_unconditional_check_cast_addr_to_myerror_existential : $@convention(thin) <X:MyError> (@in E2<X>) -> (@out MyError) {
+bb0(%0 : $*MyError, %1 : $*E2<X>):
+ unconditional_checked_cast_addr take_always E2<X> in %1 : $*E2<X> to MyError in %0 : $*MyError
+ %2 = tuple ()
+ return %2 : $()
+}
+
+// Check casts to Error.
+// CHECK-LABEL: sil @replace_unconditional_check_cast_addr_for_type_to_error_existential
+// CHECK-NOT: unconditional_checked_cast_addr
+// CHECK: [[ALLOC_BOX:%.*]] = alloc_existential_box $Error, $E1
+// CHECK: [[PROJ:%.*]] = project_existential_box $E1 in [[ALLOC_BOX]] : $Error
+// CHECK: [[VAL:%.*]] = load %1 : $*E1
+// CHECK: store [[VAL]] to [[PROJ]]
+// CHECK: store [[ALLOC_BOX]] to %0 : $*Error
+// CHECK: return
+sil @replace_unconditional_check_cast_addr_for_type_to_error_existential : $@convention(thin) (@in E1) -> (@out Error) {
+bb0(%0 : $*Error, %1 : $*E1):
+ unconditional_checked_cast_addr take_always E1 in %1 : $*E1 to Error in %0 : $*Error
+ %2 = tuple ()
+ return %2 : $()
+}
+
+// Check casts to Error.
+// CHECK-LABEL: sil @replace_unconditional_check_cast_addr_for_type_to_error_existential_copy_on_success
+// CHECK-NOT: unconditional_checked_cast_addr
+// CHECK: [[ALLOC_BOX:%.*]] = alloc_existential_box $Error, $E1
+// CHECK: [[PROJ:%.*]] = project_existential_box $E1 in [[ALLOC_BOX]] : $Error
+// CHECK: [[VAL:%.*]] = load %1 : $*E1
+// CHECK: retain_value [[VAL]]
+// CHECK: store [[VAL]] to [[PROJ]]
+// CHECK: store [[ALLOC_BOX]] to %0 : $*Error
+// CHECK: return
+sil @replace_unconditional_check_cast_addr_for_type_to_error_existential_copy_on_success : $@convention(thin) (@in E1) -> (@out Error) {
+bb0(%0 : $*Error, %1 : $*E1):
+ unconditional_checked_cast_addr copy_on_success E1 in %1 : $*E1 to Error in %0 : $*Error
+ %2 = tuple ()
+ return %2 : $()
+}
diff --git a/test/SILOptimizer/diagnose_unreachable.sil b/test/SILOptimizer/diagnose_unreachable.sil
index 8876a41..8bb789d 100644
--- a/test/SILOptimizer/diagnose_unreachable.sil
+++ b/test/SILOptimizer/diagnose_unreachable.sil
@@ -1,4 +1,4 @@
-// RUN: %target-sil-opt -assume-parsing-unqualified-ownership-sil -enable-sil-verify-all %s -diagnose-unreachable | %FileCheck %s
+// RUN: %target-sil-opt -assume-parsing-unqualified-ownership-sil -enable-sil-verify-all %s -diagnose-unreachable -sil-print-debuginfo | %FileCheck %s
import Builtin
import Swift
@@ -387,19 +387,24 @@
throw %3 : $Error
}
+sil_scope 0 { loc "f.swift":1:1 parent @try_apply_2 : $@convention(thin) (Builtin.Int1) -> @error Error }
+// CHECK: sil_scope [[F:[0-9]+]] { loc "f.swift":1:1 parent @try_apply_2
+sil_scope 1 { loc "f.swift":2:1 parent 0 }
+// CHECK: sil_scope [[S:[0-9]+]] { loc "f.swift":2:1 parent [[F]] }
// CHECK-LABEL:sil @try_apply_2
-// CHECK: bb3(
-// CHECK-NEXT: {{ unreachable}}
+// CHECK: bb3({{.*}}$Never):
+// CHECK-NEXT: {{ unreachable }}, scope [[S]]
// CHECK: bb4(
// CHECK-NEXT: throw
+
sil @try_apply_2 : $@convention(thin) (Builtin.Int1) -> @error Error {
bb0(%0 : $Builtin.Int1):
%1 = function_ref @throwing_noreturn : $@convention(thin) () -> (Never, @error Error)
cond_br %0, bb1, bb2
bb1:
- try_apply %1() : $@convention(thin) () -> (Never, @error Error), normal bb3, error bb4
+ try_apply %1() : $@convention(thin) () -> (Never, @error Error), normal bb3, error bb4, scope 0
bb2:
- try_apply %1() : $@convention(thin) () -> (Never, @error Error), normal bb3, error bb4
+ try_apply %1() : $@convention(thin) () -> (Never, @error Error), normal bb3, error bb4, scope 1
bb3(%2 : $Never):
%3 = tuple ()
return %3 : $()
diff --git a/test/SILOptimizer/sil_combine_enum_addr.sil b/test/SILOptimizer/sil_combine_enum_addr.sil
index 8493ee9..a525fbf 100644
--- a/test/SILOptimizer/sil_combine_enum_addr.sil
+++ b/test/SILOptimizer/sil_combine_enum_addr.sil
@@ -6,7 +6,7 @@
import Swift
// CHECK-LABEL: sil @convert_inject_enum_addr_select_enum_addr_into_cond_br : $@convention(thin) (@in Int, @inout _Stdout) -> ()
-// CHECK: unconditional_checked_cast_addr
+// CHECK: init_existential_addr
// CHECK: inject_enum_addr
// CHECK-NOT: select_enum_addr
// CHECK-NOT: bb1
@@ -42,7 +42,7 @@
// CHECK-LABEL: sil @convert_inject_enum_addr_switch_enum_addr_into_cond_br : $@convention(thin) (@in Int, @inout _Stdout) -> ()
-// CHECK: unconditional_checked_cast_addr
+// CHECK: init_existential_addr
// CHECK: inject_enum_addr
// CHECK-NOT: switch_enum_addr
// CHECK-NOT: bb1
diff --git a/test/Sema/exhaustive_switch.swift b/test/Sema/exhaustive_switch.swift
index 944db82..0ea73f2 100644
--- a/test/Sema/exhaustive_switch.swift
+++ b/test/Sema/exhaustive_switch.swift
@@ -309,3 +309,37 @@
case .two: break
}
}
+
+enum Runcible {
+ case spoon
+ case hat
+ case fork
+}
+
+func checkDiagnosticMinimality(x: Runcible?) {
+ switch (x!, x!) { // expected-error {{switch must be exhaustive}}
+ // expected-note@-1 {{add missing case: '(.fork, _)'}}
+ // expected-note@-2 {{add missing case: '(.hat, .hat)'}}
+ // expected-note@-3 {{add missing case: '(.hat, .fork)'}}
+ // expected-note@-4 {{add missing case: '(_, .fork)'}}
+ case (.spoon, .spoon):
+ break
+ case (.spoon, .hat):
+ break
+ case (.hat, .spoon):
+ break
+ }
+
+ switch (x!, x!) { // expected-error {{switch must be exhaustive}}
+ // expected-note@-1 {{add missing case: '(.fork, _)'}}
+ // expected-note@-2 {{add missing case: '(.hat, .spoon)'}}
+ // expected-note@-3 {{add missing case: '(.hat, .fork)'}}
+ // expected-note@-4 {{add missing case: '(.spoon, .hat)'}}
+ // expected-note@-5 {{add missing case: '(.spoon, .fork)'}}
+ // expected-note@-6 {{add missing case: '(_, .fork)'}}
+ case (.spoon, .spoon):
+ break
+ case (.hat, .hat):
+ break
+ }
+}
diff --git a/test/attr/attr_downgrade_exhaustivity.swift b/test/attr/attr_downgrade_exhaustivity.swift
new file mode 100644
index 0000000..c357209
--- /dev/null
+++ b/test/attr/attr_downgrade_exhaustivity.swift
@@ -0,0 +1,150 @@
+// RUN: %target-typecheck-verify-swift -swift-version 3 %s
+
+enum Runcible {
+ case spoon
+ case hat
+ @_downgrade_exhaustivity_check
+ case fork
+}
+
+enum Trioptional {
+ case some(Runcible)
+ case just(Runcible)
+ case none
+}
+
+enum Fungible {
+ case cash
+ case giftCard
+}
+
+func missingCases(x: Runcible?, y: Runcible?, z: Trioptional) {
+ // Should warn in S3 mode that `fork` isn't used
+ switch x! { // expected-warning {{switch must be exhaustive}}
+ // expected-note@-1 {{add missing case: '.fork'}}
+ case .spoon:
+ break
+ case .hat:
+ break
+ }
+
+ // Should warn in S3 mode that `fork` isn't used
+ switch (x!, y!) { // expected-warning {{switch must be exhaustive}}
+ // expected-note@-1 3 {{add missing case:}}
+ case (.spoon, .spoon):
+ break
+ case (.spoon, .hat):
+ break
+ case (.hat, .spoon):
+ break
+ case (.hat, .hat):
+ break
+ }
+
+ // Should error, since `fork` is used but not totally covered
+ switch (x!, y!) { // expected-error {{switch must be exhaustive}}
+ // expected-note@-1 {{add missing case: '(.fork, .hat)'}}
+ // expected-note@-2 {{add missing case: '(.fork, .fork)'}}
+ // expected-note@-3 {{add missing case: '(.hat, .fork)'}}
+ // expected-note@-4 {{add missing case: '(_, .fork)'}}
+ case (.spoon, .spoon):
+ break
+ case (.spoon, .hat):
+ break
+ case (.hat, .spoon):
+ break
+ case (.hat, .hat):
+ break
+ case (.fork, .spoon):
+ break
+ }
+
+ // Should error, since `fork` is used but not totally covered
+ switch (x!, y!) { // expected-error {{switch must be exhaustive}}
+ // expected-note@-1 {{add missing case: '(.fork, _)'}}
+ // expected-note@-2 {{add missing case: '(.spoon, .fork)'}}
+ case (.spoon, .spoon):
+ break
+ case (.spoon, .hat):
+ break
+ case (.hat, .spoon):
+ break
+ case (.hat, .hat):
+ break
+ case (.hat, .fork):
+ break
+ }
+
+ // Should warn in S3 mode that `fork` isn't used
+ switch x { // expected-warning {{switch must be exhaustive}}
+ // expected-note@-1 {{add missing case: '.some(.fork)'}}
+ case .some(.spoon):
+ break
+ case .some(.hat):
+ break
+ case .none:
+ break
+ }
+
+ // Should warn in S3 mode that `fork` isn't used
+ switch (x, y!) { // expected-warning {{switch must be exhaustive}}
+ // expected-note@-1 {{add missing case: '(.some(.fork), _)'}}
+ // expected-note@-2 {{add missing case: '(.none, .fork)'}}
+ // expected-note@-3 {{add missing case: '(.some(.hat), .fork)'}}
+ // expected-note@-4 {{add missing case: '(_, .fork)'}}
+ case (.some(.spoon), .spoon):
+ break
+ case (.some(.spoon), .hat):
+ break
+ case (.some(.hat), .spoon):
+ break
+ case (.some(.hat), .hat):
+ break
+ case (.none, .spoon):
+ break
+ case (.none, .hat):
+ break
+ }
+
+ // Should warn in S3 mode that `fork` isn't used
+ switch (x, y) { // expected-warning {{switch must be exhaustive}}
+ // expected-note@-1 {{add missing case: '(.some(.fork), _)'}}
+ // expected-note@-2 {{add missing case: '(_, .some(.fork))'}}
+ // expected-note@-3 {{add missing case: '(.some(.hat), .some(.fork))'}}
+ // expected-note@-4 {{add missing case: '(.none, _)'}}
+ case (.some(.spoon), .some(.spoon)):
+ break
+ case (.some(.spoon), .some(.hat)):
+ break
+ case (.some(.spoon), .none):
+ break
+ case (.some(.hat), .some(.spoon)):
+ break
+ case (.some(.hat), .some(.hat)):
+ break
+ case (.some(.hat), .none):
+ break
+ case (.some(.hat), .some(.spoon)): // expected-warning {{case is already handled by previous patterns; consider removing it}}
+ break
+ case (.some(.hat), .some(.hat)): // expected-warning {{case is already handled by previous patterns; consider removing it}}
+ break
+ case (.some(.hat), .none): // expected-warning {{case is already handled by previous patterns; consider removing it}}
+ break
+ }
+
+ // Should warn in S3 mode that `fork` isn't used
+ switch z { // expected-warning {{switch must be exhaustive}}
+ // expected-note@-1 {{add missing case: '.some(.fork)'}}
+ // expected-note@-2 {{add missing case: '.just(.fork)'}}
+ case .some(.spoon):
+ break
+ case .some(.hat):
+ break
+ case .just(.spoon):
+ break
+ case .just(.hat):
+ break
+ case .none:
+ break
+ }
+}
diff --git a/test/decl/var/lazy_properties.swift b/test/decl/var/lazy_properties.swift
index 1f6dba9..ab76c10 100644
--- a/test/decl/var/lazy_properties.swift
+++ b/test/decl/var/lazy_properties.swift
@@ -1,4 +1,5 @@
-// RUN: %target-typecheck-verify-swift -parse-as-library
+// RUN: %target-typecheck-verify-swift -parse-as-library -swift-version 3
+// RUN: %target-typecheck-verify-swift -parse-as-library -swift-version 4
lazy func lazy_func() {} // expected-error {{'lazy' may only be used on 'var' declarations}} {{1-6=}}
@@ -27,22 +28,21 @@
lazy var (e, f) = (1,2) // expected-error {{'lazy' cannot destructure an initializer}} {{3-8=}}
- lazy var g : Int = { 0 }() // single-expr closure
+ lazy var g = { 0 }() // single-expr closure
- lazy var h : Int = { return 0 }()+1 // multi-stmt closure
+ lazy var h : Int = { 0 }() // single-expr closure
- lazy var i : Int = 42 { // expected-error {{lazy properties may not have observers}} {{3-8=}}
+ lazy var i = { () -> Int in return 0 }()+1 // multi-stmt closure
+
+ lazy var j : Int = { return 0 }()+1 // multi-stmt closure
+
+ lazy var k : Int = { () -> Int in return 0 }()+1 // multi-stmt closure
+
+ lazy var l : Int = 42 { // expected-error {{lazy properties may not have observers}} {{3-8=}}
didSet {
}
}
- // Lazy values can have observers, be NSCopying, etc.
-/* lazy var d : Int = 42 {
- didSet {
- print("set me")
- }
- }*/
-
init() {
lazy var localvar = 42 // expected-error {{lazy is only valid for members of a struct or class}} {{5-10=}}
localvar += 1
@@ -73,7 +73,8 @@
// <rdar://problem/16889110> capture lists in lazy member properties cannot use self
class CaptureListInLazyProperty {
- lazy var closure: () -> Int = { [weak self] in return self!.i }
+ lazy var closure1 = { [weak self] in return self!.i }
+ lazy var closure2: () -> Int = { [weak self] in return self!.i }
var i = 42
}
@@ -91,3 +92,64 @@
_ = ()
}
}
+
+protocol MyProtocol {
+ func f() -> Int
+}
+
+struct MyStruct : MyProtocol {
+ func f() -> Int { return 0 }
+}
+
+struct Outer {
+ static let p: MyProtocol = MyStruct()
+
+ struct Inner {
+ lazy var x = p.f()
+
+ lazy var y = {_ = 3}()
+ // expected-warning@-1 {{variable 'y' inferred to have type '()', which may be unexpected}}
+ // expected-note@-2 {{add an explicit type annotation to silence this warning}}
+ }
+}
+
+// https://bugs.swift.org/browse/SR-2616
+struct Construction {
+ init(x: Int, y: Int? = 42) { }
+}
+
+class Constructor {
+ lazy var myQ = Construction(x: 3)
+}
+
+
+// Problems with self references
+class BaseClass {
+ var baseInstanceProp = 42
+ static var baseStaticProp = 42
+}
+
+class ReferenceSelfInLazyProperty : BaseClass {
+ lazy var refs = (i, f())
+ lazy var trefs: (Int, Int) = (i, f())
+
+ lazy var qrefs = (self.i, self.f())
+ lazy var qtrefs: (Int, Int) = (self.i, self.f())
+
+ lazy var crefs = { (i, f()) }()
+ lazy var ctrefs: (Int, Int) = { (i, f()) }()
+
+ lazy var cqrefs = { (self.i, self.f()) }()
+ lazy var cqtrefs: (Int, Int) = { (self.i, self.f()) }()
+
+ lazy var mrefs = { () -> (Int, Int) in return (i, f()) }()
+ // expected-error@-1 {{call to method 'f' in closure requires explicit 'self.' to make capture semantics explicit}}
+ // expected-error@-2 {{reference to property 'i' in closure requires explicit 'self.' to make capture semantics explicit}}
+ lazy var mtrefs: (Int, Int) = { return (i, f()) }()
+
+ lazy var mqrefs = { () -> (Int, Int) in (self.i, self.f()) }()
+ lazy var mqtrefs: (Int, Int) = { return (self.i, self.f()) }()
+
+ var i = 42
+ func f() -> Int { return 0 }
+}
diff --git a/test/expr/cast/dictionary_bridge.swift b/test/expr/cast/dictionary_bridge.swift
index c4ab85b..8b973f6 100644
--- a/test/expr/cast/dictionary_bridge.swift
+++ b/test/expr/cast/dictionary_bridge.swift
@@ -83,12 +83,12 @@
dictBO = dictBB as [BridgedToObjC: ObjC]
dictOB = dictBB as [ObjC: BridgedToObjC]
- dictBB = dictBO // expected-error{{cannot assign value of type 'Dictionary<BridgedToObjC, ObjC>' to type 'Dictionary<BridgedToObjC, BridgedToObjC>'}}
- dictBB = dictOB // expected-error{{cannot assign value of type 'Dictionary<ObjC, BridgedToObjC>' to type 'Dictionary<BridgedToObjC, BridgedToObjC>'}}
+ dictBB = dictBO // expected-error{{cannot assign value of type '[BridgedToObjC : ObjC]' to type '[BridgedToObjC : BridgedToObjC]'}}
+ dictBB = dictOB // expected-error{{cannot assign value of type '[ObjC : BridgedToObjC]' to type '[BridgedToObjC : BridgedToObjC]'}}
- dictDO = dictBB // expected-error{{cannot assign value of type 'Dictionary<BridgedToObjC, BridgedToObjC>' to type 'Dictionary<DerivesObjC, ObjC>'}}
- dictOD = dictBB // expected-error{{cannot assign value of type 'Dictionary<BridgedToObjC, BridgedToObjC>' to type 'Dictionary<ObjC, DerivesObjC>'}}
- dictDD = dictBB // expected-error{{cannot assign value of type 'Dictionary<BridgedToObjC, BridgedToObjC>' to type 'Dictionary<DerivesObjC, DerivesObjC>'}}
+ dictDO = dictBB // expected-error{{cannot assign value of type '[BridgedToObjC : BridgedToObjC]' to type '[DerivesObjC : ObjC]'}}
+ dictOD = dictBB // expected-error{{cannot assign value of type '[BridgedToObjC : BridgedToObjC]' to type '[ObjC : DerivesObjC]'}}
+ dictDD = dictBB // expected-error{{cannot assign value of type '[BridgedToObjC : BridgedToObjC]' to type '[DerivesObjC : DerivesObjC]'}}
_ = dictDD; _ = dictDO; _ = dictOD; _ = dictOO; _ = dictOR; _ = dictOR; _ = dictRR; _ = dictRO
}
@@ -119,7 +119,7 @@
_ = dictOB as Dictionary<BridgedToObjC, BridgedToObjC>
// We don't do mixed down/upcasts.
- _ = dictDO as! Dictionary<BridgedToObjC, BridgedToObjC> // expected-warning{{forced cast from 'Dictionary<DerivesObjC, ObjC>' to 'Dictionary<BridgedToObjC, BridgedToObjC>' always succeeds; did you mean to use 'as'?}}
+ _ = dictDO as! Dictionary<BridgedToObjC, BridgedToObjC> // expected-warning{{forced cast from '[DerivesObjC : ObjC]' to 'Dictionary<BridgedToObjC, BridgedToObjC>' always succeeds; did you mean to use 'as'?}}
}
func testConditionalDowncastBridge() {
@@ -149,7 +149,7 @@
// Mixed down/upcasts.
if let d = dictDO as? Dictionary<BridgedToObjC, BridgedToObjC> { _ = d }
- // expected-warning@-1{{conditional cast from 'Dictionary<DerivesObjC, ObjC>' to 'Dictionary<BridgedToObjC, BridgedToObjC>' always succeeds}}
+ // expected-warning@-1{{conditional cast from '[DerivesObjC : ObjC]' to 'Dictionary<BridgedToObjC, BridgedToObjC>' always succeeds}}
_ = dictRR
_ = dictRO
diff --git a/test/expr/cast/dictionary_coerce.swift b/test/expr/cast/dictionary_coerce.swift
index 76fa403b..de97265 100644
--- a/test/expr/cast/dictionary_coerce.swift
+++ b/test/expr/cast/dictionary_coerce.swift
@@ -24,11 +24,11 @@
dictCC = dictDD
dictCD = dictDD
-dictCD = dictCC // expected-error{{cannot assign value of type 'Dictionary<C, C>' to type 'Dictionary<C, D>'}}
+dictCD = dictCC // expected-error{{cannot assign value of type '[C : C]' to type '[C : D]'}}
dictDC = dictDD
-dictDC = dictCD // expected-error{{cannot assign value of type 'Dictionary<C, D>' to type 'Dictionary<D, C>'}}
+dictDC = dictCD // expected-error{{cannot assign value of type '[C : D]' to type '[D : C]'}}
-dictDD = dictCC // expected-error{{cannot assign value of type 'Dictionary<C, C>' to type 'Dictionary<D, D>'}}
+dictDD = dictCC // expected-error{{cannot assign value of type '[C : C]' to type '[D : D]'}}
diff --git a/test/expr/cast/dictionary_downcast.swift b/test/expr/cast/dictionary_downcast.swift
index b5cdef3..7f818cf 100644
--- a/test/expr/cast/dictionary_downcast.swift
+++ b/test/expr/cast/dictionary_downcast.swift
@@ -34,12 +34,12 @@
if let _ = dictCC as? Dictionary<D, D> { }
// Test dictionary downcasts to unrelated types.
-dictCC as Dictionary<D, U> // expected-error{{cannot convert value of type 'Dictionary<C, C>' to type 'Dictionary<D, U>' in coercion}}
-dictCC as Dictionary<U, D> // expected-error{{cannot convert value of type 'Dictionary<C, C>' to type 'Dictionary<U, D>' in coercion}}
-dictCC as Dictionary<U, U> // expected-error{{cannot convert value of type 'Dictionary<C, C>' to type 'Dictionary<U, U>' in coercion}}
+dictCC as Dictionary<D, U> // expected-error{{cannot convert value of type '[C : C]' to type 'Dictionary<D, U>' in coercion}}
+dictCC as Dictionary<U, D> // expected-error{{cannot convert value of type '[C : C]' to type 'Dictionary<U, D>' in coercion}}
+dictCC as Dictionary<U, U> // expected-error{{cannot convert value of type '[C : C]' to type 'Dictionary<U, U>' in coercion}}
// Test dictionary conditional downcasts to unrelated types
-if let _ = dictCC as? Dictionary<D, U> { } // expected-warning{{cast from 'Dictionary<C, C>' to unrelated type 'Dictionary<D, U>' always fails}}
-if let _ = dictCC as? Dictionary<U, D> { } // expected-warning{{cast from 'Dictionary<C, C>' to unrelated type 'Dictionary<U, D>' always fails}}
-if let _ = dictCC as? Dictionary<U, U> { } // expected-warning{{cast from 'Dictionary<C, C>' to unrelated type 'Dictionary<U, U>' always fails}}
+if let _ = dictCC as? Dictionary<D, U> { } // expected-warning{{cast from '[C : C]' to unrelated type 'Dictionary<D, U>' always fails}}
+if let _ = dictCC as? Dictionary<U, D> { } // expected-warning{{cast from '[C : C]' to unrelated type 'Dictionary<U, D>' always fails}}
+if let _ = dictCC as? Dictionary<U, U> { } // expected-warning{{cast from '[C : C]' to unrelated type 'Dictionary<U, U>' always fails}}
diff --git a/test/stdlib/StringCompatibility.swift b/test/stdlib/StringCompatibility.swift
index ba8fb14..385ef0b 100644
--- a/test/stdlib/StringCompatibility.swift
+++ b/test/stdlib/StringCompatibility.swift
@@ -4,58 +4,275 @@
import StdlibUnittest
+//===--- MyString ---------------------------------------------------------===//
+/// A simple StringProtocol with a wacky .description that proves
+/// LosslessStringConvertible is not infecting ordinary constructions by using
+/// .description as the content of a copied string.
+struct MyString {
+ var base: String
+}
+
+extension MyString : BidirectionalCollection {
+ typealias Iterator = String.Iterator
+ typealias Index = String.Index
+ typealias IndexDistance = String.IndexDistance
+ func makeIterator() -> Iterator { return base.makeIterator() }
+ var startIndex: String.Index { return base.startIndex }
+ var endIndex: String.Index { return base.startIndex }
+ subscript(i: Index) -> Character { return base[i] }
+ func index(after i: Index) -> Index { return base.index(after: i) }
+ func index(before i: Index) -> Index { return base.index(before: i) }
+ func index(_ i: Index, offsetBy n: IndexDistance) -> Index {
+ return base.index(i, offsetBy: n)
+ }
+ func distance(from i: Index, to j: Index) -> IndexDistance {
+ return base.distance(from: i, to: j)
+ }
+}
+
+extension MyString : RangeReplaceableCollection {
+ init() { base = "" }
+ mutating func append<S: Sequence>(contentsOf s: S)
+ where S.Element == Character {
+ base.append(contentsOf: s)
+ }
+ mutating func replaceSubrange<C: Collection>(_ r: Range<Index>, with c: C)
+ where C.Element == Character {
+ base.replaceSubrange(r, with: c)
+ }
+}
+
+extension MyString : CustomStringConvertible {
+ var description: String { return "***MyString***" }
+}
+
+extension MyString : TextOutputStream {
+ public mutating func write(_ other: String) {
+ append(contentsOf: other)
+ }
+}
+
+extension MyString : TextOutputStreamable {
+ public func write<Target : TextOutputStream>(to target: inout Target) {
+ target.write(base)
+ }
+}
+
+extension MyString : ExpressibleByUnicodeScalarLiteral {
+ public init(unicodeScalarLiteral value: String) {
+ base = .init(unicodeScalarLiteral: value)
+ }
+}
+extension MyString : ExpressibleByExtendedGraphemeClusterLiteral {
+ public init(extendedGraphemeClusterLiteral value: String) {
+ base = .init(extendedGraphemeClusterLiteral: value)
+ }
+}
+
+extension MyString : ExpressibleByStringLiteral {
+ public init(stringLiteral value: String) {
+ base = .init(stringLiteral: value)
+ }
+}
+
+extension MyString : CustomReflectable {
+ public var customMirror: Mirror {
+ return base.customMirror
+ }
+}
+
+extension MyString : CustomPlaygroundQuickLookable {
+ public var customPlaygroundQuickLook: PlaygroundQuickLook {
+ return base.customPlaygroundQuickLook
+ }
+}
+
+extension MyString : CustomDebugStringConvertible {
+ public var debugDescription: String {
+ return "(***MyString***)"
+ }
+}
+
+extension MyString : Equatable {
+ public static func ==(lhs: MyString, rhs: MyString) -> Bool {
+ return lhs.base == rhs.base
+ }
+}
+
+extension MyString : Comparable {
+ public static func <(lhs: MyString, rhs: MyString) -> Bool {
+ return lhs.base < rhs.base
+ }
+}
+
+extension MyString : Hashable {
+ public var hashValue : Int {
+ return base.hashValue
+ }
+}
+
+#if _runtime(_ObjC)
+
+extension MyString {
+ public func hasPrefix(_ prefix: String) -> Bool {
+ return self.base.hasPrefix(prefix)
+ }
+
+ public func hasSuffix(_ suffix: String) -> Bool {
+ return self.base.hasSuffix(suffix)
+ }
+}
+
+#endif
+
+extension MyString : StringProtocol {
+ typealias UTF8Index = String.UTF8Index
+ typealias UTF16Index = String.UTF16Index
+ typealias UnicodeScalarIndex = String.UnicodeScalarIndex
+ var utf8: String.UTF8View { return base.utf8 }
+ var utf16: String.UTF16View { return base.utf16 }
+ var unicodeScalars: String.UnicodeScalarView { return base.unicodeScalars }
+ var characters: String.CharacterView { return base.characters }
+ func lowercased() -> String {
+ return base.lowercased()
+ }
+ func uppercased() -> String {
+ return base.uppercased()
+ }
+
+ init<C: Collection, Encoding: Unicode.Encoding>(
+ decoding codeUnits: C, as sourceEncoding: Encoding.Type
+ )
+ where C.Iterator.Element == Encoding.CodeUnit {
+ base = .init(decoding: codeUnits, as: sourceEncoding)
+ }
+
+ init(cString nullTerminatedUTF8: UnsafePointer<CChar>) {
+ base = .init(cString: nullTerminatedUTF8)
+ }
+
+ init<Encoding: Unicode.Encoding>(
+ decodingCString nullTerminatedCodeUnits: UnsafePointer<Encoding.CodeUnit>,
+ as sourceEncoding: Encoding.Type) {
+ base = .init(decodingCString: nullTerminatedCodeUnits, as: sourceEncoding)
+ }
+
+ func withCString<Result>(
+ _ body: (UnsafePointer<CChar>) throws -> Result) rethrows -> Result {
+ return try base.withCString(body)
+ }
+
+ func withCString<Result, Encoding: Unicode.Encoding>(
+ encodedAs targetEncoding: Encoding.Type,
+ _ body: (UnsafePointer<Encoding.CodeUnit>) throws -> Result
+ ) rethrows -> Result {
+ return try base.withCString(encodedAs: targetEncoding, body)
+ }
+}
+//===----------------------------------------------------------------------===//
+
#if swift(>=4)
-public typealias ExpectedSubstring = Substring
+public typealias ExpectedConcreteSlice = Substring
+public typealias ExpectedStringFromString = String
+let swift = 4
#else
-public typealias ExpectedSubstring = String
+public typealias ExpectedConcreteSlice = String
+public typealias ExpectedStringFromString = String?
+let swift = 3
#endif
var Tests = TestSuite("SubstringCompatibility")
-Tests.test("Range/Subscript/ExpectedType") {
+Tests.test("String/Range/Slice/ExpectedType/\(swift)") {
var s = "hello world"
var sub = s[s.startIndex ..< s.endIndex]
var subsub = sub[s.startIndex ..< s.endIndex]
expectType(String.self, &s)
- expectType(ExpectedSubstring.self, &sub)
- expectType(ExpectedSubstring.self, &subsub)
+ expectType(ExpectedConcreteSlice.self, &sub)
+ expectType(ExpectedConcreteSlice.self, &subsub)
}
-Tests.test("ClosedRange/Subsript/ExpectedType") {
+Tests.test("String/ClosedRange/Slice/ExpectedType/\(swift)") {
var s = "hello world"
let lastIndex = s.index(before:s.endIndex)
var sub = s[s.startIndex ... lastIndex]
var subsub = sub[s.startIndex ... lastIndex]
expectType(String.self, &s)
- expectType(ExpectedSubstring.self, &sub)
- expectType(ExpectedSubstring.self, &subsub)
+ expectType(ExpectedConcreteSlice.self, &sub)
+ expectType(ExpectedConcreteSlice.self, &subsub)
}
-Tests.test("String.init(_:String)/default type") {
- var s = String("")
- expectType(String?.self, &s)
+Tests.test("Substring/Range/Slice/ExpectedType/\(swift)") {
+ let s = "hello world" as Substring
+ var sub = s[s.startIndex ..< s.endIndex]
+ var subsub = sub[s.startIndex ..< s.endIndex]
+
+ expectType(ExpectedConcreteSlice.self, &sub)
+ expectType(ExpectedConcreteSlice.self, &subsub)
}
-Tests.test("LosslessStringConvertible/generic") {
+Tests.test("Substring/ClosedRange/Slice/ExpectedType/\(swift)") {
+ let s = "hello world" as Substring
+ let lastIndex = s.index(before:s.endIndex)
+ var sub = s[s.startIndex ... lastIndex]
+ var subsub = sub[s.startIndex ... lastIndex]
+
+ expectType(ExpectedConcreteSlice.self, &sub)
+ expectType(ExpectedConcreteSlice.self, &subsub)
+}
+
+Tests.test("RangeReplaceable.init/generic/\(swift)") {
+ func check<
+ T: RangeReplaceableCollection, S: Collection
+ >(_: T.Type, from source: S)
+ where T.Element : Equatable, T.Element == S.Element
+ {
+ var r = T(source)
+ expectType(T.self, &r)
+ expectEqualSequence(Array(source), Array(r))
+ }
+
+ check(String.self, from: "a" as String)
+ check(Substring.self, from: "b" as String)
+ // FIXME: Why isn't this working?
+ // check(MyString.self, from: "c" as String)
+
+ check(String.self, from: "d" as Substring)
+ check(Substring.self, from: "e" as Substring)
+ // FIXME: Why isn't this working?
+ // check(MyString.self, from: "f" as Substring)
+
+ // FIXME: Why isn't this working?
+ // check(String.self, from: "g" as MyString)
+ // check(Substring.self, from: "h" as MyString)
+ check(MyString.self, from: "i" as MyString)
+}
+
+Tests.test("String.init(someString)/default type/\(swift)") {
+ var s = String("" as String)
+ expectType(ExpectedStringFromString.self, &s)
+}
+
+Tests.test("Substring.init(someString)/default type/\(swift)") {
+ var s = Substring("" as Substring)
+ expectType(Substring.self, &s)
+}
+
+Tests.test("LosslessStringConvertible/generic/\(swift)") {
func f<T : LosslessStringConvertible>(_ x: T.Type) {
_ = T("")! // unwrapping optional should work in generic context
}
f(String.self)
}
-Tests.test("LosslessStringConvertible/concrete") {
- _ = String("") as String?
-}
-
-#if swift(>=4)
-#else
-Tests.test("LosslessStringConvertible/force unwrap") {
+#if !swift(>=4)
+Tests.test("LosslessStringConvertible/force unwrap/\(swift)") {
// Force unwrap should still work in Swift 3 mode
_ = String("")!
}
diff --git a/test/stmt/statements.swift b/test/stmt/statements.swift
index db46e81..e8dcd1a 100644
--- a/test/stmt/statements.swift
+++ b/test/stmt/statements.swift
@@ -418,6 +418,7 @@
// condition may have contained a SequenceExpr.
func r23684220(_ b: Any) {
if let _ = b ?? b {} // expected-error {{initializer for conditional binding must have Optional type, not 'Any'}}
+ // expected-warning@-1 {{left side of nil coalescing operator '??' has non-optional type 'Any', so the right side is never used}}
}
diff --git a/tools/SourceKit/lib/SwiftLang/SwiftLangSupport.cpp b/tools/SourceKit/lib/SwiftLang/SwiftLangSupport.cpp
index f7b1d8a..d2712da 100644
--- a/tools/SourceKit/lib/SwiftLang/SwiftLangSupport.cpp
+++ b/tools/SourceKit/lib/SwiftLang/SwiftLangSupport.cpp
@@ -729,6 +729,7 @@
// Ignore these.
case DAK_ShowInInterface:
case DAK_RawDocComment:
+ case DAK_DowngradeExhaustivityCheck:
continue;
default:
break;
diff --git a/utils/symbolicate-linux-fatal b/utils/symbolicate-linux-fatal
index e9215d9..81d403f 100755
--- a/utils/symbolicate-linux-fatal
+++ b/utils/symbolicate-linux-fatal
@@ -25,6 +25,7 @@
from __future__ import print_function
import argparse
+import os
import subprocess
import lldb
@@ -34,8 +35,11 @@
dyn_libs = {}
for line in lddoutput.splitlines():
ldd_tokens = line.split()
- if len(ldd_tokens) >= 3:
- dyn_libs[ldd_tokens[0]] = ldd_tokens[2]
+ if len(ldd_tokens) >= 2:
+ lib = ldd_tokens[-2]
+ dyn_libs[ldd_tokens[0]] = lib
+ real_name = os.path.basename(os.path.realpath(lib))
+ dyn_libs[real_name] = lib
return dyn_libs
diff --git a/validation-test/compiler_crashers/28508-unreachable-executed-at-swift-lib-sema-csgen-cpp-2656.swift b/validation-test/compiler_crashers_fixed/28508-unreachable-executed-at-swift-lib-sema-csgen-cpp-2656.swift
similarity index 87%
rename from validation-test/compiler_crashers/28508-unreachable-executed-at-swift-lib-sema-csgen-cpp-2656.swift
rename to validation-test/compiler_crashers_fixed/28508-unreachable-executed-at-swift-lib-sema-csgen-cpp-2656.swift
index 33b37bd..19f3c69 100644
--- a/validation-test/compiler_crashers/28508-unreachable-executed-at-swift-lib-sema-csgen-cpp-2656.swift
+++ b/validation-test/compiler_crashers_fixed/28508-unreachable-executed-at-swift-lib-sema-csgen-cpp-2656.swift
@@ -5,5 +5,5 @@
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
-// RUN: not --crash %target-swift-frontend %s -emit-ir
+// RUN: not %target-swift-frontend %s -emit-ir
protocol A{{}func a{}struct A{lazy var f=a
diff --git a/validation-test/compiler_crashers/28509-allowoverwrite-e-haslvalueaccesskind-l-value-access-kind-has-already-been-set.swift b/validation-test/compiler_crashers_fixed/28509-allowoverwrite-e-haslvalueaccesskind-l-value-access-kind-has-already-been-set.swift
similarity index 82%
rename from validation-test/compiler_crashers/28509-allowoverwrite-e-haslvalueaccesskind-l-value-access-kind-has-already-been-set.swift
rename to validation-test/compiler_crashers_fixed/28509-allowoverwrite-e-haslvalueaccesskind-l-value-access-kind-has-already-been-set.swift
index b207867..fe46a52 100644
--- a/validation-test/compiler_crashers/28509-allowoverwrite-e-haslvalueaccesskind-l-value-access-kind-has-already-been-set.swift
+++ b/validation-test/compiler_crashers_fixed/28509-allowoverwrite-e-haslvalueaccesskind-l-value-access-kind-has-already-been-set.swift
@@ -5,6 +5,5 @@
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
-// RUN: not --crash %target-swift-frontend %s -emit-ir
-// REQUIRES: asserts
+// RUN: not %target-swift-frontend %s -emit-ir
class d{lazy var f={_={
diff --git a/validation-test/compiler_crashers/28605-anonymous-namespace-verifier-verifychecked-swift-type-llvm-smallptrset-swift-arc.swift b/validation-test/compiler_crashers_fixed/28605-anonymous-namespace-verifier-verifychecked-swift-type-llvm-smallptrset-swift-arc.swift
similarity index 87%
rename from validation-test/compiler_crashers/28605-anonymous-namespace-verifier-verifychecked-swift-type-llvm-smallptrset-swift-arc.swift
rename to validation-test/compiler_crashers_fixed/28605-anonymous-namespace-verifier-verifychecked-swift-type-llvm-smallptrset-swift-arc.swift
index 8e6313f..caf6a1e 100644
--- a/validation-test/compiler_crashers/28605-anonymous-namespace-verifier-verifychecked-swift-type-llvm-smallptrset-swift-arc.swift
+++ b/validation-test/compiler_crashers_fixed/28605-anonymous-namespace-verifier-verifychecked-swift-type-llvm-smallptrset-swift-arc.swift
@@ -5,6 +5,6 @@
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
-// RUN: not --crash %target-swift-frontend %s -emit-ir
+// RUN: not %target-swift-frontend %s -emit-ir
protocol A:RangeReplaceableCollection
guard let c=A.init(
diff --git a/validation-test/compiler_crashers/28755-getkind-requirementkind-layout.swift b/validation-test/compiler_crashers_fixed/28755-getkind-requirementkind-layout.swift
similarity index 82%
rename from validation-test/compiler_crashers/28755-getkind-requirementkind-layout.swift
rename to validation-test/compiler_crashers_fixed/28755-getkind-requirementkind-layout.swift
index faef36c..2e29534 100644
--- a/validation-test/compiler_crashers/28755-getkind-requirementkind-layout.swift
+++ b/validation-test/compiler_crashers_fixed/28755-getkind-requirementkind-layout.swift
@@ -5,6 +5,5 @@
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
-// REQUIRES: asserts
-// RUN: not --crash %target-swift-frontend %s -emit-ir
+// RUN: not %target-swift-frontend %s -emit-ir
Unmanaged.t