@@ -123,9 +123,16 @@ operator()(InFlightSubstitution &IFS, Type dependentType,
123
123
InFlightSubstitution::InFlightSubstitution (TypeSubstitutionFn substType,
124
124
LookupConformanceFn lookupConformance,
125
125
SubstOptions options)
126
- : Options(options),
127
- BaselineSubstType(substType),
128
- BaselineLookupConformance(lookupConformance) {
126
+ : BaselineSubstType(substType),
127
+ BaselineLookupConformance(lookupConformance),
128
+ Options(options) {
129
+
130
+ LimitReached = 0 ;
131
+
132
+ // FIXME: Make these configurable
133
+ RemainingCount = 1000 ;
134
+ RemainingDepth = 20 ;
135
+
129
136
// FIXME: Don't substitute type parameters if one of the special flags is set.
130
137
Props |= RecursiveTypeProperties::HasTypeParameter;
131
138
@@ -233,6 +240,14 @@ Type InFlightSubstitution::projectLaneFromPackType(Type substType,
233
240
}
234
241
}
235
242
243
+ bool InFlightSubstitution::checkLimits () {
244
+ if (RemainingCount == 0 || RemainingDepth == 0 ) {
245
+ LimitReached = true ;
246
+ return true ;
247
+ }
248
+ return false ;
249
+ }
250
+
236
251
Type InFlightSubstitution::substType (SubstitutableType *origType,
237
252
unsigned level) {
238
253
auto substType = BaselineSubstType (origType);
@@ -244,6 +259,20 @@ Type InFlightSubstitution::substType(SubstitutableType *origType,
244
259
else
245
260
substType = substType->increasePackElementLevel (level);
246
261
262
+ // Opaque type replacement must iterate until fixed point.
263
+ if (shouldSubstituteOpaqueArchetypes () &&
264
+ substType->hasOpaqueArchetype () &&
265
+ !substType->isEqual (origType)) {
266
+ if (checkLimits ()) {
267
+ return ErrorType::get (substType);
268
+ }
269
+
270
+ --RemainingCount;
271
+ --RemainingDepth;
272
+ substType = substType.subst (*this );
273
+ ++RemainingDepth;
274
+ }
275
+
247
276
return substType;
248
277
}
249
278
@@ -271,6 +300,19 @@ InFlightSubstitution::lookupConformance(Type dependentType,
271
300
substConfRef.getPack (), level);
272
301
}
273
302
303
+ // Opaque type replacement must iterate until fixed point.
304
+ if (shouldSubstituteOpaqueArchetypes () && substConfRef &&
305
+ substConfRef.getType ()->hasOpaqueArchetype () &&
306
+ !substConfRef.getType ()->isEqual (dependentType)) {
307
+ if (checkLimits ()) {
308
+ return ProtocolConformanceRef::forInvalid ();
309
+ }
310
+ --RemainingCount;
311
+ --RemainingDepth;
312
+ substConfRef = substConfRef.subst (*this );
313
+ ++RemainingDepth;
314
+ }
315
+
274
316
return substConfRef;
275
317
}
276
318
@@ -906,17 +948,6 @@ ReplaceOpaqueTypesWithUnderlyingTypes::shouldPerformSubstitution(
906
948
return OpaqueSubstitutionKind::SubstituteNonResilientModule;
907
949
}
908
950
909
- static Type substOpaqueTypesWithUnderlyingTypesRec (
910
- Type ty, const DeclContext *inContext, ResilienceExpansion contextExpansion,
911
- bool isWholeModuleContext,
912
- llvm::DenseSet<ReplaceOpaqueTypesWithUnderlyingTypes::SeenDecl> &decls) {
913
- ReplaceOpaqueTypesWithUnderlyingTypes replacer (inContext, contextExpansion,
914
- isWholeModuleContext, decls);
915
- return ty.subst (replacer, replacer,
916
- SubstFlags::SubstituteOpaqueArchetypes |
917
- SubstFlags::PreservePackExpansionLevel);
918
- }
919
-
920
951
// / Checks that \p dc has access to \p ty for the purposes of an opaque
921
952
// / substitution described by \p kind.
922
953
// /
@@ -973,13 +1004,6 @@ static bool canSubstituteTypeInto(Type ty, const DeclContext *dc,
973
1004
llvm_unreachable (" invalid substitution kind" );
974
1005
}
975
1006
976
- ReplaceOpaqueTypesWithUnderlyingTypes::ReplaceOpaqueTypesWithUnderlyingTypes (
977
- const DeclContext *inContext, ResilienceExpansion contextExpansion,
978
- bool isWholeModuleContext, llvm::DenseSet<SeenDecl> &seen)
979
- : contextExpansion(contextExpansion),
980
- inContextAndIsWholeModule(inContext, isWholeModuleContext),
981
- seenDecls(&seen) {}
982
-
983
1007
Type ReplaceOpaqueTypesWithUnderlyingTypes::
984
1008
operator ()(SubstitutableType *maybeOpaqueType) const {
985
1009
auto *archetype = dyn_cast<OpaqueTypeArchetypeType>(maybeOpaqueType);
@@ -1027,36 +1051,7 @@ operator()(SubstitutableType *maybeOpaqueType) const {
1027
1051
// for its type arguments. We perform this substitution after checking for
1028
1052
// visibility, since we do not want the result of the visibility check to
1029
1053
// depend on the substitutions previously applied.
1030
- auto substTy = partialSubstTy.subst (outerSubs);
1031
-
1032
- // If the type changed, but still contains opaque types, recur.
1033
- if (!substTy->isEqual (maybeOpaqueType) && substTy->hasOpaqueArchetype ()) {
1034
- SeenDecl seenKey (decl, outerSubs);
1035
- if (auto *alreadySeen = this ->seenDecls ) {
1036
- // Detect substitution loops. If we find one, just bounce the original
1037
- // type back to the caller. This substitution will fail at runtime
1038
- // instead.
1039
- if (!alreadySeen->insert (seenKey).second ) {
1040
- return maybeOpaqueType;
1041
- }
1042
-
1043
- auto res = ::substOpaqueTypesWithUnderlyingTypesRec (
1044
- substTy, inContext, contextExpansion, isContextWholeModule,
1045
- *alreadySeen);
1046
- alreadySeen->erase (seenKey);
1047
- return res;
1048
- } else {
1049
- // We're the top of the stack for the recursion check. Allocate a set of
1050
- // opaque result type decls we've already seen for the rest of the check.
1051
- llvm::DenseSet<SeenDecl> seenDecls;
1052
- seenDecls.insert (seenKey);
1053
- return ::substOpaqueTypesWithUnderlyingTypesRec (
1054
- substTy, inContext, contextExpansion, isContextWholeModule,
1055
- seenDecls);
1056
- }
1057
- }
1058
-
1059
- return substTy;
1054
+ return partialSubstTy.subst (outerSubs);
1060
1055
}
1061
1056
1062
1057
Type swift::substOpaqueTypesWithUnderlyingTypes (Type ty,
@@ -1068,9 +1063,25 @@ Type swift::substOpaqueTypesWithUnderlyingTypes(Type ty,
1068
1063
ReplaceOpaqueTypesWithUnderlyingTypes replacer (
1069
1064
context.getContext (), context.getResilienceExpansion (),
1070
1065
context.isWholeModuleContext ());
1071
- SubstOptions flags = (SubstFlags::SubstituteOpaqueArchetypes |
1072
- SubstFlags::PreservePackExpansionLevel);
1073
- return ty.subst (replacer, replacer, flags);
1066
+ InFlightSubstitution IFS (replacer, replacer,
1067
+ SubstFlags::SubstituteOpaqueArchetypes |
1068
+ SubstFlags::PreservePackExpansionLevel);
1069
+
1070
+ auto substTy = ty.subst (IFS);
1071
+
1072
+ // FIXME: This should be a diagnostic at the source location of the innermost
1073
+ // request or something.
1074
+ if (IFS.wasLimitReached ()) {
1075
+ ABORT ([&](auto &out) {
1076
+ out << " Possible non-terminating type substitution detected\n\n " ;
1077
+ out << " Original type:\n " ;
1078
+ ty.dump (out);
1079
+ out << " Substituted type:\n " ;
1080
+ substTy.dump (out);
1081
+ });
1082
+ }
1083
+
1084
+ return substTy;
1074
1085
}
1075
1086
1076
1087
CanType
@@ -1080,24 +1091,29 @@ swift::substOpaqueTypesWithUnderlyingTypes(CanType ty,
1080
1091
->getCanonicalType ();
1081
1092
}
1082
1093
1083
- static ProtocolConformanceRef substOpaqueTypesWithUnderlyingTypesRec (
1084
- ProtocolConformanceRef ref, const DeclContext *inContext,
1085
- ResilienceExpansion contextExpansion, bool isWholeModuleContext,
1086
- llvm::DenseSet<ReplaceOpaqueTypesWithUnderlyingTypes::SeenDecl> &decls) {
1087
- ReplaceOpaqueTypesWithUnderlyingTypes replacer (inContext, contextExpansion,
1088
- isWholeModuleContext, decls);
1089
- return ref.subst (replacer, replacer,
1090
- SubstFlags::SubstituteOpaqueArchetypes |
1091
- SubstFlags::PreservePackExpansionLevel);
1092
- }
1093
-
1094
1094
ProtocolConformanceRef swift::substOpaqueTypesWithUnderlyingTypes (
1095
1095
ProtocolConformanceRef ref, TypeExpansionContext context) {
1096
1096
ReplaceOpaqueTypesWithUnderlyingTypes replacer (
1097
1097
context.getContext (), context.getResilienceExpansion (),
1098
1098
context.isWholeModuleContext ());
1099
- return ref.subst (replacer, replacer,
1100
- SubstFlags::SubstituteOpaqueArchetypes);
1099
+ InFlightSubstitution IFS (replacer, replacer,
1100
+ SubstFlags::SubstituteOpaqueArchetypes);
1101
+
1102
+ auto substRef = ref.subst (IFS);
1103
+
1104
+ // FIXME: This should be a diagnostic at the source location of the innermost
1105
+ // request or something.
1106
+ if (IFS.wasLimitReached ()) {
1107
+ ABORT ([&](auto &out) {
1108
+ out << " Possible non-terminating conformance substitution detected\n\n " ;
1109
+ out << " Original conformance:\n " ;
1110
+ ref.dump (out);
1111
+ out << " \n Substituted conformance:\n " ;
1112
+ substRef.dump (out);
1113
+ });
1114
+ }
1115
+
1116
+ return substRef;
1101
1117
}
1102
1118
1103
1119
ProtocolConformanceRef ReplaceOpaqueTypesWithUnderlyingTypes::
@@ -1151,36 +1167,7 @@ operator()(InFlightSubstitution &IFS, Type maybeOpaqueType,
1151
1167
auto partialSubstRef =
1152
1168
subs->lookupConformance (archetype->getInterfaceType ()->getCanonicalType (),
1153
1169
protocol);
1154
- auto substRef = partialSubstRef.subst (outerSubs);
1155
-
1156
- // If the type still contains opaque types, recur.
1157
- if (substRef.getType ()->hasOpaqueArchetype ()) {
1158
- SeenDecl seenKey (decl, outerSubs);
1159
-
1160
- if (auto *alreadySeen = this ->seenDecls ) {
1161
- // Detect substitution loops. If we find one, just bounce the original
1162
- // type back to the caller. This substitution will fail at runtime
1163
- // instead.
1164
- if (!alreadySeen->insert (seenKey).second ) {
1165
- return lookupConformance (maybeOpaqueType.subst (IFS), protocol);
1166
- }
1167
-
1168
- auto res = ::substOpaqueTypesWithUnderlyingTypesRec (
1169
- substRef, inContext, contextExpansion, isContextWholeModule,
1170
- *alreadySeen);
1171
- alreadySeen->erase (seenKey);
1172
- return res;
1173
- } else {
1174
- // We're the top of the stack for the recursion check. Allocate a set of
1175
- // opaque result type decls we've already seen for the rest of the check.
1176
- llvm::DenseSet<SeenDecl> seenDecls;
1177
- seenDecls.insert (seenKey);
1178
- return ::substOpaqueTypesWithUnderlyingTypesRec (
1179
- substRef, inContext, contextExpansion, isContextWholeModule,
1180
- seenDecls);
1181
- }
1182
- }
1183
- return substRef;
1170
+ return partialSubstRef.subst (outerSubs);
1184
1171
}
1185
1172
1186
1173
Type ReplaceExistentialArchetypesWithConcreteTypes::getInterfaceType (
0 commit comments