@@ -133,11 +133,10 @@ namespace {
133
133
};
134
134
} // end anonymous namespace
135
135
136
- static std::tuple<Type,Type, OptionalAdjustmentKind>
137
- getTypesToCompare (ValueDecl *reqt,
138
- Type reqtType,
139
- Type witnessType,
140
- VarianceKind variance) {
136
+ static std::tuple<Type, Type, OptionalAdjustmentKind>
137
+ getTypesToCompare (ValueDecl *reqt, Type reqtType, bool reqtTypeIsIUO,
138
+ Type witnessType, bool witnessTypeIsIUO,
139
+ VarianceKind variance) {
141
140
// For @objc protocols, deal with differences in the optionality.
142
141
// FIXME: It probably makes sense to extend this to non-@objc
143
142
// protocols as well, but this requires more testing.
@@ -160,6 +159,11 @@ getTypesToCompare(ValueDecl *reqt,
160
159
break ;
161
160
162
161
case OTK_Optional:
162
+ if (witnessTypeIsIUO) {
163
+ optAdjustment = OptionalAdjustmentKind::RemoveIUO;
164
+ break ;
165
+ }
166
+
163
167
switch (variance) {
164
168
case VarianceKind::None:
165
169
case VarianceKind::Covariant:
@@ -179,6 +183,17 @@ getTypesToCompare(ValueDecl *reqt,
179
183
break ;
180
184
181
185
case OTK_Optional:
186
+ // When the requirement is an IUO, all is permitted, because we
187
+ // assume that the user knows more about the signature than we
188
+ // have information in the protocol.
189
+ if (reqtTypeIsIUO)
190
+ break ;
191
+
192
+ if (witnessTypeIsIUO) {
193
+ optAdjustment = OptionalAdjustmentKind::IUOToOptional;
194
+ break ;
195
+ }
196
+
182
197
switch (witnessOptKind) {
183
198
case OTK_None:
184
199
switch (variance) {
@@ -209,6 +224,15 @@ getTypesToCompare(ValueDecl *reqt,
209
224
// have information in the protocol.
210
225
break ;
211
226
}
227
+ } else {
228
+ // FIXME: Until IUOs are removed from the type system, make
229
+ // sure we turn these both into optionals for the purpose of
230
+ // comparing types since we could be producing IUOs in some
231
+ // places and optionals in others.
232
+ if (auto objTy = reqtType->getImplicitlyUnwrappedOptionalObjectType ())
233
+ reqtType = OptionalType::get (objTy);
234
+ if (auto objTy = witnessType->getImplicitlyUnwrappedOptionalObjectType ())
235
+ witnessType = OptionalType::get (objTy);
212
236
}
213
237
214
238
return std::make_tuple (reqtType, witnessType, optAdjustment);
@@ -344,6 +368,14 @@ static bool checkObjCWitnessSelector(TypeChecker &tc, ValueDecl *req,
344
368
return false ;
345
369
}
346
370
371
+ static ParameterList *getParameterList (ValueDecl *value) {
372
+ if (auto func = dyn_cast<AbstractFunctionDecl>(value))
373
+ return func->getParameterList (func->getDeclContext ()->isTypeContext ());
374
+
375
+ auto subscript = cast<SubscriptDecl>(value);
376
+ return subscript->getIndices ();
377
+ }
378
+
347
379
RequirementMatch
348
380
swift::matchWitness (
349
381
TypeChecker &tc,
@@ -491,18 +523,24 @@ swift::matchWitness(
491
523
// Result types must match.
492
524
// FIXME: Could allow (trivial?) subtyping here.
493
525
if (!ignoreReturnType) {
494
- auto types = getTypesToCompare (req, reqResultType,
495
- witnessResultType,
496
- VarianceKind::Covariant);
526
+ auto reqTypeIsIUO =
527
+ req->getAttrs ().hasAttribute <ImplicitlyUnwrappedOptionalAttr>();
528
+ auto witnessTypeIsIUO =
529
+ witness->getAttrs ().hasAttribute <ImplicitlyUnwrappedOptionalAttr>();
530
+ auto types =
531
+ getTypesToCompare (req, reqResultType, reqTypeIsIUO, witnessResultType,
532
+ witnessTypeIsIUO, VarianceKind::Covariant);
497
533
498
534
// Record optional adjustment, if any.
499
535
if (std::get<2 >(types) != OptionalAdjustmentKind::None) {
500
536
optionalAdjustments.push_back (
501
537
OptionalAdjustment (std::get<2 >(types)));
502
538
}
503
539
504
- if (auto result = matchTypes (std::get<0 >(types),
505
- std::get<1 >(types))) {
540
+ if (!req->isObjC () && reqTypeIsIUO != witnessTypeIsIUO)
541
+ return RequirementMatch (witness, MatchKind::TypeConflict, witnessType);
542
+
543
+ if (auto result = matchTypes (std::get<0 >(types), std::get<1 >(types))) {
506
544
return std::move (result.getValue ());
507
545
}
508
546
}
@@ -518,6 +556,12 @@ swift::matchWitness(
518
556
return RequirementMatch (witness, MatchKind::TypeConflict,
519
557
witnessType);
520
558
559
+ ParameterList *witnessParamList = getParameterList (witness);
560
+ assert (witnessParamList->size () == witnessParams.size ());
561
+
562
+ ParameterList *reqParamList = getParameterList (req);
563
+ assert (reqParamList->size () == reqParams.size ());
564
+
521
565
// Match each of the parameters.
522
566
for (unsigned i = 0 , n = reqParams.size (); i != n; ++i) {
523
567
// Variadic bits must match.
@@ -531,21 +575,33 @@ swift::matchWitness(
531
575
if (reqParams[i].isInOut () != witnessParams[i].isInOut ())
532
576
return RequirementMatch (witness, MatchKind::TypeConflict, witnessType);
533
577
578
+ auto reqParamDecl = reqParamList->get (i);
579
+ auto witnessParamDecl = witnessParamList->get (i);
580
+
581
+ auto reqParamTypeIsIUO =
582
+ reqParamDecl->getAttrs ()
583
+ .hasAttribute <ImplicitlyUnwrappedOptionalAttr>();
584
+ auto witnessParamTypeIsIUO =
585
+ witnessParamDecl->getAttrs ()
586
+ .hasAttribute <ImplicitlyUnwrappedOptionalAttr>();
587
+
534
588
// Gross hack: strip a level of unchecked-optionality off both
535
589
// sides when matching against a protocol imported from Objective-C.
536
- auto types = getTypesToCompare (req, reqParams[i].getType (),
537
- witnessParams[i].getType (),
538
- VarianceKind::Contravariant);
590
+ auto types =
591
+ getTypesToCompare (req, reqParams[i].getType (), reqParamTypeIsIUO,
592
+ witnessParams[i].getType (), witnessParamTypeIsIUO,
593
+ VarianceKind::Contravariant);
539
594
540
595
// Record any optional adjustment that occurred.
541
596
if (std::get<2 >(types) != OptionalAdjustmentKind::None) {
542
597
optionalAdjustments.push_back (
543
598
OptionalAdjustment (std::get<2 >(types), i));
544
599
}
545
600
546
- // Check whether the parameter types match.
547
- if (auto result = matchTypes (std::get<0 >(types),
548
- std::get<1 >(types))) {
601
+ if (!req->isObjC () && reqParamTypeIsIUO != witnessParamTypeIsIUO)
602
+ return RequirementMatch (witness, MatchKind::TypeConflict, witnessType);
603
+
604
+ if (auto result = matchTypes (std::get<0 >(types), std::get<1 >(types))) {
549
605
return std::move (result.getValue ());
550
606
}
551
607
}
@@ -557,16 +613,22 @@ swift::matchWitness(
557
613
}
558
614
559
615
} else {
560
- // Simple case: add the constraint.
561
- auto types = getTypesToCompare (req, reqType, witnessType,
562
- VarianceKind::None);
616
+ auto reqTypeIsIUO =
617
+ req->getAttrs ().hasAttribute <ImplicitlyUnwrappedOptionalAttr>();
618
+ auto witnessTypeIsIUO =
619
+ witness->getAttrs ().hasAttribute <ImplicitlyUnwrappedOptionalAttr>();
620
+ auto types = getTypesToCompare (req, reqType, reqTypeIsIUO, witnessType,
621
+ witnessTypeIsIUO, VarianceKind::None);
563
622
564
623
// Record optional adjustment, if any.
565
624
if (std::get<2 >(types) != OptionalAdjustmentKind::None) {
566
625
optionalAdjustments.push_back (
567
626
OptionalAdjustment (std::get<2 >(types)));
568
627
}
569
628
629
+ if (!req->isObjC () && reqTypeIsIUO != witnessTypeIsIUO)
630
+ return RequirementMatch (witness, MatchKind::TypeConflict, witnessType);
631
+
570
632
if (auto result = matchTypes (std::get<0 >(types), std::get<1 >(types))) {
571
633
return std::move (result.getValue ());
572
634
}
@@ -724,8 +786,8 @@ RequirementMatch swift::matchWitness(TypeChecker &tc,
724
786
};
725
787
726
788
// Match a type in the requirement to a type in the witness.
727
- auto matchTypes = [&](Type reqType, Type witnessType)
728
- -> Optional<RequirementMatch> {
789
+ auto matchTypes = [&](Type reqType,
790
+ Type witnessType) -> Optional<RequirementMatch> {
729
791
cs->addConstraint (ConstraintKind::Equal, reqType, witnessType, locator);
730
792
// FIXME: Check whether this has already failed.
731
793
return None;
0 commit comments