@@ -880,7 +880,7 @@ function validate_sparams(sparams::SimpleVector)
880
880
end
881
881
882
882
function analyze_method! (match:: MethodMatch , argtypes:: Vector{Any} ,
883
- flag:: UInt8 , state:: InliningState )
883
+ flag:: UInt8 , state:: InliningState , check_sparams :: Bool = false )
884
884
method = match. method
885
885
spec_types = match. spec_types
886
886
@@ -902,7 +902,7 @@ function analyze_method!(match::MethodMatch, argtypes::Vector{Any},
902
902
end
903
903
end
904
904
905
- # validate_sparams(match.sparams) || return nothing
905
+ check_sparams && ( validate_sparams (match. sparams) || return nothing )
906
906
907
907
et = state. et
908
908
@@ -1238,6 +1238,9 @@ function analyze_single_call!(
1238
1238
cases = InliningCase[]
1239
1239
local any_fully_covered = false
1240
1240
local handled_all_cases = true
1241
+ local revisit_idx = nothing
1242
+ local only_method = nothing
1243
+ local meth:: MethodLookupResult
1241
1244
for i in 1 : length (infos)
1242
1245
meth = infos[i]. results
1243
1246
if meth. ambig
@@ -1248,14 +1251,64 @@ function analyze_single_call!(
1248
1251
# No applicable methods; try next union split
1249
1252
handled_all_cases = false
1250
1253
continue
1254
+ else
1255
+ if length (meth) == 1 && only_method != = false
1256
+ if only_method === nothing
1257
+ only_method = meth[1 ]. method
1258
+ elseif only_method != = meth[1 ]. method
1259
+ only_method = false
1260
+ end
1261
+ else
1262
+ only_method = false
1263
+ end
1251
1264
end
1252
- for match in meth
1253
- handled_all_cases &= handle_match! (match, argtypes, flag, state, cases, true )
1265
+ for (j, match) in enumerate (meth)
1266
+ if ! isdispatchtuple (match. spec_types)
1267
+ if ! match. fully_covers
1268
+ handled_all_cases = false
1269
+ continue
1270
+ end
1271
+ if revisit_idx === nothing
1272
+ revisit_idx = (i, j)
1273
+ else
1274
+ handled_all_cases = false
1275
+ revisit_idx = nothing
1276
+ end
1277
+ else
1278
+ handled_all_cases &= handle_match! (match, argtypes, flag, state, cases, true )
1279
+ end
1254
1280
any_fully_covered |= match. fully_covers
1255
1281
end
1256
1282
end
1257
1283
1258
- if ! handled_all_cases
1284
+ atype = argtypes_to_type (argtypes)
1285
+ if handled_all_cases && revisit_idx != = nothing
1286
+ # If there's only one case that's not a dispatchtuple, we can
1287
+ # still unionsplit by visiting all the other cases first.
1288
+ # This is useful for code like:
1289
+ # foo(x::Int) = 1
1290
+ # foo(@nospecialize(x::Any)) = 2
1291
+ # where we where only a small number of specific dispatchable
1292
+ # cases are split off from an ::Any typed fallback.
1293
+ (i, j) = revisit_idx
1294
+ match = infos[i]. results[j]
1295
+ handled_all_cases &= handle_match! (match, argtypes, flag, state, cases, true , true )
1296
+ elseif length (cases) == 0 && only_method isa Method
1297
+ # if the signature is fully covered and there is only one applicable method,
1298
+ # we can try to inline it even if the signature is not a dispatch tuple.
1299
+ # -- But don't try it if we already tried to handle the match in the revisit_idx
1300
+ # case, because that'll (necessarily) be the same method.
1301
+ if length (infos) > 1
1302
+ (metharg, methsp) = ccall (:jl_type_intersection_with_env , Any, (Any, Any),
1303
+ atype, only_method. sig):: SimpleVector
1304
+ match = MethodMatch (metharg, methsp:: SimpleVector , only_method, true )
1305
+ else
1306
+ @assert length (meth) == 1
1307
+ match = meth[1 ]
1308
+ end
1309
+ handle_match! (match, argtypes, flag, state, cases, true , false ) || return nothing
1310
+ any_fully_covered = handled_all_cases = match. fully_covers
1311
+ elseif ! handled_all_cases
1259
1312
# if we've not seen all candidates, union split is valid only for dispatch tuples
1260
1313
filter! (case:: InliningCase -> isdispatchtuple (case. sig), cases)
1261
1314
end
@@ -1313,14 +1366,18 @@ end
1313
1366
1314
1367
function handle_match! (
1315
1368
match:: MethodMatch , argtypes:: Vector{Any} , flag:: UInt8 , state:: InliningState ,
1316
- cases:: Vector{InliningCase} , allow_abstract:: Bool = false )
1369
+ cases:: Vector{InliningCase} , allow_abstract:: Bool = false , check_sparams :: Bool = false )
1317
1370
spec_types = match. spec_types
1318
1371
allow_abstract || isdispatchtuple (spec_types) || return false
1319
- # we may see duplicated dispatch signatures here when a signature gets widened
1320
- # during abstract interpretation: for the purpose of inlining, we can just skip
1321
- # processing this dispatch candidate
1322
- _any (case-> case. sig === spec_types, cases) && return true
1323
- item = analyze_method! (match, argtypes, flag, state)
1372
+ if check_sparams
1373
+ # we may see duplicated dispatch signatures here when a signature gets widened
1374
+ # during abstract interpretation: for the purpose of inlining, we can just skip
1375
+ # processing this dispatch candidate
1376
+ _any (case-> case. sig === spec_types, cases) && return true
1377
+ item = analyze_method! (match, argtypes, flag, state, true )
1378
+ else
1379
+ item = analyze_method! (match, argtypes, flag, state)
1380
+ end
1324
1381
item === nothing && return false
1325
1382
push! (cases, InliningCase (spec_types, item))
1326
1383
return true
0 commit comments