forked from swiftlang/swift
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathTypeChecker.h
2230 lines (1923 loc) · 89 KB
/
TypeChecker.h
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
//===--- TypeChecker.h - Type Checking Class --------------------*- C++ -*-===//
//
// 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
//
//===----------------------------------------------------------------------===//
//
// This file defines the TypeChecking class.
//
//===----------------------------------------------------------------------===//
#ifndef TYPECHECKING_H
#define TYPECHECKING_H
#include "swift/AST/ASTContext.h"
#include "swift/AST/AccessScope.h"
#include "swift/AST/AnyFunctionRef.h"
#include "swift/AST/Availability.h"
#include "swift/AST/DiagnosticsSema.h"
#include "swift/AST/KnownProtocols.h"
#include "swift/AST/LazyResolver.h"
#include "swift/AST/NameLookup.h"
#include "swift/AST/TypeRefinementContext.h"
#include "swift/Parse/Lexer.h"
#include "swift/Basic/OptionSet.h"
#include "swift/Config.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/TinyPtrVector.h"
#include <functional>
namespace swift {
class GenericSignatureBuilder;
class NominalTypeDecl;
class NormalProtocolConformance;
class TopLevelContext;
class TypeChecker;
class TypeResolution;
class TypeResolutionOptions;
class TypoCorrectionResults;
class ExprPattern;
class SynthesizedFunction;
enum class TypeResolutionStage : uint8_t;
namespace constraints {
enum class ConstraintKind : char;
enum class SolutionKind : char;
class ConstraintSystem;
class Solution;
}
/// \brief A mapping from substitutable types to the protocol-conformance
/// mappings for those types.
using ConformanceMap =
llvm::DenseMap<SubstitutableType *, SmallVector<ProtocolConformance *, 2>>;
/// Special-case type checking semantics for certain declarations.
enum class DeclTypeCheckingSemantics {
/// A normal declaration.
Normal,
/// The type(of:) declaration, which performs a "dynamic type" operation,
/// with different behavior for existential and non-existential arguments.
TypeOf,
/// The withoutActuallyEscaping(_:do:) declaration, which makes a nonescaping
/// closure temporarily escapable.
WithoutActuallyEscaping,
/// The _openExistential(_:do:) declaration, which extracts the value inside
/// an existential and passes it as a value of its own dynamic type.
OpenExistential,
};
/// The result of name lookup.
class LookupResult {
private:
/// The set of results found.
SmallVector<LookupResultEntry, 4> Results;
size_t IndexOfFirstOuterResult = 0;
public:
LookupResult() {}
explicit LookupResult(const SmallVectorImpl<LookupResultEntry> &Results,
size_t indexOfFirstOuterResult)
: Results(Results.begin(), Results.end()),
IndexOfFirstOuterResult(indexOfFirstOuterResult) {}
using iterator = SmallVectorImpl<LookupResultEntry>::iterator;
iterator begin() { return Results.begin(); }
iterator end() {
return Results.begin() + IndexOfFirstOuterResult;
}
unsigned size() const { return innerResults().size(); }
bool empty() const { return innerResults().empty(); }
ArrayRef<LookupResultEntry> innerResults() const {
return llvm::makeArrayRef(Results).take_front(IndexOfFirstOuterResult);
}
ArrayRef<LookupResultEntry> outerResults() const {
return llvm::makeArrayRef(Results).drop_front(IndexOfFirstOuterResult);
}
const LookupResultEntry& operator[](unsigned index) const {
return Results[index];
}
LookupResultEntry front() const { return innerResults().front(); }
LookupResultEntry back() const { return innerResults().back(); }
/// Add a result to the set of results.
void add(LookupResultEntry result, bool isOuter) {
Results.push_back(result);
if (!isOuter) {
IndexOfFirstOuterResult++;
assert(IndexOfFirstOuterResult == Results.size() &&
"found an outer result before an inner one");
} else {
assert(IndexOfFirstOuterResult > 0 &&
"found outer results without an inner one");
}
}
void clear() { Results.clear(); }
/// Determine whether the result set is nonempty.
explicit operator bool() const {
return !empty();
}
TypeDecl *getSingleTypeResult() const {
if (size() != 1)
return nullptr;
return dyn_cast<TypeDecl>(front().getValueDecl());
}
/// Filter out any results that aren't accepted by the given predicate.
void
filter(llvm::function_ref<bool(LookupResultEntry, /*isOuter*/ bool)> pred);
/// Shift down results by dropping inner results while keeping outer
/// results (if any), the innermost of which are recogized as inner
/// results afterwards.
void shiftDownResults();
};
/// An individual result of a name lookup for a type.
struct LookupTypeResultEntry {
TypeDecl *Member;
Type MemberType;
/// The associated type that the Member/MemberType were inferred for, but only
/// if inference happened when creating this entry.
AssociatedTypeDecl *InferredAssociatedType;
};
/// The result of name lookup for types.
class LookupTypeResult {
/// The set of results found.
SmallVector<LookupTypeResultEntry, 4> Results;
friend class TypeChecker;
public:
using iterator = SmallVectorImpl<LookupTypeResultEntry>::iterator;
iterator begin() { return Results.begin(); }
iterator end() { return Results.end(); }
unsigned size() const { return Results.size(); }
LookupTypeResultEntry operator[](unsigned index) const {
return Results[index];
}
LookupTypeResultEntry front() const { return Results.front(); }
LookupTypeResultEntry back() const { return Results.back(); }
/// Add a result to the set of results.
void addResult(LookupTypeResultEntry result) { Results.push_back(result); }
/// \brief Determine whether this result set is ambiguous.
bool isAmbiguous() const {
return Results.size() > 1;
}
/// Determine whether the result set is nonempty.
explicit operator bool() const {
return !Results.empty();
}
};
/// This specifies the purpose of the contextual type, when specified to
/// typeCheckExpression. This is used for diagnostic generation to produce more
/// specified error messages when the conversion fails.
///
enum ContextualTypePurpose {
CTP_Unused, ///< No contextual type is specified.
CTP_Initialization, ///< Pattern binding initialization.
CTP_ReturnStmt, ///< Value specified to a 'return' statement.
CTP_YieldByValue, ///< By-value yield operand.
CTP_YieldByReference, ///< By-reference yield operand.
CTP_ThrowStmt, ///< Value specified to a 'throw' statement.
CTP_EnumCaseRawValue, ///< Raw value specified for "case X = 42" in enum.
CTP_DefaultParameter, ///< Default value in parameter 'foo(a : Int = 42)'.
CTP_CalleeResult, ///< Constraint is placed on the result of a callee.
CTP_CallArgument, ///< Call to function or operator requires type.
CTP_ClosureResult, ///< Closure result expects a specific type.
CTP_ArrayElement, ///< ArrayExpr wants elements to have a specific type.
CTP_DictionaryKey, ///< DictionaryExpr keys should have a specific type.
CTP_DictionaryValue, ///< DictionaryExpr values should have a specific type.
CTP_CoerceOperand, ///< CoerceExpr operand coerced to specific type.
CTP_AssignSource, ///< AssignExpr source operand coerced to result type.
CTP_CannotFail, ///< Conversion can never fail. abort() if it does.
};
/// Flags that can be used to control name lookup.
enum class TypeCheckExprFlags {
/// Whether we know that the result of the expression is discarded. This
/// disables constraints forcing an lvalue result to be loadable.
IsDiscarded = 0x01,
/// Whether the client wants to disable the structural syntactic restrictions
/// that we force for style or other reasons.
DisableStructuralChecks = 0x02,
/// Set if the client wants diagnostics suppressed.
SuppressDiagnostics = 0x04,
/// If set, the client wants a best-effort solution to the constraint system,
/// but can tolerate a solution where all of the constraints are solved, but
/// not all type variables have been determined. In this case, the constraint
/// system is not applied to the expression AST, but the ConstraintSystem is
/// left in-tact.
AllowUnresolvedTypeVariables = 0x08,
/// If set, the 'convertType' specified to typeCheckExpression should not
/// produce a conversion constraint, but it should be used to guide the
/// solution in terms of performance optimizations of the solver, and in terms
/// of guiding diagnostics.
ConvertTypeIsOnlyAHint = 0x10,
/// If set, this expression isn't embedded in a larger expression or
/// statement. This should only be used for syntactic restrictions, and should
/// not affect type checking itself.
IsExprStmt = 0x20,
/// If set, this expression is being re-type checked as part of diagnostics,
/// and so we should not visit bodies of non-single expression closures.
SkipMultiStmtClosures = 0x40,
/// If set, don't apply a solution.
SkipApplyingSolution = 0x100,
/// This is an inout yield.
IsInOutYield = 0x200,
/// If set, a conversion constraint should be specfied so that the result of
/// the expression is an optional type.
ExpressionTypeMustBeOptional = 0x400,
};
using TypeCheckExprOptions = OptionSet<TypeCheckExprFlags>;
inline TypeCheckExprOptions operator|(TypeCheckExprFlags flag1,
TypeCheckExprFlags flag2) {
return TypeCheckExprOptions(flag1) | flag2;
}
/// Flags that can be used to control name lookup.
enum class NameLookupFlags {
/// Whether we know that this lookup is always a private dependency.
KnownPrivate = 0x01,
/// Whether name lookup should be able to find protocol members.
ProtocolMembers = 0x02,
/// Whether we should map the requirement to the witness if we
/// find a protocol member and the base type is a concrete type.
///
/// If this is not set but ProtocolMembers is set, we will
/// find protocol extension members, but not protocol requirements
/// that do not yet have a witness (such as inferred associated
/// types, or witnesses for derived conformances).
PerformConformanceCheck = 0x04,
/// Whether to perform 'dynamic' name lookup that finds @objc
/// members of any class or protocol.
DynamicLookup = 0x08,
/// Whether to ignore access control for this lookup, allowing inaccessible
/// results to be returned.
IgnoreAccessControl = 0x10,
/// Whether to include results from outside the innermost scope that has a
/// result.
IncludeOuterResults = 0x20,
};
/// A set of options that control name lookup.
using NameLookupOptions = OptionSet<NameLookupFlags>;
inline NameLookupOptions operator|(NameLookupFlags flag1,
NameLookupFlags flag2) {
return NameLookupOptions(flag1) | flag2;
}
/// Default options for member name lookup.
const NameLookupOptions defaultMemberLookupOptions
= NameLookupFlags::ProtocolMembers |
NameLookupFlags::PerformConformanceCheck;
/// Default options for constructor lookup.
const NameLookupOptions defaultConstructorLookupOptions
= NameLookupFlags::ProtocolMembers |
NameLookupFlags::PerformConformanceCheck;
/// Default options for member type lookup.
const NameLookupOptions defaultMemberTypeLookupOptions
= NameLookupFlags::ProtocolMembers |
NameLookupFlags::PerformConformanceCheck;
/// Default options for unqualified name lookup.
const NameLookupOptions defaultUnqualifiedLookupOptions
= NameLookupFlags::ProtocolMembers |
NameLookupFlags::PerformConformanceCheck;
/// Describes the result of comparing two entities, of which one may be better
/// or worse than the other, or they are unordered.
enum class Comparison {
/// Neither entity is better than the other.
Unordered,
/// The first entity is better than the second.
Better,
/// The first entity is worse than the second.
Worse
};
/// Specify how we handle the binding of underconstrained (free) type variables
/// within a solution to a constraint system.
enum class FreeTypeVariableBinding {
/// Disallow any binding of such free type variables.
Disallow,
/// Allow the free type variables to persist in the solution.
Allow,
/// Bind the type variables to UnresolvedType to represent the ambiguity.
UnresolvedType
};
/// An abstract interface that can interact with the type checker during
/// the type checking of a particular expression.
class ExprTypeCheckListener {
public:
virtual ~ExprTypeCheckListener();
/// Callback invoked once the constraint system has been constructed.
///
/// \param cs The constraint system that has been constructed.
///
/// \param expr The pre-checked expression from which the constraint system
/// was generated.
///
/// \returns true if an error occurred that is not itself part of the
/// 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.
///
/// 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 *appliedSolution(constraints::Solution &solution,
Expr *expr);
};
/// A conditional conformance that implied some other requirements. That is, \c
/// ConformingType conforming to \c Protocol may have required additional
/// requirements to be satisfied.
///
/// This is designed to be used in a stack of such requirements, which can be
/// formatted with \c diagnoseConformanceStack.
struct ParentConditionalConformance {
Type ConformingType;
ProtocolType *Protocol;
/// Format the stack \c conformances as a series of notes that trace a path of
/// conditional conformances that lead to some other failing requirement (that
/// is not in \c conformances).
///
/// The end of \c conformances is the active end of the stack, i.e. \c
/// conformances[0] is a conditional conformance that requires \c
/// conformances[1], etc.
static void
diagnoseConformanceStack(DiagnosticEngine &diags, SourceLoc location,
ArrayRef<ParentConditionalConformance> conformances);
};
/// An abstract interface that is used by `checkGenericArguments`.
class GenericRequirementsCheckListener {
public:
virtual ~GenericRequirementsCheckListener();
/// Callback invoked before trying to check generic requirement placed
/// between given types. Note: if either of the types assigned to the
/// requirement is generic parameter or dependent member, this callback
/// method is going to get their substitutions.
///
/// \param kind The kind of generic requirement to check.
///
/// \param first The left-hand side type assigned to the requirement,
/// possibly represented by its generic substitute.
///
/// \param second The right-hand side type assigned to the requirement,
/// possibly represented by its generic substitute.
///
///
/// \returns true if it's ok to validate requirement, false otherwise.
virtual bool shouldCheck(RequirementKind kind, Type first, Type second);
/// Callback to report the result of a satisfied conformance requirement.
///
/// \param depTy The dependent type, from the signature.
/// \param replacementTy The type \c depTy was replaced with.
/// \param conformance The conformance itself.
virtual void satisfiedConformance(Type depTy, Type replacementTy,
ProtocolConformanceRef conformance);
/// Callback to diagnose problem with unsatisfied generic requirement.
///
/// \param req The unsatisfied generic requirement.
///
/// \param first The left-hand side type assigned to the requirement,
/// possibly represented by its generic substitute.
///
/// \param second The right-hand side type assigned to the requirement,
/// possibly represented by its generic substitute.
///
/// \returns true if problem has been diagnosed, false otherwise.
virtual bool diagnoseUnsatisfiedRequirement(
const Requirement &req, Type first, Type second,
ArrayRef<ParentConditionalConformance> parents);
};
/// The result of `checkGenericRequirement`.
enum class RequirementCheckResult {
Success, Failure, SubstitutionFailure
};
/// Flags that control protocol conformance checking.
enum class ConformanceCheckFlags {
/// Whether we're performing the check from within an expression.
InExpression = 0x01,
/// Whether we will be using the conformance in the AST.
///
/// This implies that the conformance will have to be complete.
Used = 0x02,
/// Whether to suppress dependency tracking entirely.
///
/// FIXME: This deals with some oddities with the
/// _ObjectiveCBridgeable conformances.
SuppressDependencyTracking = 0x04,
/// Whether to skip the check for any conditional conformances.
///
/// When set, the caller takes responsibility for any
/// conditional requirements required for the conformance to be
/// correctly used. Otherwise (the default), all of the conditional
/// requirements will be checked.
SkipConditionalRequirements = 0x08,
/// Whether to require that the conditional requirements have been computed.
///
/// When set, if the conditional requirements aren't available, they are just
/// skipped, and the caller is responsible for detecting and handling this
/// case (likely via another call to getConditionalRequirementsIfAvailable).
AllowUnavailableConditionalRequirements = 0x10,
};
/// Options that control protocol conformance checking.
using ConformanceCheckOptions = OptionSet<ConformanceCheckFlags>;
inline ConformanceCheckOptions operator|(ConformanceCheckFlags lhs,
ConformanceCheckFlags rhs) {
return ConformanceCheckOptions(lhs) | rhs;
}
/// Describes the kind of checked cast operation being performed.
enum class CheckedCastContextKind {
/// None: we're just establishing how to perform the checked cast. This
/// is useful when we don't care to produce any diagnostics.
None,
/// A forced cast, with "as!".
ForcedCast,
/// A conditional cast, with "as?".
ConditionalCast,
/// An "is" expression.
IsExpr,
/// An "is" pattern.
IsPattern,
/// An enum-element pattern.
EnumElementPattern,
};
/// The Swift type checker, which takes a parsed AST and performs name binding,
/// type checking, and semantic analysis to produce a type-annotated AST.
class TypeChecker final : public LazyResolver {
public:
ASTContext &Context;
DiagnosticEngine &Diags;
/// \brief The list of function definitions we've encountered.
std::vector<AbstractFunctionDecl *> definedFunctions;
/// Declarations that need their conformances checked.
llvm::SmallVector<Decl *, 8> ConformanceContexts;
/// The list of protocol conformances that were "used" and will need to be
/// completed before type checking is considered complete.
llvm::SetVector<NormalProtocolConformance *> UsedConformances;
/// The list of protocol conformances whose requirements could not be
/// fully checked and, therefore, should be checked again at the top
/// level.
llvm::SetVector<NormalProtocolConformance *> PartiallyCheckedConformances;
/// The list of declarations that we've done at least partial validation
/// of during type-checking, but which will need to be finalized before
/// we can hand them off to SILGen etc.
llvm::SetVector<ValueDecl *> DeclsToFinalize;
/// Track the index of the next declaration that needs to be finalized,
/// from the \c DeclsToFinalize set.
unsigned NextDeclToFinalize = 0;
/// The list of functions that need to have their bodies synthesized.
llvm::MapVector<FuncDecl*, SynthesizedFunction> FunctionsToSynthesize;
/// The list of protocols that need their requirement signatures computed,
/// because they were first validated by validateDeclForNameLookup(),
/// which skips this step.
llvm::SetVector<ProtocolDecl *> DelayedRequirementSignatures;
/// The list of types whose circularity checks were delayed.
SmallVector<NominalTypeDecl*, 8> DelayedCircularityChecks;
// Caches whether a given declaration is "as specialized" as another.
llvm::DenseMap<std::tuple<ValueDecl *, ValueDecl *,
/*isDynamicOverloadComparison*/ unsigned>,
bool>
specializedOverloadComparisonCache;
/// A list of closures for the most recently type-checked function, which we
/// will need to compute captures for.
std::vector<AnyFunctionRef> ClosuresWithUncomputedCaptures;
/// Local functions that have been captured before their definitions.
///
/// We need this to guard against functions that would transitively capture
/// variables before their definition, e.g.:
///
/// func outer() {
/// func first() {
/// second()
/// }
/// second()
/// var x
/// func second() {
/// use(x)
/// }
/// }
llvm::SmallDenseMap<AnyFunctionRef, SmallVector<AnyFunctionRef, 4>, 4>
ForwardCapturedFuncs;
/// A set of local functions from which C function pointers are derived.
///
/// This is used to diagnose the use of local functions with captured context
/// as C function pointers when the function's captures have not yet been
/// computed.
llvm::DenseMap<AnyFunctionRef, std::vector<Expr*>> LocalCFunctionPointers;
private:
/// Return statements with functions as return values.
llvm::DenseMap<AbstractFunctionDecl *, llvm::DenseSet<ReturnStmt *>>
FunctionAsReturnValue;
/// Function apply expressions with a certain function as an argument.
llvm::DenseMap<AbstractFunctionDecl *, llvm::DenseSet<ApplyExpr *>>
FunctionAsEscapingArg;
/// The # of times we have performed typo correction.
unsigned NumTypoCorrections = 0;
public:
/// Record an occurrence of a function that captures inout values as an
/// argument.
///
/// \param decl the function that occurs as an argument.
///
/// \param apply the expression in which the function appears.
void addEscapingFunctionAsArgument(AbstractFunctionDecl *decl,
ApplyExpr *apply) {
FunctionAsEscapingArg[decl].insert(apply);
}
/// Find occurrences of a function that captures inout values as arguments.
///
/// \param decl the function that occurs as an argument.
///
/// \returns Expressions in which the function appears as arguments.
llvm::DenseSet<ApplyExpr *> &
getEscapingFunctionAsArgument(AbstractFunctionDecl *decl) {
return FunctionAsEscapingArg[decl];
}
/// Record an occurrence of a function that captures inout values as a return
/// value
///
/// \param decl the function that occurs as a return value.
///
/// \param stmt the expression in which the function appears.
void addEscapingFunctionAsReturnValue(AbstractFunctionDecl *decl,
ReturnStmt *stmt) {
FunctionAsReturnValue[decl].insert(stmt);
}
/// Find occurrences of a function that captures inout values as return
/// values.
///
/// \param decl the function that occurs as a return value.
///
/// \returns Expressions in which the function appears as arguments.
llvm::DenseSet<ReturnStmt *> &
getEscapingFunctionAsReturnValue(AbstractFunctionDecl *decl) {
return FunctionAsReturnValue[decl];
}
private:
Type IntLiteralType;
Type MaxIntegerType;
Type FloatLiteralType;
Type BooleanLiteralType;
Type UnicodeScalarType;
Type ExtendedGraphemeClusterType;
Type StringLiteralType;
Type ArrayLiteralType;
Type DictionaryLiteralType;
Type ColorLiteralType;
Type ImageLiteralType;
Type FileReferenceLiteralType;
Type StringType;
Type SubstringType;
Type IntType;
Type Int8Type;
Type UInt8Type;
Type NSObjectType;
Type NSNumberType;
Type NSValueType;
Type ObjCSelectorType;
Type ExceptionType;
/// The \c Swift.UnsafeMutablePointer<T> declaration.
Optional<NominalTypeDecl *> ArrayDecl;
/// The set of expressions currently being analyzed for failures.
llvm::DenseMap<Expr*, Expr*> DiagnosedExprs;
ModuleDecl *StdlibModule = nullptr;
/// The index of the next response metavariable to bind to a REPL result.
unsigned NextResponseVariableIndex = 0;
/// If non-zero, warn when a function body takes longer than this many
/// milliseconds to type-check.
///
/// Intended for debugging purposes only.
unsigned WarnLongFunctionBodies = 0;
/// If non-zero, warn when type-checking an expression takes longer
/// than this many milliseconds.
///
/// Intended for debugging purposes only.
unsigned WarnLongExpressionTypeChecking = 0;
/// If non-zero, abort the expression type checker if it takes more
/// than this many seconds.
unsigned ExpressionTimeoutThreshold = 600;
/// If non-zero, abort the switch statement exhaustiveness checker if
/// the Space::minus function is called more than this many times.
///
/// Why this number? Times out in about a second on a 2017 iMac, Retina 5K,
// 4.2 GHz Intel Core i7.
// (It's arbitrary, but will keep the compiler from taking too much time.)
unsigned SwitchCheckingInvocationThreshold = 200000;
/// If true, the time it takes to type-check each function will be dumped
/// to llvm::errs().
bool DebugTimeFunctionBodies = false;
/// If true, the time it takes to type-check each expression will be
/// dumped to llvm::errs().
bool DebugTimeExpressions = false;
/// Indicate that the type checker is checking code that will be
/// immediately executed. This will suppress certain warnings
/// when executing scripts.
bool InImmediateMode = false;
/// A helper to construct and typecheck call to super.init().
///
/// \returns NULL if the constructed expression does not typecheck.
Expr* constructCallToSuperInit(ConstructorDecl *ctor, ClassDecl *ClDecl);
public:
TypeChecker(ASTContext &Ctx) : TypeChecker(Ctx, Ctx.Diags) { }
TypeChecker(ASTContext &Ctx, DiagnosticEngine &Diags);
TypeChecker(const TypeChecker&) = delete;
TypeChecker& operator=(const TypeChecker&) = delete;
~TypeChecker();
LangOptions &getLangOpts() const { return Context.LangOpts; }
/// Dump the time it takes to type-check each function to llvm::errs().
void enableDebugTimeFunctionBodies() {
DebugTimeFunctionBodies = true;
}
/// Dump the time it takes to type-check each function to llvm::errs().
void enableDebugTimeExpressions() {
DebugTimeExpressions = true;
}
bool getDebugTimeExpressions() {
return DebugTimeExpressions;
}
/// If \p timeInMS is non-zero, warn when a function body takes longer than
/// this many milliseconds to type-check.
///
/// Intended for debugging purposes only.
void setWarnLongFunctionBodies(unsigned timeInMS) {
WarnLongFunctionBodies = timeInMS;
}
/// If \p timeInMS is non-zero, warn when type-checking an expression
/// takes longer than this many milliseconds.
///
/// Intended for debugging purposes only.
void setWarnLongExpressionTypeChecking(unsigned timeInMS) {
WarnLongExpressionTypeChecking = timeInMS;
}
/// Return the current setting for the number of milliseconds
/// threshold we use to determine whether to warn about an
/// expression taking a long time.
unsigned getWarnLongExpressionTypeChecking() {
return WarnLongExpressionTypeChecking;
}
/// Set the threshold that determines the upper bound for the number
/// of seconds we'll let the expression type checker run before
/// considering an expression "too complex".
void setExpressionTimeoutThreshold(unsigned timeInSeconds) {
ExpressionTimeoutThreshold = timeInSeconds;
}
/// Return the current setting for the threshold that determines
/// the upper bound for the number of seconds we'll let the
/// expression type checker run before considering an expression
/// "too complex".
/// If zero, do not limit the checking.
unsigned getExpressionTimeoutThresholdInSeconds() {
return ExpressionTimeoutThreshold;
}
/// Get the threshold that determines the upper bound for the number
/// of times we'll let the Space::minus routine run before
/// considering a switch statement "too complex".
/// If zero, do not limit the checking.
unsigned getSwitchCheckingInvocationThreshold() const {
return SwitchCheckingInvocationThreshold;
}
/// Set the threshold that determines the upper bound for the number
/// of times we'll let the Space::minus routine run before
/// considering a switch statement "too complex".
void setSwitchCheckingInvocationThreshold(unsigned invocationCount) {
SwitchCheckingInvocationThreshold = invocationCount;
}
bool getInImmediateMode() {
return InImmediateMode;
}
void setInImmediateMode(bool InImmediateMode) {
this->InImmediateMode = InImmediateMode;
}
template<typename ...ArgTypes>
InFlightDiagnostic diagnose(ArgTypes &&...Args) {
return Diags.diagnose(std::forward<ArgTypes>(Args)...);
}
static Type getArraySliceType(SourceLoc loc, Type elementType);
static Type getDictionaryType(SourceLoc loc, Type keyType, Type valueType);
static Type getOptionalType(SourceLoc loc, Type elementType);
Type getUnsafePointerType(SourceLoc loc, Type pointeeType);
Type getUnsafeMutablePointerType(SourceLoc loc, Type pointeeType);
Type getStringType(DeclContext *dc);
Type getSubstringType(DeclContext *dc);
Type getIntType(DeclContext *dc);
Type getInt8Type(DeclContext *dc);
Type getUInt8Type(DeclContext *dc);
Type getMaxIntegerType(DeclContext *dc);
Type getNSObjectType(DeclContext *dc);
Type getObjCSelectorType(DeclContext *dc);
Type getExceptionType(DeclContext *dc, SourceLoc loc);
/// \brief Try to resolve an IdentTypeRepr, returning either the referenced
/// Type or an ErrorType in case of error.
static Type resolveIdentifierType(TypeResolution resolution,
IdentTypeRepr *IdType,
TypeResolutionOptions options);
/// Bind an UnresolvedDeclRefExpr by performing name lookup and
/// returning the resultant expression. Context is the DeclContext used
/// for the lookup.
Expr *resolveDeclRefExpr(UnresolvedDeclRefExpr *UDRE, DeclContext *Context);
/// \brief Validate the given type.
///
/// Type validation performs name binding, checking of generic arguments,
/// and so on to determine whether the given type is well-formed and can
/// be used as a type.
///
/// \param Loc The type (with source location information) to validate.
/// If the type has already been validated, returns immediately.
///
/// \param resolution The type resolution being performed.
///
/// \param options Options that alter type resolution.
///
/// \returns true if type validation failed, or false otherwise.
bool validateType(TypeLoc &Loc, TypeResolution resolution,
TypeResolutionOptions options);
/// Check for unsupported protocol types in the given declaration.
void checkUnsupportedProtocolType(Decl *decl);
/// Check for unsupported protocol types in the given statement.
void checkUnsupportedProtocolType(Stmt *stmt);
/// Expose TypeChecker's handling of GenericParamList to SIL parsing.
GenericEnvironment *handleSILGenericParams(GenericParamList *genericParams,
DeclContext *DC);
void validateDecl(ValueDecl *D);
void validateDecl(OperatorDecl *decl);
void validateDecl(PrecedenceGroupDecl *decl);
/// Perform just enough validation for looking up names using the Decl.
void validateDeclForNameLookup(ValueDecl *D);
/// Validate the given extension declaration, ensuring that it
/// properly extends the nominal type it names.
void validateExtension(ExtensionDecl *ext);
/// Request that type containing the given member needs to have all
/// members validated after everythign in the translation unit has
/// been processed.
void requestMemberLayout(ValueDecl *member);
/// Request that the given class needs to have all members validated
/// after everything in the translation unit has been processed.
void requestNominalLayout(NominalTypeDecl *nominalDecl);
/// Request that the superclass of the given class, if any, needs to have
/// all members validated after everything in the translation unit has
/// been processed.
void requestSuperclassLayout(ClassDecl *classDecl);
/// Perform final validation of a declaration after everything in the
/// translation unit has been processed.
void finalizeDecl(ValueDecl *D);
/// Resolve a reference to the given type declaration within a particular
/// context.
///
/// This routine aids unqualified name lookup for types by performing the
/// resolution necessary to rectify the declaration found by name lookup with
/// the declaration context from which name lookup started.
///
/// \param typeDecl The type declaration found by name lookup.
/// \param isSpecialized Whether the type will have generic arguments applied.
/// \param resolution The resolution to perform.
///
/// \returns the resolved type.
static Type resolveTypeInContext(TypeDecl *typeDecl,
DeclContext *foundDC,
TypeResolution resolution,
TypeResolutionOptions options,
bool isSpecialized);
/// Apply generic arguments to the given type.
///
/// This function emits diagnostics about an invalid type or the wrong number
/// of generic arguments, whereas applyUnboundGenericArguments requires this
/// to be in a correct and valid form.
///
/// \param type The generic type to which to apply arguments.
/// \param loc The source location for diagnostic reporting.
/// \param resolution The type resolution to perform.
/// \param generic The arguments to apply with the angle bracket range for
/// diagnostics.
/// \param options The type resolution context.
///
/// \returns A BoundGenericType bound to the given arguments, or null on
/// error.
///
/// \see applyUnboundGenericArguments
static Type applyGenericArguments(Type type, SourceLoc loc,
TypeResolution resolution,
GenericIdentTypeRepr *generic,
TypeResolutionOptions options);
/// Apply generic arguments to the given type.
///
/// This function requires a valid unbound generic type with the correct
/// number of generic arguments given, whereas applyGenericArguments emits
/// diagnostics in those cases.
///
/// \param unboundType The unbound generic type to which to apply arguments.
/// \param decl The declaration of the type.
/// \param loc The source location for diagnostic reporting.
/// \param resolution The type resolution.
/// \param genericArgs The list of generic arguments to apply to the type.
///
/// \returns A BoundGenericType bound to the given arguments, or null on
/// error.
///
/// \see applyGenericArguments
static Type applyUnboundGenericArguments(UnboundGenericType *unboundType,
GenericTypeDecl *decl,
SourceLoc loc,
TypeResolution resolution,
ArrayRef<Type> genericArgs);
/// \brief Substitute the given base type into the type of the given nested type,
/// producing the effective type that the nested type will have.
///
/// \param module The module in which the substitution will be performed.
/// \param member The member whose type projection is being computed.
/// \param baseTy The base type that will be substituted for the 'Self' of the
/// member.
/// \param useArchetypes Whether to use context archetypes for outer generic
/// parameters if the class is nested inside a generic function.
static Type substMemberTypeWithBase(ModuleDecl *module, TypeDecl *member,
Type baseTy, bool useArchetypes = true);
/// \brief Retrieve the superclass type of the given type, or a null type if
/// the type has no supertype.
Type getSuperClassOf(Type type);
/// \brief Determine whether one type is a subtype of another.
///
/// \param t1 The potential subtype.
/// \param t2 The potential supertype.
/// \param dc The context of the check.
///
/// \returns true if \c t1 is a subtype of \c t2.
bool isSubtypeOf(Type t1, Type t2, DeclContext *dc);
/// \brief Determine whether one type is a subclass of another.
///
/// \param t1 The potential subtype.
/// \param t2 The potential supertype.
/// \param dc The context of the check.
///
/// \returns true if \c t1 is a subtype of \c t2.
bool isSubclassOf(Type t1, Type t2, DeclContext *dc);
/// \brief Determine whether one type is implicitly convertible to another.
///
/// \param t1 The potential source type of the conversion.
///
/// \param t2 The potential destination type of the conversion.
///
/// \param dc The context of the conversion.