Skip to content

Commit 30be693

Browse files
authored
Merge pull request #24808 from xedin/cleaner-foreach
[TypeChecker] Simplify for ... in ... type checking
2 parents 7a99da3 + 1cc6f77 commit 30be693

File tree

9 files changed

+72
-83
lines changed

9 files changed

+72
-83
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -447,6 +447,13 @@ ERROR(cannot_convert_assign_protocol,none,
447447
ERROR(cannot_convert_assign_nil,none,
448448
"'nil' cannot be assigned to type %0", (Type))
449449

450+
// for ... in expression
451+
ERROR(cannot_convert_sequence_element_value,none,
452+
"cannot convert sequence element type %0 to expected type %1",
453+
(Type, Type))
454+
ERROR(cannot_convert_sequence_element_protocol,none,
455+
"sequence element type %0 does not conform to expected type %1",
456+
(Type, Type))
450457

451458
ERROR(throws_functiontype_mismatch,none,
452459
"invalid conversion from throwing function of type %0 to "

lib/Sema/CSDiagnostics.cpp

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2847,6 +2847,7 @@ bool ExtraneousReturnFailure::diagnoseAsError() {
28472847

28482848
bool CollectionElementContextualFailure::diagnoseAsError() {
28492849
auto *anchor = getAnchor();
2850+
auto *locator = getLocator();
28502851

28512852
auto eltType = getFromType();
28522853
auto contextualType = getToType();
@@ -2859,8 +2860,7 @@ bool CollectionElementContextualFailure::diagnoseAsError() {
28592860
}
28602861

28612862
if (isa<DictionaryExpr>(getRawAnchor())) {
2862-
auto *locator = getLocator();
2863-
const auto eltLoc = locator->getPath().back();
2863+
const auto &eltLoc = locator->getPath().back();
28642864

28652865
switch (eltLoc.getValue()) {
28662866
case 0: // key
@@ -2880,6 +2880,15 @@ bool CollectionElementContextualFailure::diagnoseAsError() {
28802880
}
28812881
}
28822882

2883+
if (locator->isForSequenceElementType()) {
2884+
diagnostic.emplace(
2885+
emitDiagnostic(anchor->getLoc(),
2886+
contextualType->isExistentialType()
2887+
? diag::cannot_convert_sequence_element_protocol
2888+
: diag::cannot_convert_sequence_element_value,
2889+
eltType, contextualType));
2890+
}
2891+
28832892
if (!diagnostic)
28842893
return false;
28852894

lib/Sema/CSSimplify.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2193,6 +2193,12 @@ bool ConstraintSystem::repairFailures(
21932193
break;
21942194
}
21952195

2196+
case ConstraintLocator::SequenceElementType: {
2197+
conversionsOrFixes.push_back(CollectionElementContextualMismatch::create(
2198+
*this, lhs, rhs, getConstraintLocator(locator)));
2199+
break;
2200+
}
2201+
21962202
default:
21972203
break;
21982204
}

lib/Sema/ConstraintLocator.cpp

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,7 @@ void ConstraintLocator::Profile(llvm::FoldingSetNodeID &id, Expr *anchor,
6464
case ClosureResult:
6565
case ParentType:
6666
case InstanceType:
67-
case SequenceIteratorProtocol:
68-
case GeneratorElementType:
67+
case SequenceElementType:
6968
case AutoclosureResult:
7069
case GenericArgument:
7170
case NamedTupleElement:
@@ -176,6 +175,12 @@ bool ConstraintLocator::isForGenericParameter() const {
176175
path.back().getKind() == ConstraintLocator::GenericParameter;
177176
}
178177

178+
bool ConstraintLocator::isForSequenceElementType() const {
179+
auto path = getPath();
180+
return !path.empty() &&
181+
path.back().getKind() == ConstraintLocator::SequenceElementType;
182+
}
183+
179184
void ConstraintLocator::dump(SourceManager *sm) {
180185
dump(sm, llvm::errs());
181186
llvm::errs() << "\n";
@@ -257,8 +262,8 @@ void ConstraintLocator::dump(SourceManager *sm, raw_ostream &out) {
257262
out << "function result";
258263
break;
259264

260-
case GeneratorElementType:
261-
out << "generator element type";
265+
case SequenceElementType:
266+
out << "sequence element type";
262267
break;
263268

264269
case GenericArgument:
@@ -301,10 +306,6 @@ void ConstraintLocator::dump(SourceManager *sm, raw_ostream &out) {
301306
out << "rvalue adjustment";
302307
break;
303308

304-
case SequenceIteratorProtocol:
305-
out << "sequence iterator type";
306-
break;
307-
308309
case SubscriptMember:
309310
out << "subscript member";
310311
break;

lib/Sema/ConstraintLocator.h

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -98,10 +98,8 @@ class ConstraintLocator : public llvm::FoldingSetNode {
9898
ParentType,
9999
/// The instance of a metatype type.
100100
InstanceType,
101-
/// The generic type of a sequence.
102-
SequenceIteratorProtocol,
103-
/// The element type of a generator.
104-
GeneratorElementType,
101+
/// The element type of a sequence in a for ... in ... loop.
102+
SequenceElementType,
105103
/// An argument passed in an autoclosure parameter
106104
/// position, which must match the autoclosure return type.
107105
AutoclosureResult,
@@ -161,8 +159,7 @@ class ConstraintLocator : public llvm::FoldingSetNode {
161159
case ClosureResult:
162160
case ParentType:
163161
case InstanceType:
164-
case SequenceIteratorProtocol:
165-
case GeneratorElementType:
162+
case SequenceElementType:
166163
case AutoclosureResult:
167164
case Requirement:
168165
case Witness:
@@ -211,8 +208,7 @@ class ConstraintLocator : public llvm::FoldingSetNode {
211208
case ApplyArgument:
212209
case ApplyFunction:
213210
case ApplyArgToParam:
214-
case SequenceIteratorProtocol:
215-
case GeneratorElementType:
211+
case SequenceElementType:
216212
case ClosureResult:
217213
case ConstructorMember:
218214
case InstanceType:
@@ -571,6 +567,10 @@ class ConstraintLocator : public llvm::FoldingSetNode {
571567
/// Determine whether this locator points to the generic parameter.
572568
bool isForGenericParameter() const;
573569

570+
/// Determine whether this locator points to the element type of a
571+
/// sequence in a for ... in ... loop.
572+
bool isForSequenceElementType() const;
573+
574574
/// Produce a profile of this locator, for use in a folding set.
575575
static void Profile(llvm::FoldingSetNodeID &id, Expr *anchor,
576576
ArrayRef<PathElement> path);

lib/Sema/ConstraintSystem.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2200,6 +2200,8 @@ Type simplifyTypeImpl(ConstraintSystem &cs, Type type, Fn getFixedTypeFn) {
22002200
// FIXME: It's kind of weird in general that we have to look
22012201
// through lvalue, inout and IUO types here
22022202
Type lookupBaseType = newBase->getWithoutSpecifierType();
2203+
if (auto selfType = lookupBaseType->getAs<DynamicSelfType>())
2204+
lookupBaseType = selfType->getSelfType();
22032205

22042206
if (lookupBaseType->mayHaveMembers() ||
22052207
lookupBaseType->is<DynamicSelfType>()) {

lib/Sema/TypeCheckConstraints.cpp

Lines changed: 7 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -2882,85 +2882,29 @@ bool TypeChecker::typeCheckForEachBinding(DeclContext *dc, ForEachStmt *stmt) {
28822882
return true;
28832883
}
28842884

2885+
auto elementAssocType =
2886+
cast<AssociatedTypeDecl>(
2887+
sequenceProto->lookupDirect(tc.Context.Id_Element).front());
2888+
28852889
SequenceType = cs.createTypeVariable(Locator, TVO_CanBindToNoEscape);
28862890
cs.addConstraint(ConstraintKind::Conversion, cs.getType(expr),
28872891
SequenceType, Locator);
28882892
cs.addConstraint(ConstraintKind::ConformsTo, SequenceType,
28892893
sequenceProto->getDeclaredType(), Locator);
28902894

2891-
auto iteratorLocator =
2892-
cs.getConstraintLocator(Locator,
2893-
ConstraintLocator::SequenceIteratorProtocol);
28942895
auto elementLocator =
2895-
cs.getConstraintLocator(iteratorLocator,
2896-
ConstraintLocator::GeneratorElementType);
2896+
cs.getConstraintLocator(Locator,
2897+
ConstraintLocator::SequenceElementType);
28972898

28982899
// Collect constraints from the element pattern.
28992900
auto pattern = Stmt->getPattern();
29002901
InitType = cs.generateConstraints(pattern, elementLocator);
29012902
if (!InitType)
29022903
return true;
2903-
2904-
// Manually search for the iterator witness. If no iterator/element pair
2905-
// exists, solve for them.
2906-
Type iteratorType;
2907-
Type elementType;
2908-
2909-
NameLookupOptions lookupOptions = defaultMemberTypeLookupOptions;
2910-
if (isa<AbstractFunctionDecl>(cs.DC))
2911-
lookupOptions |= NameLookupFlags::KnownPrivate;
2912-
2913-
auto sequenceType = cs.getType(expr)->getRValueType();
2914-
2915-
// Look through one level of optional; this improves recovery but doesn't
2916-
// change the result.
2917-
if (auto sequenceObjectType = sequenceType->getOptionalObjectType())
2918-
sequenceType = sequenceObjectType;
2919-
2920-
// If the sequence type is an existential, we should not attempt to
2921-
// look up the member type at all, since we cannot represent associated
2922-
// types of existentials.
2923-
//
2924-
// We will diagnose it later.
2925-
if (!sequenceType->isExistentialType() &&
2926-
(sequenceType->mayHaveMembers() ||
2927-
sequenceType->isTypeVariableOrMember())) {
2928-
ASTContext &ctx = tc.Context;
2929-
auto iteratorAssocType =
2930-
cast<AssociatedTypeDecl>(
2931-
sequenceProto->lookupDirect(ctx.Id_Iterator).front());
2932-
2933-
auto subs = sequenceType->getContextSubstitutionMap(
2934-
cs.DC->getParentModule(),
2935-
sequenceProto);
2936-
iteratorType = iteratorAssocType->getDeclaredInterfaceType()
2937-
.subst(subs);
2938-
2939-
if (iteratorType) {
2940-
auto iteratorProto =
2941-
tc.getProtocol(Stmt->getForLoc(),
2942-
KnownProtocolKind::IteratorProtocol);
2943-
if (!iteratorProto)
2944-
return true;
2945-
2946-
auto elementAssocType =
2947-
cast<AssociatedTypeDecl>(
2948-
iteratorProto->lookupDirect(ctx.Id_Element).front());
2949-
2950-
elementType = iteratorType->getTypeOfMember(
2951-
cs.DC->getParentModule(),
2952-
elementAssocType,
2953-
elementAssocType->getDeclaredInterfaceType());
2954-
}
2955-
}
2956-
2957-
if (elementType.isNull()) {
2958-
elementType = cs.createTypeVariable(elementLocator,
2959-
TVO_CanBindToNoEscape);
2960-
}
29612904

29622905
// Add a conversion constraint between the element type of the sequence
29632906
// and the type of the element pattern.
2907+
auto elementType = DependentMemberType::get(SequenceType, elementAssocType);
29642908
cs.addConstraint(ConstraintKind::Conversion, elementType, InitType,
29652909
elementLocator);
29662910

test/decl/func/dynamic_self.swift

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -419,3 +419,20 @@ func useSelfOperator() {
419419
let s = SelfOperator()
420420
_ = s + s
421421
}
422+
423+
// for ... in loops
424+
425+
struct DummyIterator : IteratorProtocol {
426+
func next() -> Int? { return nil }
427+
}
428+
429+
class Iterable : Sequence {
430+
func returnsSelf() -> Self {
431+
for _ in self {}
432+
return self
433+
}
434+
435+
func makeIterator() -> DummyIterator {
436+
return DummyIterator()
437+
}
438+
}

test/stmt/foreach.swift

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,12 +53,15 @@ struct GoodTupleIterator: Sequence, IteratorProtocol {
5353
func makeIterator() -> GoodTupleIterator {}
5454
}
5555

56+
protocol ElementProtocol {}
57+
5658
func patterns(gir: GoodRange<Int>, gtr: GoodTupleIterator) {
5759
var sum : Int
5860
var sumf : Float
5961
for i : Int in gir { sum = sum + i }
6062
for i in gir { sum = sum + i }
61-
for f : Float in gir { sum = sum + f } // expected-error{{'Int' is not convertible to 'Float'}}
63+
for f : Float in gir { sum = sum + f } // expected-error{{cannot convert sequence element type 'Int' to expected type 'Float'}}
64+
for f : ElementProtocol in gir { } // expected-error {{sequence element type 'Int' does not conform to expected type 'ElementProtocol'}}
6265

6366
for (i, f) : (Int, Float) in gtr { sum = sum + i }
6467

@@ -70,7 +73,7 @@ func patterns(gir: GoodRange<Int>, gtr: GoodTupleIterator) {
7073

7174
for (i, _) : (Int, Float) in gtr { sum = sum + i }
7275

73-
for (i, _) : (Int, Int) in gtr { sum = sum + i } // expected-error{{'GoodTupleIterator.Element' (aka '(Int, Float)') is not convertible to '(Int, Int)'}}
76+
for (i, _) : (Int, Int) in gtr { sum = sum + i } // expected-error{{cannot convert sequence element type 'GoodTupleIterator.Element' (aka '(Int, Float)') to expected type '(Int, Int)'}}
7477

7578
for (i, f) in gtr {}
7679
}

0 commit comments

Comments
 (0)