@@ -37,6 +37,7 @@ LUAU_FASTFLAG(LuauNewSolverPopulateTableLocations)
37
37
LUAU_FASTFLAGVARIABLE(LuauAllowNilAssignmentToIndexer)
38
38
LUAU_FASTFLAG(LuauUserTypeFunNoExtraConstraint)
39
39
LUAU_FASTFLAG(LuauTrackInteriorFreeTypesOnScope)
40
+ LUAU_FASTFLAGVARIABLE(LuauAlwaysFillInFunctionCallDiscriminantTypes)
40
41
41
42
namespace Luau
42
43
{
@@ -1153,6 +1154,42 @@ bool ConstraintSolver::tryDispatch(const TypeAliasExpansionConstraint& c, NotNul
1153
1154
return true ;
1154
1155
}
1155
1156
1157
+ void ConstraintSolver::fillInDiscriminantTypes (
1158
+ NotNull<const Constraint> constraint,
1159
+ const std::vector<std::optional<TypeId>>& discriminantTypes
1160
+ )
1161
+ {
1162
+ for (std::optional<TypeId> ty : discriminantTypes)
1163
+ {
1164
+ if (!ty)
1165
+ continue ;
1166
+
1167
+ // If the discriminant type has been transmuted, we need to unblock them.
1168
+ if (!isBlocked (*ty))
1169
+ {
1170
+ unblock (*ty, constraint->location );
1171
+ continue ;
1172
+ }
1173
+
1174
+ if (FFlag::LuauRemoveNotAnyHack)
1175
+ {
1176
+ // We bind any unused discriminants to the `*no-refine*` type indicating that it can be safely ignored.
1177
+ emplaceType<BoundType>(asMutable (follow (*ty)), builtinTypes->noRefineType );
1178
+ }
1179
+ else
1180
+ {
1181
+ // We use `any` here because the discriminant type may be pointed at by both branches,
1182
+ // where the discriminant type is not negated, and the other where it is negated, i.e.
1183
+ // `unknown ~ unknown` and `~unknown ~ never`, so `T & unknown ~ T` and `T & ~unknown ~ never`
1184
+ // v.s.
1185
+ // `any ~ any` and `~any ~ any`, so `T & any ~ T` and `T & ~any ~ T`
1186
+ //
1187
+ // In practice, users cannot negate `any`, so this is an implementation detail we can always change.
1188
+ emplaceType<BoundType>(asMutable (follow (*ty)), builtinTypes->anyType );
1189
+ }
1190
+ }
1191
+ }
1192
+
1156
1193
bool ConstraintSolver::tryDispatch (const FunctionCallConstraint& c, NotNull<const Constraint> constraint)
1157
1194
{
1158
1195
TypeId fn = follow (c.fn );
@@ -1168,19 +1205,25 @@ bool ConstraintSolver::tryDispatch(const FunctionCallConstraint& c, NotNull<cons
1168
1205
{
1169
1206
emplaceTypePack<BoundTypePack>(asMutable (c.result ), builtinTypes->anyTypePack );
1170
1207
unblock (c.result , constraint->location );
1208
+ if (FFlag::LuauAlwaysFillInFunctionCallDiscriminantTypes)
1209
+ fillInDiscriminantTypes (constraint, c.discriminantTypes );
1171
1210
return true ;
1172
1211
}
1173
1212
1174
1213
// if we're calling an error type, the result is an error type, and that's that.
1175
1214
if (get<ErrorType>(fn))
1176
1215
{
1177
1216
bind (constraint, c.result , builtinTypes->errorRecoveryTypePack ());
1217
+ if (FFlag::LuauAlwaysFillInFunctionCallDiscriminantTypes)
1218
+ fillInDiscriminantTypes (constraint, c.discriminantTypes );
1178
1219
return true ;
1179
1220
}
1180
1221
1181
1222
if (get<NeverType>(fn))
1182
1223
{
1183
1224
bind (constraint, c.result , builtinTypes->neverTypePack );
1225
+ if (FFlag::LuauAlwaysFillInFunctionCallDiscriminantTypes)
1226
+ fillInDiscriminantTypes (constraint, c.discriminantTypes );
1184
1227
return true ;
1185
1228
}
1186
1229
@@ -1261,36 +1304,45 @@ bool ConstraintSolver::tryDispatch(const FunctionCallConstraint& c, NotNull<cons
1261
1304
emplace<FreeTypePack>(constraint, c.result , constraint->scope );
1262
1305
}
1263
1306
1264
- for (std::optional<TypeId> ty : c. discriminantTypes )
1307
+ if (FFlag::LuauAlwaysFillInFunctionCallDiscriminantTypes )
1265
1308
{
1266
- if (!ty)
1267
- continue ;
1268
-
1269
- // If the discriminant type has been transmuted, we need to unblock them.
1270
- if (!isBlocked (*ty))
1309
+ fillInDiscriminantTypes (constraint, c.discriminantTypes );
1310
+ }
1311
+ else
1312
+ {
1313
+ // NOTE: This is the body of the `fillInDiscriminantTypes` helper.
1314
+ for (std::optional<TypeId> ty : c.discriminantTypes )
1271
1315
{
1272
- unblock (*ty, constraint->location );
1273
- continue ;
1274
- }
1316
+ if (!ty)
1317
+ continue ;
1275
1318
1276
- if (FFlag::LuauRemoveNotAnyHack)
1277
- {
1278
- // We bind any unused discriminants to the `*no-refine*` type indicating that it can be safely ignored.
1279
- emplaceType<BoundType>(asMutable (follow (*ty)), builtinTypes->noRefineType );
1280
- }
1281
- else
1282
- {
1283
- // We use `any` here because the discriminant type may be pointed at by both branches,
1284
- // where the discriminant type is not negated, and the other where it is negated, i.e.
1285
- // `unknown ~ unknown` and `~unknown ~ never`, so `T & unknown ~ T` and `T & ~unknown ~ never`
1286
- // v.s.
1287
- // `any ~ any` and `~any ~ any`, so `T & any ~ T` and `T & ~any ~ T`
1288
- //
1289
- // In practice, users cannot negate `any`, so this is an implementation detail we can always change.
1290
- emplaceType<BoundType>(asMutable (follow (*ty)), builtinTypes->anyType );
1319
+ // If the discriminant type has been transmuted, we need to unblock them.
1320
+ if (!isBlocked (*ty))
1321
+ {
1322
+ unblock (*ty, constraint->location );
1323
+ continue ;
1324
+ }
1325
+
1326
+ if (FFlag::LuauRemoveNotAnyHack)
1327
+ {
1328
+ // We bind any unused discriminants to the `*no-refine*` type indicating that it can be safely ignored.
1329
+ emplaceType<BoundType>(asMutable (follow (*ty)), builtinTypes->noRefineType );
1330
+ }
1331
+ else
1332
+ {
1333
+ // We use `any` here because the discriminant type may be pointed at by both branches,
1334
+ // where the discriminant type is not negated, and the other where it is negated, i.e.
1335
+ // `unknown ~ unknown` and `~unknown ~ never`, so `T & unknown ~ T` and `T & ~unknown ~ never`
1336
+ // v.s.
1337
+ // `any ~ any` and `~any ~ any`, so `T & any ~ T` and `T & ~any ~ T`
1338
+ //
1339
+ // In practice, users cannot negate `any`, so this is an implementation detail we can always change.
1340
+ emplaceType<BoundType>(asMutable (follow (*ty)), builtinTypes->anyType );
1341
+ }
1291
1342
}
1292
1343
}
1293
1344
1345
+
1294
1346
OverloadResolver resolver{
1295
1347
builtinTypes,
1296
1348
NotNull{arena},
0 commit comments