-
Notifications
You must be signed in to change notification settings - Fork 10.4k
/
Copy pathTypeCheckConstraints.cpp
2412 lines (2036 loc) · 80.7 KB
/
TypeCheckConstraints.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
//===--- TypeCheckConstraints.cpp - Constraint-based Type Checking --------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2018 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
//
//===----------------------------------------------------------------------===//
//
// This file provides high-level entry points that use constraint
// systems for type checking, as well as a few miscellaneous helper
// functions that support the constraint system.
//
//===----------------------------------------------------------------------===//
#include "MiscDiagnostics.h"
#include "TypeCheckAvailability.h"
#include "TypeChecker.h"
#include "swift/AST/ASTVisitor.h"
#include "swift/AST/ASTWalker.h"
#include "swift/AST/ConformanceLookup.h"
#include "swift/AST/DiagnosticSuppression.h"
#include "swift/AST/ExistentialLayout.h"
#include "swift/AST/GenericEnvironment.h"
#include "swift/AST/Initializer.h"
#include "swift/AST/PrettyStackTrace.h"
#include "swift/AST/SubstitutionMap.h"
#include "swift/AST/TypeCheckRequests.h"
#include "swift/Basic/Assertions.h"
#include "swift/Basic/Statistic.h"
#include "swift/IDE/TypeCheckCompletionCallback.h"
#include "swift/Sema/ConstraintSystem.h"
#include "swift/Sema/SolutionResult.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/SaveAndRestore.h"
#include "llvm/Support/raw_ostream.h"
#include <iterator>
#include <map>
#include <memory>
#include <tuple>
#include <utility>
using namespace swift;
using namespace constraints;
//===----------------------------------------------------------------------===//
// Type variable implementation.
//===----------------------------------------------------------------------===//
#pragma mark Type variable implementation
void TypeVariableType::Implementation::print(llvm::raw_ostream &OS) {
PrintOptions PO;
PO.PrintTypesForDebugging = true;
getTypeVariable()->print(OS, PO);
SmallVector<TypeVariableOptions, 4> bindingOptions;
if (canBindToLValue())
bindingOptions.push_back(TypeVariableOptions::TVO_CanBindToLValue);
if (canBindToInOut())
bindingOptions.push_back(TypeVariableOptions::TVO_CanBindToInOut);
if (canBindToNoEscape())
bindingOptions.push_back(TypeVariableOptions::TVO_CanBindToNoEscape);
if (canBindToHole())
bindingOptions.push_back(TypeVariableOptions::TVO_CanBindToHole);
if (canBindToPack())
bindingOptions.push_back(TypeVariableOptions::TVO_CanBindToPack);
if (isPackExpansion())
bindingOptions.push_back(TypeVariableOptions::TVO_PackExpansion);
if (!bindingOptions.empty()) {
OS << " [can bind to: ";
interleave(bindingOptions, OS,
[&](TypeVariableOptions option) {
(OS << getTypeVariableOptions(option));},
", ");
OS << "]";
}
}
GenericTypeParamType *
TypeVariableType::Implementation::getGenericParameter() const {
return locator ? locator->getGenericParameter() : nullptr;
}
std::optional<ExprKind>
TypeVariableType::Implementation::getAtomicLiteralKind() const {
if (!locator || !locator->directlyAt<LiteralExpr>())
return std::nullopt;
auto kind = getAsExpr(locator->getAnchor())->getKind();
switch (kind) {
case ExprKind::IntegerLiteral:
case ExprKind::FloatLiteral:
case ExprKind::StringLiteral:
case ExprKind::BooleanLiteral:
case ExprKind::NilLiteral:
return kind;
default:
return std::nullopt;
}
}
bool TypeVariableType::Implementation::isClosureType() const {
if (!(locator && locator->getAnchor()))
return false;
return isExpr<ClosureExpr>(locator->getAnchor()) && locator->getPath().empty();
}
bool TypeVariableType::Implementation::isTapType() const {
return locator && locator->directlyAt<TapExpr>();
}
bool TypeVariableType::Implementation::isClosureParameterType() const {
if (!(locator && locator->getAnchor()))
return false;
return isExpr<ClosureExpr>(locator->getAnchor()) &&
locator->isLastElement<LocatorPathElt::TupleElement>();
}
bool TypeVariableType::Implementation::isClosureResultType() const {
if (!(locator && locator->getAnchor()))
return false;
return isExpr<ClosureExpr>(locator->getAnchor()) &&
locator->isLastElement<LocatorPathElt::ClosureResult>();
}
bool TypeVariableType::Implementation::isKeyPathType() const {
return locator && locator->isKeyPathType();
}
bool TypeVariableType::Implementation::isKeyPathRoot() const {
return locator && locator->isKeyPathRoot();
}
bool TypeVariableType::Implementation::isKeyPathValue() const {
return locator && locator->isKeyPathValue();
}
bool TypeVariableType::Implementation::isKeyPathSubscriptIndex() const {
return locator &&
locator->isLastElement<LocatorPathElt::KeyPathSubscriptIndex>();
}
bool TypeVariableType::Implementation::isSubscriptResultType() const {
if (!(locator && locator->getAnchor()))
return false;
if (!locator->isLastElement<LocatorPathElt::FunctionResult>())
return false;
if (isExpr<SubscriptExpr>(locator->getAnchor()))
return true;
auto *KP = getAsExpr<KeyPathExpr>(locator->getAnchor());
if (!KP)
return false;
auto componentLoc = locator->findFirst<LocatorPathElt::KeyPathComponent>();
if (!componentLoc)
return false;
auto &component = KP->getComponents()[componentLoc->getIndex()];
return component.getKind() == KeyPathExpr::Component::Kind::Subscript ||
component.getKind() ==
KeyPathExpr::Component::Kind::UnresolvedSubscript;
}
bool TypeVariableType::Implementation::isParameterPack() const {
return locator
&& locator->isForGenericParameter()
&& locator->getGenericParameter()->isParameterPack();
}
bool TypeVariableType::Implementation::isCodeCompletionToken() const {
return locator && locator->directlyAt<CodeCompletionExpr>();
}
bool TypeVariableType::Implementation::isOpaqueType() const {
if (!locator)
return false;
auto GP = locator->getLastElementAs<LocatorPathElt::GenericParameter>();
if (!GP)
return false;
if (auto *GPT = GP->getType()->getAs<GenericTypeParamType>())
return (GPT->getOpaqueDecl() != nullptr);
return false;
}
bool TypeVariableType::Implementation::isCollectionLiteralType() const {
return locator && (locator->directlyAt<ArrayExpr>() ||
locator->directlyAt<DictionaryExpr>());
}
void *operator new(size_t bytes, ConstraintSystem& cs,
size_t alignment) {
return cs.getAllocator().Allocate(bytes, alignment);
}
bool constraints::computeTupleShuffle(TupleType *fromTuple,
TupleType *toTuple,
SmallVectorImpl<unsigned> &sources) {
const unsigned unassigned = -1;
auto fromElts = fromTuple->getElements();
auto toElts = toTuple->getElements();
SmallVector<bool, 4> consumed(fromElts.size(), false);
sources.clear();
sources.assign(toElts.size(), unassigned);
// Match up any named elements.
for (unsigned i = 0, n = toElts.size(); i != n; ++i) {
const auto &toElt = toElts[i];
// Skip unnamed elements.
if (!toElt.hasName())
continue;
// Find the corresponding named element.
int matched = -1;
{
int index = 0;
for (auto field : fromElts) {
if (field.getName() == toElt.getName() && !consumed[index]) {
matched = index;
break;
}
++index;
}
}
if (matched == -1)
continue;
// Record this match.
sources[i] = matched;
consumed[matched] = true;
}
// Resolve any unmatched elements.
unsigned fromNext = 0, fromLast = fromElts.size();
auto skipToNextAvailableInput = [&] {
while (fromNext != fromLast && consumed[fromNext])
++fromNext;
};
skipToNextAvailableInput();
for (unsigned i = 0, n = toElts.size(); i != n; ++i) {
// Check whether we already found a value for this element.
if (sources[i] != unassigned)
continue;
// If there aren't any more inputs, we are done.
if (fromNext == fromLast) {
return true;
}
// Otherwise, assign this input to the next output element.
const auto &elt2 = toElts[i];
// Fail if the input element is named and we're trying to match it with
// something with a different label.
if (fromElts[fromNext].hasName() && elt2.hasName())
return true;
sources[i] = fromNext;
consumed[fromNext] = true;
skipToNextAvailableInput();
}
// Complain if we didn't reach the end of the inputs.
if (fromNext != fromLast) {
return true;
}
// If we got here, we should have claimed all the arguments.
assert(std::find(consumed.begin(), consumed.end(), false) == consumed.end());
return false;
}
Expr *ConstraintLocatorBuilder::trySimplifyToExpr() const {
SmallVector<LocatorPathElt, 4> pathBuffer;
auto anchor = getLocatorParts(pathBuffer);
// Locators are not guaranteed to have an anchor
// if constraint system is used to verify generic
// requirements.
if (!anchor.is<Expr *>())
return nullptr;
ArrayRef<LocatorPathElt> path = pathBuffer;
SourceRange range;
simplifyLocator(anchor, path, range);
return (path.empty() ? getAsExpr(anchor) : nullptr);
}
void ParentConditionalConformance::diagnoseConformanceStack(
DiagnosticEngine &diags, SourceLoc loc,
ArrayRef<ParentConditionalConformance> conformances) {
for (auto history : llvm::reverse(conformances)) {
diags.diagnose(loc, diag::requirement_implied_by_conditional_conformance,
history.ConformingType, history.Protocol->getDeclaredInterfaceType());
}
}
namespace {
/// Produce any additional syntactic diagnostics for a SyntacticElementTarget.
class SyntacticDiagnosticWalker final : public BaseDiagnosticWalker {
const SyntacticElementTarget &Target;
bool IsTopLevelExprStmt;
unsigned ExprDepth = 0;
SyntacticDiagnosticWalker(const SyntacticElementTarget &target,
bool isExprStmt)
: Target(target), IsTopLevelExprStmt(isExprStmt) {}
public:
static void check(const SyntacticElementTarget &target, bool isExprStmt) {
auto walker = SyntacticDiagnosticWalker(target, isExprStmt);
target.walk(walker);
}
PreWalkResult<Expr *> walkToExprPre(Expr *E) override {
// We only want to call the diagnostic logic for the top-level expression,
// since the underlying logic will visit each sub-expression. We want to
// continue walking however to diagnose any child statements in e.g
// closures.
if (ExprDepth == 0) {
auto isExprStmt = (E == Target.getAsExpr()) ? IsTopLevelExprStmt : false;
performSyntacticExprDiagnostics(E, Target.getDeclContext(), isExprStmt);
}
ExprDepth += 1;
return Action::Continue(E);
}
PostWalkResult<Expr *> walkToExprPost(Expr *E) override {
assert(ExprDepth > 0);
ExprDepth -= 1;
return Action::Continue(E);
}
PreWalkResult<Stmt *> walkToStmtPre(Stmt *stmt) override {
performStmtDiagnostics(stmt, Target.getDeclContext());
return Action::Continue(stmt);
}
PreWalkAction walkToTypeReprPre(TypeRepr *typeRepr) override {
return Action::SkipNode();
}
PreWalkAction walkToParameterListPre(ParameterList *params) override {
return Action::SkipNode();
}
};
} // end anonymous namespace
void constraints::performSyntacticDiagnosticsForTarget(
const SyntacticElementTarget &target, bool isExprStmt) {
SyntacticDiagnosticWalker::check(target, isExprStmt);
}
#pragma mark High-level entry points
Type TypeChecker::typeCheckExpression(Expr *&expr, DeclContext *dc,
ContextualTypeInfo contextualInfo,
TypeCheckExprOptions options) {
SyntacticElementTarget target(
expr, dc, contextualInfo.purpose, contextualInfo.getType(),
options.contains(TypeCheckExprFlags::IsDiscarded));
auto resultTarget = typeCheckExpression(target, options);
if (!resultTarget) {
expr = target.getAsExpr();
return Type();
}
expr = resultTarget->getAsExpr();
return expr->getType();
}
/// FIXME: In order to remote this function both \c FrontendStatsTracer
/// and \c PrettyStackTrace* have to be updated to accept `ASTNode`
// instead of each individual syntactic element types.
std::optional<SyntacticElementTarget>
TypeChecker::typeCheckExpression(SyntacticElementTarget &target,
TypeCheckExprOptions options,
DiagnosticTransaction *diagnosticTransaction) {
DeclContext *dc = target.getDeclContext();
auto &Context = dc->getASTContext();
FrontendStatsTracer StatsTracer(Context.Stats, "typecheck-expr",
target.getAsExpr());
PrettyStackTraceExpr stackTrace(Context, "type-checking", target.getAsExpr());
return typeCheckTarget(target, options, diagnosticTransaction);
}
std::optional<SyntacticElementTarget>
TypeChecker::typeCheckTarget(SyntacticElementTarget &target,
TypeCheckExprOptions options,
DiagnosticTransaction *diagnosticTransaction) {
auto errorResult = [&]() -> std::optional<SyntacticElementTarget> {
// Fill in ErrorTypes for the target if we can.
if (!options.contains(TypeCheckExprFlags::AvoidInvalidatingAST))
target.markInvalid();
return std::nullopt;
};
DeclContext *dc = target.getDeclContext();
auto &Context = dc->getASTContext();
PrettyStackTraceLocation stackTrace(Context, "type-checking-target",
target.getLoc());
// First, pre-check the target, validating any types that occur in the
// expression and folding sequence expressions.
if (ConstraintSystem::preCheckTarget(target))
return errorResult();
// Check whether given target has a code completion token which requires
// special handling. Returns true if handled, in which case we've already
// type-checked it for completion, and don't need the solution applied.
if (Context.CompletionCallback &&
typeCheckForCodeCompletion(target, /*needsPrecheck*/ false,
[&](const constraints::Solution &S) {
Context.CompletionCallback->sawSolution(S);
}))
return std::nullopt;
// Construct a constraint system from this expression.
ConstraintSystemOptions csOptions = ConstraintSystemFlags::AllowFixes;
if (DiagnosticSuppression::isEnabled(Context.Diags))
csOptions |= ConstraintSystemFlags::SuppressDiagnostics;
if (options.contains(TypeCheckExprFlags::DisableMacroExpansions))
csOptions |= ConstraintSystemFlags::DisableMacroExpansions;
ConstraintSystem cs(dc, csOptions, diagnosticTransaction);
if (auto *expr = target.getAsExpr()) {
// Tell the constraint system what the contextual type is. This informs
// diagnostics and is a hint for various performance optimizations.
cs.setContextualInfo(expr, target.getExprContextualTypeInfo());
// Try to shrink the system by reducing disjunction domains. This
// goes through every sub-expression and generate its own sub-system, to
// try to reduce the domains of those subexpressions.
cs.shrink(expr);
target.setExpr(expr);
}
// If the client can handle unresolved type variables, leave them in the
// system.
auto allowFreeTypeVariables = FreeTypeVariableBinding::Disallow;
// Attempt to solve the constraint system.
auto viable = cs.solve(target, allowFreeTypeVariables);
if (!viable)
return errorResult();
// Apply this solution to the constraint system.
// FIXME: This shouldn't be necessary.
auto &solution = (*viable)[0];
cs.replaySolution(solution);
// Apply the solution to the expression.
auto resultTarget = cs.applySolution(solution, target);
if (!resultTarget) {
// Failure already diagnosed, above, as part of applying the solution.
return errorResult();
}
// Unless the client has disabled them, perform syntactic checks on the
// expression now.
if (!cs.shouldSuppressDiagnostics()) {
bool isExprStmt = options.contains(TypeCheckExprFlags::IsExprStmt);
performSyntacticDiagnosticsForTarget(*resultTarget, isExprStmt);
}
return *resultTarget;
}
Type TypeChecker::typeCheckParameterDefault(Expr *&defaultValue,
DeclContext *DC, Type paramType,
bool isAutoClosure,
bool atCallerSide) {
// During normal type checking we don't type check the parameter default if
// the param has an error type. For code completion, we also type check the
// parameter default because it might contain the code completion token.
assert(paramType &&
(!paramType->hasError() || DC->getASTContext().CompletionCallback));
auto &ctx = DC->getASTContext();
// First, let's try to type-check default expression using interface
// type of the parameter, if that succeeds - we are done.
SyntacticElementTarget defaultExprTarget(
defaultValue, DC,
isAutoClosure ? CTP_AutoclosureDefaultParameter : CTP_DefaultParameter,
paramType, /*isDiscarded=*/false);
auto paramInterfaceTy = paramType->mapTypeOutOfContext();
{
// Buffer all of the diagnostics produced by \c typeCheckExpression
// since in some cases we need to try type-checking again with a
// different contextual type, see below.
DiagnosticTransaction diagnostics(ctx.Diags);
TypeCheckExprOptions options;
// Avoid invalidating the AST since we'll fall through and try to type-check
// with an archetype contextual type opened. Note we also don't need to call
// `markInvalid` for the target below since we'll replace the expression
// with an ErrorExpr on failure anyway.
options |= TypeCheckExprFlags::AvoidInvalidatingAST;
// Expand macro expansion expression at caller side only
if (!atCallerSide && isa<MacroExpansionExpr>(defaultValue)) {
options |= TypeCheckExprFlags::DisableMacroExpansions;
}
// First, let's try to type-check default expression using
// archetypes, which guarantees that it would work for any
// substitution of the generic parameter (if they are involved).
if (auto result = typeCheckExpression(
defaultExprTarget, options, &diagnostics)) {
defaultValue = result->getAsExpr();
return defaultValue->getType();
}
// Caller-side defaults are always type-checked based on the concrete
// type of the argument deduced at a particular call site.
if (isa<MagicIdentifierLiteralExpr>(defaultValue))
return Type();
// Parameter type doesn't have any generic parameters mentioned
// in it, so there is nothing to infer.
if (!paramInterfaceTy->hasTypeParameter())
return Type();
// Ignore any diagnostics emitted by the original type-check.
diagnostics.abort();
}
// Let's see whether it would be possible to use default expression
// for generic parameter inference.
//
// First, let's check whether:
// - Parameter type is a generic parameter; and
// - It's only used in the current position in the parameter list
// or result. This check makes sure that generic argument
// could only come from an explicit argument or this expression.
//
// If both of aforementioned conditions are true, let's attempt
// to open generic parameter and infer the type of this default
// expression.
SmallVector<OpenedType, 4> genericParameters;
ConstraintSystemOptions options;
options |= ConstraintSystemFlags::AllowFixes;
ConstraintSystem cs(DC, options);
auto *locator = cs.getConstraintLocator(
defaultValue, LocatorPathElt::ContextualType(
defaultExprTarget.getExprContextualTypePurpose()));
auto findParam = [&](GenericTypeParamType *GP) -> TypeVariableType * {
for (auto pair : genericParameters) {
if (pair.first->isEqual(GP))
return pair.second;
}
return nullptr;
};
// Find and open all of the generic parameters used by the parameter
// and replace them with type variables.
auto contextualTy = paramInterfaceTy.transformRec([&](Type type) -> std::optional<Type> {
assert(!type->is<UnboundGenericType>());
if (auto *GP = type->getAs<GenericTypeParamType>()) {
if (auto *typeVar = findParam(GP))
return typeVar;
auto *typeVar = cs.openGenericParameter(GP, locator);
genericParameters.emplace_back(GP, typeVar);
return typeVar;
}
return std::nullopt;
});
auto containsTypes = [&](Type type) {
return type.findIf([&](Type nested) -> bool {
if (auto *GP = nested->getAs<GenericTypeParamType>())
return findParam(GP);
return false;
});
};
auto containsGenericParamsExcluding = [&](Type type) -> bool {
return type.findIf([&](Type type) -> bool {
if (auto *GP = type->getAs<GenericTypeParamType>())
return !findParam(GP);
return false;
});
};
// Anchor of this default expression i.e. function, subscript
// or enum case.
auto *anchor = cast<ValueDecl>(DC->getParent()->getAsDecl());
// Check whether generic parameters are only mentioned once in
// the anchor's signature.
{
auto anchorTy = anchor->getInterfaceType()->castTo<GenericFunctionType>();
// Reject if generic parameters are used in multiple different positions
// in the parameter list.
llvm::SmallVector<unsigned, 2> affectedParams;
for (unsigned i : indices(anchorTy->getParams())) {
const auto ¶m = anchorTy->getParams()[i];
if (containsTypes(param.getPlainType()))
affectedParams.push_back(i);
}
if (affectedParams.size() > 1) {
SmallString<32> paramBuf;
llvm::raw_svector_ostream params(paramBuf);
interleave(
affectedParams, [&](const unsigned index) { params << "#" << index; },
[&] { params << ", "; });
ctx.Diags.diagnose(
defaultValue->getLoc(),
diag::
cannot_default_generic_parameter_inferrable_from_another_parameter,
paramInterfaceTy, params.str());
return Type();
}
}
auto signature = DC->getGenericSignatureOfContext();
assert(signature && "generic parameter without signature?");
auto *requirementBaseLocator = cs.getConstraintLocator(
locator, LocatorPathElt::OpenedGeneric(signature));
// Let's check all of the requirements this parameter is involved in,
// If it's connected to any other generic types (directly or through
// a dependent member type), that means it could be inferred through
// them e.g. `T: X.Y` or `T == U`.
{
auto recordRequirement = [&](unsigned index, Requirement requirement,
ConstraintLocator *locator) {
cs.openGenericRequirement(DC->getParent(), signature, index, requirement,
/*skipSelfProtocolConstraint=*/false, locator,
[&](Type type) -> Type {
return cs.openType(type, genericParameters,
locator);
});
};
auto diagnoseInvalidRequirement = [&](Requirement requirement) {
SmallString<32> reqBuf;
llvm::raw_svector_ostream req(reqBuf);
requirement.print(req, PrintOptions());
ctx.Diags.diagnose(
defaultValue->getLoc(),
diag::cannot_default_generic_parameter_invalid_requirement,
paramInterfaceTy, req.str());
};
auto requirements = signature.getRequirements();
for (unsigned reqIdx = 0; reqIdx != requirements.size(); ++reqIdx) {
auto &requirement = requirements[reqIdx];
switch (requirement.getKind()) {
case RequirementKind::SameShape:
llvm_unreachable("Same-shape requirement not supported here");
case RequirementKind::SameType: {
auto lhsTy = requirement.getFirstType();
auto rhsTy = requirement.getSecondType();
// Unrelated requirement.
if (!containsTypes(lhsTy) &&
!containsTypes(rhsTy))
continue;
// If both sides are dependent members, that's okay because types
// don't flow from member to the base e.g. `T.Element == U.Element`.
if (lhsTy->is<DependentMemberType>() &&
rhsTy->is<DependentMemberType>())
continue;
// Allow a subset of generic same-type requirements that only mention
// "in scope" generic parameters e.g. `T.X == Int` or `T == U.Z`
if (!containsGenericParamsExcluding(lhsTy) &&
!containsGenericParamsExcluding(rhsTy)) {
recordRequirement(reqIdx, requirement, requirementBaseLocator);
continue;
}
// If there is a same-type constraint that involves out of scope
// generic parameters mixed with in-scope ones, fail the type-check
// since the type could be inferred through other positions.
{
diagnoseInvalidRequirement(requirement);
return Type();
}
}
case RequirementKind::Conformance:
case RequirementKind::Superclass:
case RequirementKind::Layout:
auto adheringTy = requirement.getFirstType();
// Unrelated requirement.
if (!containsTypes(adheringTy))
continue;
// If adhering type has a mix or in- and out-of-scope parameters
// mentioned we need to diagnose.
if (containsGenericParamsExcluding(adheringTy)) {
diagnoseInvalidRequirement(requirement);
return Type();
}
if (requirement.getKind() == RequirementKind::Superclass) {
auto superclassTy = requirement.getSecondType();
if (containsGenericParamsExcluding(superclassTy)) {
diagnoseInvalidRequirement(requirement);
return Type();
}
}
recordRequirement(reqIdx, requirement, requirementBaseLocator);
break;
}
}
}
defaultExprTarget.setExprConversionType(contextualTy);
cs.setContextualInfo(defaultValue,
defaultExprTarget.getExprContextualTypeInfo());
auto viable = cs.solve(defaultExprTarget, FreeTypeVariableBinding::Disallow);
if (!viable)
return Type();
auto &solution = (*viable)[0];
cs.replaySolution(solution);
if (auto result = cs.applySolution(solution, defaultExprTarget)) {
// Perform syntactic diagnostics on the type-checked target.
performSyntacticDiagnosticsForTarget(*result, /*isExprStmt=*/false);
defaultValue = result->getAsExpr();
return defaultValue->getType();
}
return Type();
}
bool TypeChecker::typeCheckBinding(Pattern *&pattern, Expr *&initializer,
DeclContext *DC, Type patternType,
PatternBindingDecl *PBD,
unsigned patternNumber,
TypeCheckExprOptions options) {
SyntacticElementTarget target =
PBD ? SyntacticElementTarget::forInitialization(
initializer, patternType, PBD, patternNumber,
/*bindPatternVarsOneWay=*/false)
: SyntacticElementTarget::forInitialization(
initializer, DC, patternType, pattern,
/*bindPatternVarsOneWay=*/false);
// Type-check the initializer.
auto resultTarget = typeCheckExpression(target, options);
if (resultTarget) {
initializer = resultTarget->getAsExpr();
pattern = resultTarget->getInitializationPattern();
return false;
}
auto &Context = DC->getASTContext();
initializer = target.getAsExpr();
if (!initializer->getType())
initializer->setType(ErrorType::get(Context));
// Assign error types to the pattern and its variables, to prevent it from
// being referenced by the constraint system.
if (patternType->hasUnresolvedType() ||
patternType->hasPlaceholder() ||
patternType->hasUnboundGenericType()) {
pattern->setType(ErrorType::get(Context));
}
pattern->forEachVariable([&](VarDecl *var) {
// Don't change the type of a variable that we've been able to
// compute a type for.
if (var->hasInterfaceType() &&
!var->getTypeInContext()->hasUnboundGenericType() &&
!var->isInvalid())
return;
var->setInvalid();
});
return true;
}
bool TypeChecker::typeCheckPatternBinding(PatternBindingDecl *PBD,
unsigned patternNumber,
Type patternType,
TypeCheckExprOptions options) {
Pattern *pattern = PBD->getPattern(patternNumber);
Expr *init = PBD->getInit(patternNumber);
// Enter an initializer context if necessary.
PatternBindingInitializer *initContext = PBD->getInitContext(patternNumber);
DeclContext *DC = initContext ? initContext : PBD->getDeclContext();
// If we weren't given a pattern type, compute one now.
if (!patternType) {
if (pattern->hasType())
patternType = pattern->getType();
else {
auto contextualPattern = ContextualPattern::forRawPattern(pattern, DC);
patternType = typeCheckPattern(contextualPattern);
}
if (patternType->hasError()) {
PBD->setInvalid();
return true;
}
}
bool hadError = TypeChecker::typeCheckBinding(pattern, init, DC, patternType,
PBD, patternNumber, options);
if (!init) {
PBD->setInvalid();
return true;
}
PBD->setPattern(patternNumber, pattern);
PBD->setInit(patternNumber, init);
if (hadError)
PBD->setInvalid();
PBD->setInitializerChecked(patternNumber);
return hadError;
}
bool TypeChecker::typeCheckForEachPreamble(DeclContext *dc, ForEachStmt *stmt) {
auto &Context = dc->getASTContext();
FrontendStatsTracer statsTracer(Context.Stats, "typecheck-for-each", stmt);
PrettyStackTraceStmt stackTrace(Context, "type-checking-for-each", stmt);
auto failed = [&]() -> bool {
// Invalidate the pattern and the var decl.
stmt->getPattern()->setType(ErrorType::get(Context));
stmt->getPattern()->forEachVariable([&](VarDecl *var) {
if (var->hasInterfaceType() && !var->isInvalid())
return;
var->setInvalid();
});
return true;
};
auto target = SyntacticElementTarget::forForEachPreamble(stmt, dc);
if (!typeCheckTarget(target))
return failed();
if (auto *where = stmt->getWhere()) {
auto boolType = dc->getASTContext().getBoolType();
if (!boolType)
return failed();
SyntacticElementTarget whereClause(where, dc, {boolType, CTP_Condition},
/*isDiscarded=*/false);
auto result = typeCheckTarget(whereClause);
if (!result)
return true;
stmt->setWhere(result->getAsExpr());
}
// Check to see if the sequence expr is throwing (in async context),
// if so require the stmt to have a `try`.
if (diagnoseUnhandledThrowsInAsyncContext(dc, stmt))
return failed();
return false;
}
bool TypeChecker::typeCheckCondition(Expr *&expr, DeclContext *dc) {
// If this expression is already typechecked and has type Bool, then just
// re-typecheck it.
if (expr->getType() && expr->getType()->isBool()) {
auto resultTy =
TypeChecker::typeCheckExpression(expr, dc);
return !resultTy;
}
auto *boolDecl = dc->getASTContext().getBoolDecl();
if (!boolDecl)
return true;
auto resultTy = TypeChecker::typeCheckExpression(
expr, dc,
/*contextualInfo=*/{boolDecl->getDeclaredInterfaceType(), CTP_Condition});
return !resultTy;
}
/// Find the `~=` operator that can compare an expression inside a pattern to a
/// value of a given type.
bool TypeChecker::typeCheckExprPattern(ExprPattern *EP, DeclContext *DC,
Type rhsType) {
auto &Context = DC->getASTContext();
FrontendStatsTracer StatsTracer(Context.Stats,
"typecheck-expr-pattern", EP);
PrettyStackTracePattern stackTrace(Context, "type-checking", EP);
EP->getMatchVar()->setInterfaceType(rhsType->mapTypeOutOfContext());
// Check the expression as a condition.
auto target = SyntacticElementTarget::forExprPattern(EP);
auto result = typeCheckExpression(target);
if (!result)
return true;
// Save the type-checked expression in the pattern.
EP->setMatchExpr(result->getAsExpr());
// Set the type on the pattern.
EP->setType(rhsType);
return false;
}
static Type openTypeParameter(ConstraintSystem &cs,
Type interfaceTy,
GenericEnvironment *env,
llvm::DenseMap<SubstitutableType *, TypeVariableType *> &types) {
if (auto *memberTy = interfaceTy->getAs<DependentMemberType>()) {
return DependentMemberType::get(
openTypeParameter(cs, memberTy->getBase(), env, types),
memberTy->getAssocType());
}
auto *paramTy = interfaceTy->castTo<GenericTypeParamType>();
auto archetypeTy = env->mapTypeIntoContext(paramTy)->castTo<ArchetypeType>();
auto found = types.find(archetypeTy);
if (found != types.end())
return found->second;
auto locator = cs.getConstraintLocator({});
auto replacement = cs.createTypeVariable(locator,
TVO_CanBindToNoEscape);
// FIXME: This doesn't capture all requirements imposed on the archetype!
// We really need to be opening the generic signature instead.
if (auto superclass = archetypeTy->getSuperclass()) {
cs.addConstraint(ConstraintKind::Subtype, replacement,
superclass, locator);
}
// If we have a Sendable or SendableMetatype conformance requirement,
// we have to prohibit nonisolated conformances.
bool prohibitNonisolated = false;
for (auto proto : archetypeTy->getConformsTo()) {
if (proto->isSpecificProtocol(KnownProtocolKind::Sendable) ||
proto->isSpecificProtocol(KnownProtocolKind::SendableMetatype)) {
prohibitNonisolated = true;
break;
}
}
for (auto proto : archetypeTy->getConformsTo()) {
auto kind = prohibitNonisolated ? ConstraintKind::NonisolatedConformsTo
: ConstraintKind::ConformsTo;