Skip to content

Commit c102e91

Browse files
authored
Merge pull request #4061 from DougGregor/existential-collection-literal-inference-3.0
Infer existential element/key/value types for collection literals as a fallback
2 parents 5e5a623 + d3eabb0 commit c102e91

19 files changed

+409
-72
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2097,7 +2097,11 @@ ERROR(discard_expr_outside_of_assignment,none,
20972097
())
20982098
ERROR(inout_expr_outside_of_call,none,
20992099
"'&' can only appear immediately in a call argument list", ())
2100-
2100+
ERROR(collection_literal_heterogenous,none,
2101+
"heterogenous collection literal could only be inferred to %0; add"
2102+
" explicit type annotation if this is intentional", (Type))
2103+
ERROR(collection_literal_empty,none,
2104+
"empty collection literal requires an explicit type", ())
21012105

21022106
ERROR(unresolved_member_no_inference,none,
21032107
"reference to member %0 cannot be resolved without a contextual type",

include/swift/AST/Expr.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2140,6 +2140,10 @@ class CollectionExpr : public Expr {
21402140

21412141
Expr *SemanticExpr = nullptr;
21422142

2143+
/// True if the type of this collection expr was inferred by the collection
2144+
/// fallback type, like [Any].
2145+
bool IsTypeDefaulted = false;
2146+
21432147
protected:
21442148
CollectionExpr(ExprKind Kind, SourceLoc LBracketLoc,
21452149
MutableArrayRef<Expr*> Elements,
@@ -2157,6 +2161,9 @@ class CollectionExpr : public Expr {
21572161
void setElement(unsigned i, Expr *E) { Elements[i] = E; }
21582162
unsigned getNumElements() const { return Elements.size(); }
21592163

2164+
bool isTypeDefaulted() const { return IsTypeDefaulted; }
2165+
void setIsTypeDefaulted(bool value = true) { IsTypeDefaulted = value; }
2166+
21602167
SourceLoc getLBracketLoc() const { return LBracketLoc; }
21612168
SourceLoc getRBracketLoc() const { return RBracketLoc; }
21622169
SourceRange getSourceRange() const {

include/swift/AST/Type.h

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,30 @@ class Type {
183183

184184
/// Get the canonical type, or return null if the type is null.
185185
CanType getCanonicalTypeOrNull() const; // in Types.h
186-
186+
187+
/// Computes the meet between two types.
188+
///
189+
/// The meet of two types is the most specific type that is a supertype of
190+
/// both \c type1 and \c type2. For example, given a simple class hierarchy as
191+
/// follows:
192+
///
193+
/// \code
194+
/// class A { }
195+
/// class B : A { }
196+
/// class C : A { }
197+
/// class D { }
198+
/// \endcode
199+
///
200+
/// The meet of B and C is A, the meet of A and B is A. However, there is no
201+
/// meet of D and A (or D and B, or D and C) because there is no common
202+
/// superclass. One would have to jump to an existential (e.g., \c AnyObject)
203+
/// to find a common type.
204+
///
205+
/// \returns the meet of the two types, if there is a concrete type that can
206+
/// express the meet, or a null type if the only meet would be a more-general
207+
/// existential type (e.g., \c Any).
208+
static Type meet(Type type1, Type type2);
209+
187210
private:
188211
// Direct comparison is disabled for types, because they may not be canonical.
189212
void operator==(Type T) const = delete;
@@ -432,6 +455,7 @@ class CanGenericSignature {
432455
return Signature;
433456
}
434457
};
458+
435459
} // end namespace swift
436460

437461
namespace llvm {

lib/AST/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ add_swift_library(swiftAST STATIC
3838
SourceEntityWalker.cpp
3939
Substitution.cpp
4040
Type.cpp
41+
TypeJoinMeet.cpp
4142
TypeRefinementContext.cpp
4243
TypeRepr.cpp
4344
TypeWalker.cpp

lib/AST/TypeJoinMeet.cpp

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
//===--- TypeJoinMeet.cpp - Swift Type "Join" and "Meet" -----------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See http://swift.org/LICENSE.txt for license information
9+
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
// This file implements the "meet" operation for types (and, eventually,
14+
// "join").
15+
//
16+
//===----------------------------------------------------------------------===//
17+
#include "swift/AST/ASTContext.h"
18+
#include "swift/AST/Type.h"
19+
#include "swift/AST/Types.h"
20+
#include "llvm/ADT/SmallPtrSet.h"
21+
using namespace swift;
22+
23+
Type Type::meet(Type type1, Type type2) {
24+
assert(!type1->hasTypeVariable() && !type2->hasTypeVariable() &&
25+
"Cannot compute meet of types involving type variables");
26+
27+
// FIXME: This algorithm is woefully incomplete, and is only currently used
28+
// for optimizing away extra exploratory work in the constraint solver. It
29+
// should eventually encompass all of the subtyping rules of the language.
30+
31+
// If the types are equivalent, the meet is obvious.
32+
if (type1->isEqual(type2))
33+
return type1;
34+
35+
// If both are class types or opaque types that potentially have superclasses,
36+
// find the common superclass.
37+
if (type1->mayHaveSuperclass() && type2->mayHaveSuperclass()) {
38+
ASTContext &ctx = type1->getASTContext();
39+
LazyResolver *resolver = ctx.getLazyResolver();
40+
41+
/// Walk the superclasses of type1 looking for type2. Record them for our
42+
/// second step.
43+
llvm::SmallPtrSet<CanType, 8> superclassesOfType1;
44+
CanType canType2 = type2->getCanonicalType();
45+
for (Type super1 = type1; super1; super1 = super1->getSuperclass(resolver)){
46+
CanType canSuper1 = super1->getCanonicalType();
47+
48+
// If we have found the second type, we're done.
49+
if (canSuper1 == canType2) return super1;
50+
51+
superclassesOfType1.insert(canSuper1);
52+
}
53+
54+
// Look through the superclasses of type2 to determine if any were also
55+
// superclasses of type1.
56+
for (Type super2 = type2; super2; super2 = super2->getSuperclass(resolver)){
57+
CanType canSuper2 = super2->getCanonicalType();
58+
59+
// If we found the first type, we're done.
60+
if (superclassesOfType1.count(canSuper2)) return super2;
61+
}
62+
63+
// There is no common superclass; we're done.
64+
return nullptr;
65+
}
66+
67+
// The meet can only be an existential.
68+
return nullptr;
69+
}
70+

lib/Sema/CSApply.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2711,6 +2711,14 @@ namespace {
27112711

27122712
expr->setSemanticExpr(result);
27132713
expr->setType(arrayTy);
2714+
2715+
// If the array element type was defaulted, note that in the expression.
2716+
auto elementTypeVariable = cs.ArrayElementTypeVariables.find(expr);
2717+
if (elementTypeVariable != cs.ArrayElementTypeVariables.end()) {
2718+
if (solution.DefaultedTypeVariables.count(elementTypeVariable->second))
2719+
expr->setIsTypeDefaulted();
2720+
}
2721+
27142722
return expr;
27152723
}
27162724

@@ -2780,6 +2788,18 @@ namespace {
27802788

27812789
expr->setSemanticExpr(result);
27822790
expr->setType(dictionaryTy);
2791+
2792+
// If the dictionary key or value type was defaulted, note that in the
2793+
// expression.
2794+
auto elementTypeVariable = cs.DictionaryElementTypeVariables.find(expr);
2795+
if (elementTypeVariable != cs.DictionaryElementTypeVariables.end()) {
2796+
if (solution.DefaultedTypeVariables.count(
2797+
elementTypeVariable->second.first) ||
2798+
solution.DefaultedTypeVariables.count(
2799+
elementTypeVariable->second.second))
2800+
expr->setIsTypeDefaulted();
2801+
}
2802+
27832803
return expr;
27842804
}
27852805

lib/Sema/CSGen.cpp

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1728,12 +1728,18 @@ namespace {
17281728
LocatorPathElt::getTupleElement(index++)));
17291729
}
17301730

1731+
// The array element type defaults to 'Any'.
1732+
if (auto elementTypeVar = arrayElementTy->getAs<TypeVariableType>()) {
1733+
CS.addConstraint(ConstraintKind::Defaultable, arrayElementTy,
1734+
tc.Context.TheAnyType, locator);
1735+
CS.ArrayElementTypeVariables[expr] = elementTypeVar;
1736+
}
1737+
17311738
return arrayTy;
17321739
}
17331740

17341741
static bool isMergeableValueKind(Expr *expr) {
1735-
return isa<CollectionExpr>(expr) ||
1736-
isa<StringLiteralExpr>(expr) || isa<IntegerLiteralExpr>(expr) ||
1742+
return isa<StringLiteralExpr>(expr) || isa<IntegerLiteralExpr>(expr) ||
17371743
isa<FloatLiteralExpr>(expr);
17381744
}
17391745

@@ -1811,16 +1817,22 @@ namespace {
18111817
auto keyTyvar2 = tty2->getElementTypes()[0]->
18121818
getAs<TypeVariableType>();
18131819

1814-
mergedKey = mergeRepresentativeEquivalenceClasses(CS,
1820+
auto keyExpr1 = cast<TupleExpr>(element1)->getElements()[0];
1821+
auto keyExpr2 = cast<TupleExpr>(element2)->getElements()[0];
1822+
1823+
if (keyExpr1->getKind() == keyExpr2->getKind() &&
1824+
isMergeableValueKind(keyExpr1)) {
1825+
mergedKey = mergeRepresentativeEquivalenceClasses(CS,
18151826
keyTyvar1, keyTyvar2);
1827+
}
18161828

18171829
auto valueTyvar1 = tty1->getElementTypes()[1]->
18181830
getAs<TypeVariableType>();
18191831
auto valueTyvar2 = tty2->getElementTypes()[1]->
18201832
getAs<TypeVariableType>();
18211833

1822-
auto elemExpr1 = dyn_cast<TupleExpr>(element1)->getElements()[1];
1823-
auto elemExpr2 = dyn_cast<TupleExpr>(element2)->getElements()[1];
1834+
auto elemExpr1 = cast<TupleExpr>(element1)->getElements()[1];
1835+
auto elemExpr2 = cast<TupleExpr>(element2)->getElements()[1];
18241836

18251837
if (elemExpr1->getKind() == elemExpr2->getKind() &&
18261838
isMergeableValueKind(elemExpr1)) {
@@ -1849,6 +1861,26 @@ namespace {
18491861
LocatorPathElt::getTupleElement(index++)));
18501862
}
18511863

1864+
// The dictionary key type defaults to 'AnyHashable'.
1865+
auto keyTypeVar = dictionaryKeyTy->getAs<TypeVariableType>();
1866+
if (keyTypeVar && tc.Context.getAnyHashableDecl()) {
1867+
auto anyHashable = tc.Context.getAnyHashableDecl();
1868+
tc.validateDecl(anyHashable);
1869+
CS.addConstraint(ConstraintKind::Defaultable, dictionaryKeyTy,
1870+
anyHashable->getDeclaredInterfaceType(), locator);
1871+
}
1872+
1873+
// The dictionary value type defaults to 'Any'.
1874+
auto valueTypeVar = dictionaryValueTy->getAs<TypeVariableType>();
1875+
if (valueTypeVar) {
1876+
CS.addConstraint(ConstraintKind::Defaultable, dictionaryValueTy,
1877+
tc.Context.TheAnyType, locator);
1878+
}
1879+
1880+
// Record key/value type variables.
1881+
if (keyTypeVar || valueTypeVar)
1882+
CS.DictionaryElementTypeVariables[expr] = { keyTypeVar, valueTypeVar };
1883+
18521884
return dictionaryTy;
18531885
}
18541886

0 commit comments

Comments
 (0)