• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

pmd / pmd / 403

22 Feb 2026 04:05PM UTC coverage: 78.975% (+0.02%) from 78.958%
403

push

github

web-flow
chore: Small release process fixes (#6447)

18539 of 24360 branches covered (76.1%)

Branch coverage included in aggregate %.

40429 of 50307 relevant lines covered (80.36%)

0.81 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

86.49
/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/internal/infer/Infer.java
1
/*
2
 * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3
 */
4

5
package net.sourceforge.pmd.lang.java.types.internal.infer;
6

7
import static net.sourceforge.pmd.lang.java.types.TypeConversion.capture;
8
import static net.sourceforge.pmd.lang.java.types.TypeConversion.isWilcardParameterized;
9
import static net.sourceforge.pmd.lang.java.types.TypeOps.asList;
10
import static net.sourceforge.pmd.lang.java.types.TypeOps.subst;
11
import static net.sourceforge.pmd.lang.java.types.internal.InternalMethodTypeItf.cast;
12
import static net.sourceforge.pmd.lang.java.types.internal.infer.ExprOps.isPertinentToApplicability;
13
import static net.sourceforge.pmd.lang.java.types.internal.infer.MethodResolutionPhase.INVOC_LOOSE;
14
import static net.sourceforge.pmd.util.CollectionUtil.listOf;
15
import static net.sourceforge.pmd.util.CollectionUtil.setOf;
16

17
import java.util.ArrayList;
18
import java.util.Collections;
19
import java.util.List;
20

21
import org.checkerframework.checker.nullness.qual.NonNull;
22
import org.checkerframework.checker.nullness.qual.Nullable;
23

24
import net.sourceforge.pmd.lang.java.symbols.JClassSymbol;
25
import net.sourceforge.pmd.lang.java.types.JArrayType;
26
import net.sourceforge.pmd.lang.java.types.JClassType;
27
import net.sourceforge.pmd.lang.java.types.JMethodSig;
28
import net.sourceforge.pmd.lang.java.types.JTypeMirror;
29
import net.sourceforge.pmd.lang.java.types.JTypeVar;
30
import net.sourceforge.pmd.lang.java.types.Substitution;
31
import net.sourceforge.pmd.lang.java.types.TypeOps;
32
import net.sourceforge.pmd.lang.java.types.TypeOps.Convertibility;
33
import net.sourceforge.pmd.lang.java.types.TypeSystem;
34
import net.sourceforge.pmd.lang.java.types.internal.infer.ExprCheckHelper.ExprChecker;
35
import net.sourceforge.pmd.lang.java.types.internal.infer.ExprMirror.CtorInvocationMirror;
36
import net.sourceforge.pmd.lang.java.types.internal.infer.ExprMirror.FunctionalExprMirror;
37
import net.sourceforge.pmd.lang.java.types.internal.infer.ExprMirror.InvocationMirror;
38
import net.sourceforge.pmd.lang.java.types.internal.infer.ExprMirror.InvocationMirror.MethodCtDecl;
39
import net.sourceforge.pmd.lang.java.types.internal.infer.ExprMirror.PolyExprMirror;
40
import net.sourceforge.pmd.lang.java.types.internal.infer.InferenceVar.BoundKind;
41
import net.sourceforge.pmd.util.CollectionUtil;
42
import net.sourceforge.pmd.util.OptionalBool;
43

44
/**
45
 * Main entry point for type inference.
46
 */
47
@SuppressWarnings("PMD.CompareObjectsWithEquals")
1✔
48
public final class Infer {
49

50
    final ExprOps exprOps;
51

52
    private final TypeInferenceLogger logger;
53

54
    private final boolean isPreJava8;
55
    private final TypeSystem ts;
56

57
    private final MethodCtDecl noCtDecl;
58

59
    /** This is a sentinel for when the CTDecl was resolved, but invocation failed. */
60
    private final MethodCtDecl failedInvocation;
61

62
    private final SupertypeCheckCache supertypeCheckCache = new SupertypeCheckCache();
1✔
63

64
    /**
65
     * Creates a new instance.
66
     *
67
     * @param ts         Type system
68
     * @param jdkVersion JDK version to use. Type inference was changed
69
     *                   in Java 8 to propagate the context type.
70
     * @param logger     Strategy to log failures
71
     */
72
    public Infer(TypeSystem ts, int jdkVersion, TypeInferenceLogger logger) {
1✔
73
        this.ts = ts;
1✔
74
        this.isPreJava8 = jdkVersion < 8;
1✔
75
        this.logger = logger;
1✔
76

77
        this.noCtDecl = MethodCtDecl.unresolved(ts);
1✔
78
        this.failedInvocation = MethodCtDecl.unresolved(ts);
1✔
79

80
        this.exprOps = new ExprOps(this);
1✔
81
    }
1✔
82

83
    public boolean isPreJava8() {
84
        return isPreJava8;
1✔
85
    }
86

87
    public TypeSystem getTypeSystem() {
88
        return ts;
1✔
89
    }
90

91
    public TypeInferenceLogger getLogger() {
92
        return logger;
1✔
93
    }
94

95
    public MethodCtDecl getMissingCtDecl() {
96
        return noCtDecl;
1✔
97
    }
98

99
    public MethodCtDecl getFailedInvocation() {
100
        return failedInvocation;
1✔
101
    }
102

103
    public PolySite<FunctionalExprMirror> newFunctionalSite(FunctionalExprMirror mirror, @Nullable JTypeMirror expectedType) {
104
        return new PolySite<>(mirror, expectedType);
1✔
105
    }
106

107
    public MethodCallSite newCallSite(InvocationMirror expr, @Nullable JTypeMirror expectedType) {
108
        return newCallSite(expr, expectedType, null, null, false);
1✔
109
    }
110

111
    /** Site for a nested poly expr. */
112
    // package
113
    MethodCallSite newCallSite(InvocationMirror expr,
114
                               @Nullable JTypeMirror expectedType,
115
                               @Nullable MethodCallSite outerSite,
116
                               @Nullable InferenceContext outerCtx,
117
                               boolean isSpecificityCheck) {
118
        return new MethodCallSite(expr, expectedType, outerSite, outerCtx != null ? outerCtx : emptyContext(), isSpecificityCheck);
1✔
119
    }
120

121
    InferenceContext emptyContext() {
122
        return newContextFor(Collections.emptyList());
1✔
123
    }
124

125
    @NonNull
126
    InferenceContext newContextFor(JMethodSig m) {
127
        return newContextFor(m.getTypeParameters());
1✔
128
    }
129

130
    InferenceContext newContextFor(List<JTypeVar> tvars) {
131
        return newContextFor(tvars, true);
1✔
132
    }
133

134
    InferenceContext newContextFor(List<JTypeVar> tvars, boolean addPrimaryBound) {
135
        return new InferenceContext(ts, supertypeCheckCache, tvars, logger, addPrimaryBound);
1✔
136
    }
137

138
    /**
139
     * Infer lambdas and method references that have a target type: cast contexts,
140
     * and some assignment contexts (not inferred, not return from lambda).
141
     */
142
    public void inferFunctionalExprInUnambiguousContext(PolySite<FunctionalExprMirror> site) {
143
        FunctionalExprMirror expr = site.getExpr();
1✔
144
        JTypeMirror expected = site.getExpectedType();
1✔
145
        try {
146
            if (expected == null) {
1✔
147
                throw ResolutionFailedException.missingTargetTypeForFunctionalExpr(logger, expr);
1✔
148
            }
149
            addBoundOrDefer(null, emptyContext(), INVOC_LOOSE, expr, expected);
1✔
150
        } catch (ResolutionFailedException rfe) {
1✔
151
            rfe.getFailure().addContext(null, site, null);
1✔
152
            logger.logResolutionFail(rfe.getFailure());
1✔
153
            expr.finishFailedInference(expected);
1✔
154
        }
1✔
155
    }
1✔
156

157

158
    /**
159
     * Determines the most specific applicable method for the given call site.
160
     *
161
     * <p>The returned method type may be {@link TypeSystem#UNRESOLVED_METHOD},
162
     * in which case no method is applicable (compile-time error).
163
     *
164
     * <p>The returned method type may contain un-instantiated inference
165
     * variables, which depend on the target type. In that case those
166
     * variables and their bounds will have been duplicated into the
167
     * inference context of the [site].
168
     *
169
     * <p>The given call site should mention information like the expected
170
     * return type, to help inference. This should be non-null if we're
171
     * in an invocation or assignment context, otherwise can be left blank.
172
     */
173
    public void inferInvocationRecursively(MethodCallSite site) {
174
        MethodCtDecl ctdecl = goToInvocationWithFallback(site);
1✔
175
        InvocationMirror expr = site.getExpr();
1✔
176
        expr.setCompileTimeDecl(ctdecl);
1✔
177
        if (ctdecl == noCtDecl) {
1✔
178
            expr.setInferredType(fallbackType(expr));
1✔
179
        } else {
180
            expr.setInferredType(ctdecl.getMethodType().getReturnType());
1✔
181
        }
182
    }
1✔
183

184

185
    /**
186
     * Given a symbol S and a type T which is assumed to be
187
     * a supertype of some parameterization of S, infer this
188
     * parameterization.
189
     */
190
    public JTypeMirror inferParameterizationForSubtype(JClassSymbol symbol, JTypeMirror superType) {
191
        if (!symbol.isGeneric()) {
1✔
192
            return ts.typeOf(symbol, false);
1✔
193
        } else if (superType instanceof JClassType && ((JClassType) superType).hasErasedSuperTypes()) {
1!
194
            return ts.typeOf(symbol, true); // raw type
×
195
        }
196

197
        // otherwise infer
198
        try {
199
            InferenceContext ctx = newContextFor(symbol.getTypeParameters());
1✔
200
            JTypeMirror withIvars = ctx.mapToIVars(ts.typeOf(symbol, false));
1✔
201
            if (TypeOps.isConvertible(withIvars, superType).bySubtyping()) {
1!
202
                ctx.solve(true);
1✔
203
                return InferenceContext.groundOrWildcard(withIvars);
1✔
204
            }
205
        } catch (ResolutionFailedException ignored) {
×
206

207
        }
×
208
        return ts.parameterise(symbol, Collections.nCopies(symbol.getTypeParameterCount(), ts.ERROR));
×
209
    }
210

211
    private MethodCtDecl goToInvocationWithFallback(MethodCallSite site) {
212
        MethodCtDecl ctdecl = getCompileTimeDecl(site);
1✔
213
        if (ctdecl == noCtDecl) {
1✔
214
            return noCtDecl;
1✔
215
        }
216

217
        site.clearFailures();
1✔
218

219
        // do invocation
220

221
        { // reduce scope of invocType, outside of here it's failed
222
            final MethodCtDecl invocType = finishInstantiation(site, ctdecl);
1✔
223
            if (invocType != failedInvocation) {
1✔
224
                return invocType;
1✔
225
            }
226
        }
227
        // ok we failed, we can still use some info from the ctdecl
228

229
        JMethodSig fallback = deleteTypeParams(cast(ctdecl.getMethodType()).adaptedMethod());
1✔
230
        logger.fallbackInvocation(fallback, site);
1✔
231
        // When we fail in invocation we need to clean-up partial
232
        // data from the tree. This means erasing inference variables
233
        // from the types stored in AST nodes.
234
        site.getExpr().groundTree();
1✔
235

236
        return ctdecl.withMethod(fallback, true);
1✔
237
    }
238

239
    private JTypeMirror fallbackType(PolyExprMirror expr) {
240
        JTypeMirror t = expr.unresolvedType();
1✔
241
        return t == null ? ts.UNKNOWN : t;
1✔
242
    }
243

244
    // If the invocation fails, replace type parameters with a placeholder,
245
    // to not hide a bad failure, while preserving the method if possible
246
    private JMethodSig deleteTypeParams(JMethodSig m) {
247
        if (!m.isGeneric()) {
1✔
248
            return m;
1✔
249
        }
250
        List<JTypeVar> tparams = m.getTypeParameters();
1✔
251
        List<JTypeMirror> nErrors = Collections.nCopies(tparams.size(), ts.ERROR);
1✔
252
        return m.subst(Substitution.mapping(tparams, nErrors));
1✔
253
    }
254

255
    /**
256
     * Similar to {@link #inferInvocationRecursively(MethodCallSite)} for
257
     * subexpressions. This never returns a fallback method.
258
     *
259
     * <p>A return of {@link #noCtDecl} indicates no overload is applicable.
260
     * <p>A return of {@link #failedInvocation} means there is a maximally
261
     * specific compile-time declaration, but it failed invocation, meaning,
262
     * it couldn't be linked to its context. If so, the outer inference process
263
     * must be terminated with a failure.
264
     * <p>This ne
265
     *
266
     * <p>The returned method type may contain un-instantiated inference
267
     * variables, which depend on the target type. In that case those
268
     * variables and their bounds will have been duplicated into the
269
     * inference context of the [site].
270
     */
271
    @NonNull MethodCtDecl determineInvocationTypeOrFail(MethodCallSite site) {
272
        MethodCtDecl ctdecl = getCompileTimeDecl(site);
1✔
273
        if (ctdecl == noCtDecl) {
1✔
274
            return ctdecl;
1✔
275
        }
276

277
        return finishInstantiation(site, ctdecl);
1✔
278
    }
279

280

281
    public @NonNull MethodCtDecl getCompileTimeDecl(MethodCallSite site) {
282
        if (site.getExpr().getCtDecl() == null) {
1✔
283
            MethodCtDecl ctdecl = computeCompileTimeDecl(site);
1✔
284
            site.getExpr().setCompileTimeDecl(ctdecl); // cache it for later
1✔
285
        }
286
        return site.getExpr().getCtDecl();
1✔
287
    }
288

289
    /**
290
     * Determines the most specific applicable method for the given call site.
291
     *
292
     * <p>The returned method type may be null, in which case no method is
293
     * applicable (compile-time error).
294
     */
295
    private @NonNull MethodCtDecl computeCompileTimeDecl(MethodCallSite site) {
296

297
        /*
298
         *  The process starts with a set of candidates and refines it
299
         *  iteratively. Applicability/best applicability are the only
300
         *  ones which needs inference.
301
         *
302
         *  visible ⊇ accessible ⊇ potentially applicable ⊇ applicable ⊇ best applicable
303
         */
304
        List<JMethodSig> potentiallyApplicable = new ArrayList<>();
1✔
305
        for (JMethodSig it : site.getExpr().getAccessibleCandidates()) {
1✔
306
            if (isPotentiallyApplicable(it, site.getExpr())) {
1✔
307
                potentiallyApplicable.add(it);
1✔
308
            }
309
        }
1✔
310

311
        if (potentiallyApplicable.isEmpty()) {
1✔
312
            logger.noApplicableCandidates(site);
1✔
313
            return noCtDecl;
1✔
314
        }
315

316
        for (MethodResolutionPhase phase : MethodResolutionPhase.APPLICABILITY_TESTS) {
1✔
317
            PhaseOverloadSet applicable = new PhaseOverloadSet(this, phase, site);
1✔
318
            for (JMethodSig m : potentiallyApplicable) {
1✔
319
                site.resetInferenceData();
1✔
320

321
                MethodCtDecl candidate = logInference(site, phase, m);
1✔
322

323
                if (!candidate.isFailed()) {
1✔
324
                    applicable.add(candidate);
1✔
325
                }
326
            }
1✔
327

328
            if (applicable.nonEmpty()) {
1✔
329
                MethodCtDecl bestApplicable = applicable.getMostSpecificOrLogAmbiguity(logger);
1✔
330
                JMethodSig adapted = ExprOps.adaptGetClass(bestApplicable.getMethodType(),
1✔
331
                                                           site.getExpr()::getErasedReceiverType);
1✔
332
                return bestApplicable.withMethod(adapted).neededSpecificityCheck(applicable.threwAwaySomeOverloads());
1✔
333
            }
334
        }
1✔
335

336

337
        logger.noCompileTimeDeclaration(site);
1✔
338

339
        return noCtDecl;
1✔
340
    }
341

342
    @NonNull MethodCtDecl finishInstantiation(MethodCallSite site, MethodCtDecl ctdecl) {
343
        JMethodSig m = ctdecl.getMethodType();
1✔
344
        InvocationMirror expr = site.getExpr();
1✔
345

346
        site.loadInferenceData(ctdecl);
1✔
347
        site.setInInvocation();
1✔
348

349
        if (site.canSkipInvocation()) {
1✔
350
            assert assertReturnIsGround(m);
1!
351

352
            expr.setInferredType(m.getReturnType());
1✔
353
            logger.skipInstantiation(m, site);
1✔
354
            return ctdecl;
1✔
355
        }
356

357
        // start the inference over with the original method, including
358
        // arguments that are not pertinent to applicability (lambdas)
359
        // to instantiate all tvars
360

361
        return logInference(site,
1✔
362
                            ctdecl.getResolvePhase().asInvoc(),
1✔
363
                            cast(ctdecl.getMethodType()).adaptedMethod());
1✔
364
    }
365

366
    // this is skipped when running without assertions
367
    private boolean assertReturnIsGround(JMethodSig t) {
368
        subst(t.getReturnType(), var -> {
1✔
369
            assert !(var instanceof InferenceVar)
1!
370
                : "Expected a ground type " + t;
371
            assert !(var instanceof JTypeVar) || !t.getTypeParameters().contains(var)
1!
372
                : "Some type parameters have not been instantiated";
373
            return var;
1✔
374
        });
375
        return true;
1✔
376
    }
377

378

379
    private @NonNull MethodCtDecl logInference(MethodCallSite site, MethodResolutionPhase phase, JMethodSig m) {
380
        logger.startInference(m, site, phase);
1✔
381
        @Nullable JMethodSig candidate = instantiateMethodOrCtor(site, phase, m);
1✔
382
        logger.endInference(candidate);
1✔
383

384
        if (candidate == null) {
1✔
385
            return failedInvocation;
1✔
386
        } else {
387
            return new MethodCtDecl(
1✔
388
                candidate,
389
                phase,
390
                site.canSkipInvocation(),
1✔
391
                OptionalBool.definitely(site.needsUncheckedConversion()),
1✔
392
                false,
393
                site.getExpr(),
1✔
394
                false
395
            );
396
        }
397
    }
398

399

400
    private @Nullable JMethodSig instantiateMethodOrCtor(MethodCallSite site, MethodResolutionPhase phase, JMethodSig m) {
401
        return site.getExpr() instanceof CtorInvocationMirror ? instantiateConstructor(m, site, phase)
1✔
402
                                                              : instantiateMethod(m, site, phase);
1✔
403
    }
404

405

406
    /**
407
     * Infer type arguments for the given method at the method call.
408
     * Returns null if no instantiations exist, ie the method is not
409
     * applicable.
410
     *
411
     * @param m     Candidate method
412
     * @param site  Descriptor of the context of the call.
413
     * @param phase Phase in which the method is reviewed
414
     */
415
    private @Nullable JMethodSig instantiateMethod(JMethodSig m,
416
                                                   MethodCallSite site,
417
                                                   MethodResolutionPhase phase) {
418
        if (phase.requiresVarargs() && !m.isVarargs()) {
1✔
419
            return null; // don't log such a dumb mistake
1✔
420
        }
421
        try {
422
            return instantiateMaybeNoInfer(m, site, phase);
1✔
423
        } catch (ResolutionFailedException e) {
1✔
424
            ResolutionFailure failure = e.getFailure();
1✔
425
            failure.addContext(m, site, phase);
1✔
426
            logger.logResolutionFail(failure);
1✔
427
            return null;
1✔
428
        }
429
    }
430

431
    private @Nullable JMethodSig instantiateConstructor(JMethodSig cons,
432
                                                        MethodCallSite site,
433
                                                        MethodResolutionPhase phase) {
434

435
        CtorInvocationMirror expr = (CtorInvocationMirror) site.getExpr();
1✔
436

437
        JTypeMirror newTypeMaybeInvalid = expr.getNewType();
1✔
438
        if (!(newTypeMaybeInvalid instanceof JClassType)) {
1!
439
            // no constructor, note also, that array type constructors
440
            // don't go through these routines because there's no overloading
441
            // of array ctors. They're handled entirely in LazyTypeResolver.
442
            return null;
×
443
        }
444

445
        JClassType newType = (JClassType) newTypeMaybeInvalid;
1✔
446
        boolean isAdapted = needsAdaptation(expr, newType);
1✔
447
        JMethodSig adapted = isAdapted
1✔
448
                             ? adaptGenericConstructor(cons, newType, expr)
1✔
449
                             : cons;
1✔
450

451
        site.maySkipInvocation(!isAdapted);
1✔
452

453
        @Nullable JMethodSig result = instantiateMethod(adapted, site, phase);
1✔
454
        if (isAdapted && result != null) {
1✔
455
            // undo the adaptation
456

457
            JTypeMirror rtype = result.getReturnType();
1✔
458
            if (!rtype.isInterface()) {
1✔
459
                // this is for anonymous class ctors
460
                // an interface cannot declare a constructor
461
                result = cast(result).withOwner(rtype);
1✔
462
            }
463
            return cast(result).withTypeParams(null);
1✔
464

465
        }
466
        return result;
1✔
467
    }
468

469
    private boolean needsAdaptation(CtorInvocationMirror expr, JClassType newType) {
470
        return expr.isDiamond()
1✔
471
            || newType.isParameterizedType() // ???
1✔
472
            || expr.isAnonymous();
1✔
473
    }
474

475
    /**
476
     * Transform the constructor of a generic class so that its type parameters
477
     * mention the type params of the declaring class. This enables diamond
478
     * inference, we just treat the class type params to infer as
479
     * additional inference variables.
480
     *
481
     * <p>E.g. for
482
     *
483
     * {@code class ArrayList<T> { ArrayList() {} } }
484
     *
485
     * the constructor is represented as a method type:
486
     *
487
     * {@code <T> ArrayList<T> new() }
488
     *
489
     * the return type being that of the created instance.
490
     */
491
    private static JMethodSig adaptGenericConstructor(JMethodSig cons, JClassType newType, CtorInvocationMirror expr) {
492
        assert cons.isConstructor() : cons + " should be a constructor";
1!
493

494
        if (cons.getDeclaringType().isArray()) {
1!
495
            // array methods do not need to be adapted and don't support it
496
            return cons;
×
497
        }
498

499
        // replace the return type so that anonymous class ctors return the supertype
500
        JMethodSig adaptedSig = cast(cast(cons).withReturnType(newType)).markAsAdapted();
1✔
501

502
        List<JTypeVar> newTypeFormals = newType.getFormalTypeParams();
1✔
503
        if (newTypeFormals.isEmpty()) {
1✔
504
            // non-generic type
505
            return adaptedSig;
1✔
506
        } else {
507
            // else transform the constructor to add the type parameters
508
            // of the constructed type
509
            List<JTypeVar> consParams = cons.getTypeParameters();
1✔
510
            if (consParams.size() > cons.getSymbol().getTypeParameterCount()) {
1✔
511
                // it's already been adapted
512
                assert consParams.equals(CollectionUtil.concatView(cons.getSymbol().getTypeParameters(), newTypeFormals));
1!
513
                return adaptedSig;
1✔
514
            } else if (!expr.isDiamond()) {
1✔
515
                // it doesn't need adaptation, we're not doing diamond inference
516
                return adaptedSig;
1✔
517
            }
518

519
            List<JTypeVar> tparams = CollectionUtil.concatView(consParams, newTypeFormals);
1✔
520

521
            // type parameters are not part of the adapted signature, so that when we reset
522
            // the signature for invocation inference, we don't duplicate new type parameters
523
            return cast(cast(adaptedSig).withTypeParams(tparams)).markAsAdapted();
1✔
524
        }
525
    }
526

527
    /**
528
     * Catch the easy cases before starting inference.
529
     */
530
    private JMethodSig instantiateMaybeNoInfer(JMethodSig m, MethodCallSite site, MethodResolutionPhase phase) {
531

532
        if (!m.isGeneric()) {
1✔
533
            // non-generic methods may mention explicit type arguments
534
            // for compatibility, they must be ignored.
535

536
            // check that the arguments are conformant
537
            // the inference context is empty because all param types are ground.
538
            addArgsConstraints(emptyContext(), m, site, phase);
1✔
539
            return m;
1✔
540
        }
541

542
        InvocationMirror expr = site.getExpr();
1✔
543
        List<JTypeMirror> explicitTargs = expr.getExplicitTypeArguments();
1✔
544

545
        if (!explicitTargs.isEmpty()) {
1✔
546
            // we have explicit type arguments
547
            List<JTypeVar> tparams = m.getTypeParameters();
1✔
548

549
            if (tparams.size() != explicitTargs.size()) {
1!
550
                // normally checked by isPotentiallyApplicable
551
                throw ResolutionFailedException.incompatibleTypeParamCount(logger, site.getExpr(), m, explicitTargs.size(), tparams.size());
×
552
            }
553

554
            Substitution explicitSubst = Substitution.mapping(tparams, explicitTargs);
1✔
555

556
            for (int i = 0; i < tparams.size(); i++) {
1✔
557
                JTypeMirror explicit = explicitTargs.get(i);
1✔
558
                JTypeMirror upperBound = tparams.get(i).getUpperBound().subst(explicitSubst);
1✔
559

560
                if (explicit.isConvertibleTo(upperBound).never()) {
1!
561
                    throw ResolutionFailedException.incompatibleBound(logger, explicit, upperBound, expr.getExplicitTargLoc(i));
×
562
                }
563
            }
564

565

566
            JMethodSig subst = m.subst(explicitSubst);
1✔
567

568
            // check that the arguments are conformant
569
            // the inference context is empty because all param types are ground.
570
            addArgsConstraints(emptyContext(), subst, site, phase);
1✔
571

572
            return subst;
1✔
573
        }
574

575

576
        site.maySkipInvocation(!ExprOps.isContextDependent(m) && site.getOuterCtx().isGround(m.getReturnType()));
1!
577

578
        return instantiateImpl(m, site, phase);
1✔
579
    }
580

581
    /**
582
     * Perform actual inference. If the method is return-type-polymorphic,
583
     * then we delegate the solving to the call site's inference context,
584
     * which knows more, however we add inference vars and their constraints
585
     * to it.
586
     * During non-invocation phases, this inference
587
     * checks for validity but doesn't commit any inferred types.
588
     */
589
    private JMethodSig instantiateImpl(JMethodSig m, MethodCallSite site, MethodResolutionPhase phase) {
590

591
        InferenceContext infCtx = newContextFor(m); // b0
1✔
592
        logger.ctxInitialization(infCtx, m);
1✔
593

594
        try {
595

596
            if (phase.isInvocation() && !isPreJava8) {
1✔
597
                m = doReturnChecksAndChangeReturnType(m, site, infCtx);
1✔
598
            }
599

600
            addArgsConstraints(infCtx, m, site, phase); // c
1✔
601
            infCtx.incorporate(); // b2
1✔
602

603
            if (phase.isInvocation() || site.canSkipInvocation()) {
1✔
604
                // this may throw for incompatible bounds
605
                return tryToSolve(m, site, infCtx, phase);
1✔
606
            } else {
607
                // we solve on a **copy**. We are only testing applicability
608
                // see: https://docs.oracle.com/javase/specs/jls/se9/html/jls-18.html#jls-18.5.1
609
                // as per https://docs.oracle.com/javase/specs/jls/se9/html/jls-18.html#jls-18.5.2
610
                // we only test it can reduce, we don't commit inferred types at this stage
611
                InferenceContext ctxCopy = infCtx.shallowCopy();
1✔
612
                logger.applicabilityTest(ctxCopy);
1✔
613
                try {
614
                    ctxCopy.solve(/*onlyBoundedVars:*/isPreJava8());
1✔
615
                } finally {
616
                    logger.finishApplicabilityTest();
1✔
617
                }
618
                // if unchecked conversion was needed, update the site for invocation pass
619
                if (ctxCopy.needsUncheckedConversion()) {
1✔
620
                    site.setNeedsUncheckedConversion();
1✔
621
                }
622

623
                // don't commit any types
624
                return infCtx.mapToIVars(m);
1✔
625
            }
626
        } finally {
627
            // Note that even if solve succeeded, listeners checking deferred
628
            // bounds may still throw ResolutionFailedException, in which case
629
            // by the laws of finally, this exception will be thrown and the
630
            // return value will be ignored.
631
            if (phase.isInvocation() || site.canSkipInvocation()) {
1✔
632
                infCtx.callListeners();
1✔
633
            }
634
        }
635
    }
636

637
    /**
638
     * Actually tries to solve and commit inference types as per
639
     * https://docs.oracle.com/javase/specs/jls/se9/html/jls-18.html#jls-18.5.2
640
     * {@code infCtx} must already at the B2 state for this method to be called.
641
     */
642
    private JMethodSig tryToSolve(JMethodSig m, MethodCallSite site, InferenceContext infCtx, MethodResolutionPhase phase) {
643
        boolean shouldPropagate = phase.isInvocation() && shouldPropagateOutwards(m.getReturnType(), site, infCtx);
1✔
644

645
        //propagate outwards if needed
646
        if (shouldPropagate) {
1✔
647
            // propagate inference context outwards and exit
648
            // the outer context will solve the variables and call listeners
649
            // of this context
650
            logger.propagateAndAbort(infCtx, site.getOuterCtx());
1✔
651
            infCtx.duplicateInto(site.getOuterCtx());
1✔
652
            return infCtx.mapToIVars(m);
1✔
653
        }
654

655
        // this may throw for incompatible bounds
656
        boolean isDone = infCtx.solve(/*onlyBoundedVars:*/isPreJava8());
1✔
657

658
        if (isPreJava8() && !isDone) {
1✔
659
            // this means we're not in an invocation context,
660
            // if we are, we must ignore it in java 7
661
            if (site.getOuterCtx().isEmpty()) {
1✔
662
                // Then add the return constraints late
663
                // Java 7 only uses the context type if the arguments are not enough
664
                // https://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.12.2.8
665
                m = doReturnChecksAndChangeReturnType(m, site, infCtx);
1✔
666
            }
667
            // otherwise force solving remaining vars
668
            infCtx.solve();
1✔
669
        }
670

671
        // instantiate vars and return
672
        return InferenceContext.finalGround(infCtx.mapToIVars(m));
1✔
673
    }
674

675
    private JMethodSig doReturnChecksAndChangeReturnType(JMethodSig m, MethodCallSite site, InferenceContext infCtx) {
676
        logger.startReturnChecks();
1✔
677
        JTypeMirror actualResType = addReturnConstraints(infCtx, m, site); // b3
1✔
678
        logger.endReturnChecks();
1✔
679
        m = cast(m).withReturnType(actualResType);
1✔
680
        return m;
1✔
681
    }
682

683

684
    private boolean shouldPropagateOutwards(JTypeMirror resultType, MethodCallSite target, InferenceContext inferenceContext) {
685
        return !isPreJava8
1✔
686
            && !target.getOuterCtx().isEmpty()  //enclosing context is a generic method
1✔
687
            && !inferenceContext.isGround(resultType)   //return type contains inference vars
1✔
688
            && !(resultType instanceof InferenceVar    //no eager instantiation is required (as per 18.5.2)
689
            && needsEagerInstantiation((InferenceVar) resultType, target.getExpectedType(), inferenceContext));
1!
690
    }
691

692
    /**
693
     * Add more constraints on the inference vars based on the expected
694
     * return type at the call site. This is described in
695
     *
696
     * https://docs.oracle.com/javase/specs/jls/se9/html/jls-18.html#jls-18.5.2.1
697
     *
698
     * under "Let B3 be the bound set derived from B2 as follows."
699
     *
700
     * <p>This binds the ivars of this context to those of the outer context.
701
     */
702
    private JTypeMirror addReturnConstraints(InferenceContext infCtx, JMethodSig m, MethodCallSite site) {
703

704
        /*
705
            Remember: calling stuff like isConvertible or isSubtype
706
            adds constraints on the type variables that are found there.
707
         */
708

709
        JTypeMirror resultType = m.getReturnType();
1✔
710
        if (site.needsUncheckedConversion()) {
1✔
711
            // if unchecked conversion is necessary, the result type,
712
            // and all thrown exception types, are erased.
713
            resultType = resultType.getErasure();
1✔
714
        }
715
        resultType = infCtx.mapToIVars(resultType);
1✔
716
        InferenceContext outerInfCtx = site.getOuterCtx();
1✔
717

718
        if (!infCtx.isGround(resultType) && !outerInfCtx.isEmpty() && resultType instanceof JClassType) {
1✔
719
            JClassType resClass = capture((JClassType) resultType);
1✔
720
            resultType = resClass;
1✔
721

722
            for (JTypeMirror targ : resClass.getTypeArgs()) {
1✔
723
                if (targ instanceof JTypeVar && ((JTypeVar) targ).isCaptured()) {
1!
724
                    infCtx.addVar((JTypeVar) targ);
1✔
725
                }
726
            }
1✔
727
            resultType = infCtx.mapToIVars(resultType);
1✔
728
        }
729

730
        JTypeMirror actualRes = site.getExpectedType();
1✔
731
        if (actualRes == null) {
1✔
732
            actualRes = ts.OBJECT;
1✔
733
        }
734

735
        if (resultType instanceof InferenceVar) {
1✔
736
            InferenceVar retVar = (InferenceVar) resultType;
1✔
737
            if (needsEagerInstantiation(retVar, actualRes, infCtx)) {
1!
738
                infCtx.solve(retVar);
×
739
                infCtx.callListeners();
×
740
                if (isConvertible(retVar.getInst(), actualRes, true).never()) {
×
741
                    actualRes = ts.OBJECT;
×
742
                }
743
            } else if (actualRes.isPrimitive()) {
1✔
744
                actualRes = actualRes.box();
1✔
745
            }
746
        }
747

748
        if (isConvertible(resultType, outerInfCtx.mapToIVars(actualRes), true).never()) {
1✔
749
            throw ResolutionFailedException.incompatibleReturn(logger, site.getExpr(), resultType, actualRes);
1✔
750
        }
751

752
        return resultType;
1✔
753
    }
754

755

756
    /**
757
     * Returns true if the inference var needs to be instantiated eagerly,
758
     * as described in JLS§18.5.2.1. (Poly Method Invocation Compatibility)
759
     *
760
     * https://docs.oracle.com/javase/specs/jls/se9/html/jls-18.html#jls-18.5.2.1
761
     *
762
     * @param alpha  Inference var
763
     * @param t      Target type of the invocation
764
     * @param infCtx Inference context
765
     */
766
    private boolean needsEagerInstantiation(InferenceVar alpha, JTypeMirror t, InferenceContext infCtx) {
767
        if (t == null) {
1!
768
            return false;
×
769
        }
770

771
        if (t.isPrimitive()) {
1✔
772
            // T is a primitive type, and one of the primitive wrapper classes is an instantiation,
773
            // upper bound, or lower bound for alpha in B2.
774

775
            for (JTypeMirror b : alpha.getBounds(BoundKind.ALL)) {
1✔
776
                if (b.isBoxedPrimitive()) {
1!
777
                    return true;
×
778
                }
779
            }
1✔
780
            return false;
1✔
781
        }
782

783
        // T is a reference type, but is not a wildcard-parameterized type, and either
784

785
        if (!t.isPrimitive() && !isWilcardParameterized(t)) {
1!
786
            // i) B2 contains a bound of one of the forms alpha = S or S <: alpha,
787
            //    where S is a wildcard-parameterized type, or
788
            for (JTypeMirror s : alpha.getBounds(BoundKind.EQ_LOWER)) {
1✔
789
                if (isWilcardParameterized(s)) {
1!
790
                    return true;
×
791
                }
792
            }
1✔
793

794
            // ii) B2 contains two bounds of the forms S1 <: alpha and S2 <: alpha,
795
            // where S1 and S2 have supertypes that are two different
796
            // parameterizations of the same generic class or interface.
797

798
            for (JTypeMirror aLowerBound : alpha.getBounds(BoundKind.LOWER)) {
1✔
799
                for (JTypeMirror anotherLowerBound : alpha.getBounds(BoundKind.LOWER)) {
1✔
800
                    if (aLowerBound != anotherLowerBound
1!
801
                        && infCtx.isGround(aLowerBound)
×
802
                        && infCtx.isGround(anotherLowerBound)
×
803
                        && commonSuperWithDiffParameterization(aLowerBound, anotherLowerBound)) {
×
804
                        return true;
×
805
                    }
806
                }
1✔
807
            }
1✔
808
        }
809

810
        // T is a parameterization of a generic class or interface, G,
811
        // and B2 contains a bound of one of the forms alpha = S or S <: alpha,
812
        // where there exists no type of the form G<...> that is a
813
        // supertype of S, but the raw type G is a supertype of S
814

815
        if (t.isParameterizedType()) {
1✔
816
            for (JTypeMirror b : alpha.getBounds(BoundKind.EQ_LOWER)) {
1✔
817
                JTypeMirror sup = b.getAsSuper(((JClassType) t).getSymbol());
1✔
818
                if (sup != null && sup.isRaw()) {
1!
819
                    return true;
×
820
                }
821
            }
1✔
822
        }
823
        return false;
1✔
824
    }
825

826
    private boolean commonSuperWithDiffParameterization(JTypeMirror t, JTypeMirror s) {
827
        JTypeMirror lubResult = ts.lub(listOf(t, s));
×
828
        if (lubResult.isBottom() || lubResult.isTop() || t.isBottom() || s.isBottom()) {
×
829
            return false;
×
830
        }
831
        for (JTypeMirror sup : asList(lubResult)) {
×
832
            if (sup.isParameterizedType()) {
×
833
                JClassSymbol sym = ((JClassType) sup).getSymbol();
×
834
                JTypeMirror asSuperOfT = t.getAsSuper(sym);
×
835
                JTypeMirror asSuperOfS = s.getAsSuper(sym);
×
836
                assert asSuperOfS != null : "s <: sup, because sup is part of the LUB of s";
×
837
                assert asSuperOfT != null : "t <: sup, because sup is part of the LUB of t";
×
838
                if (!asSuperOfS.equals(asSuperOfT)) {
×
839
                    return true;
×
840
                }
841
            }
842
        }
×
843
        return false;
×
844
    }
845

846
    /**
847
     * Generate bounds on the ivars based on the expected/actual types
848
     * of the arguments to the call. This is described in
849
     *
850
     * https://docs.oracle.com/javase/specs/jls/se9/html/jls-18.html#jls-18.5.1
851
     *
852
     * as being the set C.
853
     *
854
     * <p>For invocation applicability inference (phases {@link MethodResolutionPhase#STRICT STRICT}
855
     * through {@link MethodResolutionPhase#VARARGS VARARGS}), only arguments
856
     * that are {@linkplain ExprOps#isPertinentToApplicability(ExprMirror, JMethodSig, JTypeMirror, InvocationMirror)
857
     * pertinent to applicability}
858
     * are considered. Arguments like lambdas do not influence the applicability
859
     * check beyond checking their basic 'shape' (number of params)
860
     * to check that the method is {@linkplain #isPotentiallyApplicable(JMethodSig, InvocationMirror) potentially
861
     * applicable}, which is done very much earlier.
862
     * So they don't add constraints during those first phases.
863
     *
864
     * <p>When we have found an applicable method and are instantiating it
865
     * (phases {@link MethodResolutionPhase#INVOC_STRICT INVOC_STRICT} through {@link
866
     * MethodResolutionPhase#INVOC_VARARGS INVOC_VARARGS}),
867
     * all arguments are considered so as to yield sharper bounds.
868
     *
869
     * @param infCtx Inference context
870
     * @param m      Tested method
871
     * @param site   Invocation expression
872
     * @param phase  Phase (determines what constraints are allowed)
873
     */
874
    private void addArgsConstraints(InferenceContext infCtx, JMethodSig m, MethodCallSite site, MethodResolutionPhase phase) {
875
        logger.startArgsChecks();
1✔
876

877
        InvocationMirror expr = site.getExpr();
1✔
878

879
        boolean varargsRequired = phase.requiresVarargs();
1✔
880

881
        if (!varargsRequired && m.getArity() != expr.getArgumentCount()) {
1✔
882
            throw ResolutionFailedException.incompatibleArity(logger, expr.getArgumentCount(), m.getArity(), expr);
1✔
883
        }
884

885
        List<JTypeMirror> fs = m.getFormalParameters();
1✔
886

887
        @Nullable
888
        JArrayType varargsParam = varargsRequired && m.isVarargs() ? (JArrayType) fs.get(fs.size() - 1) : null;
1!
889
        int lastP = varargsParam == null ? fs.size() : fs.size() - 1;
1✔
890

891
        List<ExprMirror> args = expr.getArgumentExpressions();
1✔
892

893
        for (int i = 0; i < lastP; i++) {
1✔
894
            ExprMirror ei = args.get(i);
1✔
895

896

897
            if (phase.isInvocation() || isPertinentToApplicability(ei, m, fs.get(i), expr)) {
1✔
898
                JTypeMirror stdType = ei.getStandaloneType();
1✔
899
                JTypeMirror fi = infCtx.mapToIVars(fs.get(i));
1✔
900

901
                logger.startArg(i, ei, fi);
1✔
902

903
                if (!phase.canBox()) {
1✔
904
                    // these are cases where applicability is impossible (in strict ctx)
905
                    if (stdType != null && stdType.isPrimitive() != fi.isPrimitive() && stdType != ts.UNKNOWN) {
1✔
906
                        throw ResolutionFailedException.incompatibleFormal(logger, ei, stdType, fi);
1✔
907
                    }
908
                }
909

910
                addBoundOrDefer(site, infCtx, phase, ei, fi);
1✔
911

912
                logger.endArg();
1✔
913
            } else {
1✔
914
                // then the final reinvocation is necessary
915
                site.maySkipInvocation(false);
1✔
916
                logger.skipArgAsNonPertinent(i, ei);
1✔
917
            }
918
        }
919

920
        if (varargsRequired && varargsParam != null) {
1!
921
            JTypeMirror varargsComponent = infCtx.mapToIVars(varargsParam.getComponentType());
1✔
922

923
            // possibly some varargs arguments left
924
            for (int i = lastP; i < args.size(); i++) {
1✔
925
                ExprMirror ei = args.get(i);
1✔
926

927
                if (phase.isInvocation() || isPertinentToApplicability(ei, m, varargsComponent, expr)) {
1!
928
                    logger.startArg(i, ei, varargsComponent);
1✔
929
                    addBoundOrDefer(site, infCtx, phase, ei, varargsComponent);
1✔
930
                    logger.endArg();
1✔
931
                } else {
932
                    site.maySkipInvocation(false);
×
933
                    logger.skipArgAsNonPertinent(i, ei);
×
934
                }
935
            }
936
        }
937
        logger.endArgsChecks();
1✔
938
    }
1✔
939

940
    /**
941
     * This corresponds to the attribution of expression compatibility
942
     * constraints in https://docs.oracle.com/javase/specs/jls/se9/html/jls-18.html#jls-18.2.1
943
     * although it's not implemented as described.
944
     *
945
     * See {@link ExprCheckHelper#isCompatible(JTypeMirror, ExprMirror)}.
946
     */
947
    private void addBoundOrDefer(@Nullable MethodCallSite site, InferenceContext infCtx, MethodResolutionPhase phase, @NonNull ExprMirror arg, @NonNull JTypeMirror formalType) {
948
        ExprChecker exprChecker =
1✔
949
            (ctx, exprType, formalType1) -> checkConvertibleOrDefer(ctx, exprType, formalType1, arg, phase, site);
1✔
950

951
        ExprCheckHelper helper = new ExprCheckHelper(infCtx, phase, exprChecker, site, this);
1✔
952
        if (!helper.isCompatible(formalType, arg)) {
1✔
953
            throw ResolutionFailedException.incompatibleFormalExprNoReason(logger, arg, formalType);
1✔
954
        }
955
    }
1✔
956

957
    /**
958
     * Add a compatibility constraint between an exprType and a formalType.
959
     * This asserts {@code exprType <: formalType}, the arg parameter is only
960
     * used for reporting.
961
     *
962
     * <p>This method is called back to by {@link ExprCheckHelper#isCompatible(JTypeMirror, ExprMirror)}.
963
     */
964
    void checkConvertibleOrDefer(InferenceContext infCtx, JTypeMirror exprType, JTypeMirror formalType, ExprMirror arg, MethodResolutionPhase phase, @Nullable MethodCallSite site) {
965
        if (!infCtx.isGround(formalType) || !infCtx.isGround(exprType)) {
1✔
966
            // defer the check
967
            infCtx.addInstantiationListener(setOf(formalType, exprType), solvedCtx -> checkConvertibleOrDefer(solvedCtx, exprType, formalType, arg, phase, site));
1✔
968
        }
969

970
        JTypeMirror groundE = infCtx.ground(exprType);
1✔
971
        JTypeMirror groundF = infCtx.ground(formalType);
1✔
972

973
        // This method call does all the work of adding constraints
974
        // If groundE or groundF are in fact not ground, then constraints
975
        // on the ivars that appear within them are implicitly added during
976
        // the subtyping check. The call then returns true and we return
977
        // normally
978

979
        // If they are ground, then they must conform to each other else
980
        // the exception stops the resolution process.
981
        Convertibility isConvertible = isConvertible(groundE, groundF, phase.canBox());
1✔
982
        if (isConvertible.never()) {
1✔
983
            throw ResolutionFailedException.incompatibleFormal(logger, arg, groundE, groundF);
1✔
984
        } else if (isConvertible.withUncheckedWarning()) {
1✔
985
            if (site != null) {
1!
986
                site.setNeedsUncheckedConversion();
1✔
987
            } else {
988
                infCtx.setNeedsUncheckedConversion();
×
989
            }
990
        }
991
    }
1✔
992

993
    /**
994
     * Convertibility in *invocation* context.
995
     *
996
     * https://docs.oracle.com/javase/specs/jls/se8/html/jls-5.html#jls-5.3
997
     */
998
    static Convertibility isConvertible(JTypeMirror exprType, JTypeMirror formalType, boolean canBox) {
999
        if (exprType == formalType) {
1✔
1000
            // fast path
1001
            return Convertibility.SUBTYPING;
1✔
1002
        }
1003

1004
        if (canBox && exprType.isPrimitive() ^ formalType.isPrimitive()) {
1✔
1005
            // then boxing conversions may be useful
1006
            Convertibility result = TypeOps.isConvertible(exprType.box(), formalType.box());
1✔
1007
            if (!result.never()) {
1✔
1008
                return result;
1✔
1009
            } else {
1010
                return TypeOps.isConvertible(exprType.unbox(), formalType.unbox());
1✔
1011
            }
1012
        }
1013

1014
        return TypeOps.isConvertible(exprType, formalType);
1✔
1015
    }
1016

1017
    /**
1018
     * Returns true if the method is potentially applicable to the invocation
1019
     * expression expr, as specified in JLS§15.12.2.1.
1020
     *
1021
     * https://docs.oracle.com/javase/specs/jls/se9/html/jls-15.html#jls-15.12.2.1
1022
     *
1023
     * <p>This assumes the name of the method matches the expression, and
1024
     * the method is accessible.
1025
     *
1026
     * @param m    Method to test
1027
     * @param expr Invocation expression
1028
     */
1029
    boolean isPotentiallyApplicable(JMethodSig m, InvocationMirror expr) {
1030

1031
        if (m.isGeneric()
1✔
1032
            && !expr.getExplicitTypeArguments().isEmpty()
1✔
1033
            && expr.getExplicitTypeArguments().size() != m.getTypeParameters().size()) {
1!
1034
            return false;
×
1035
        }
1036

1037
        List<ExprMirror> args = expr.getArgumentExpressions();
1✔
1038

1039
        if (!m.isVarargs()) {
1✔
1040
            // we can avoid computing formal parameters by using getArity here
1041
            if (args.size() != m.getArity()) {
1✔
1042
                return false;
1✔
1043
            }
1044

1045
            List<JTypeMirror> fs = m.getFormalParameters();
1✔
1046
            for (int i = 0; i < args.size(); i++) {
1✔
1047
                if (!exprOps.isPotentiallyCompatible(m, args.get(i), fs.get(i))) {
1✔
1048
                    return false;
1✔
1049
                }
1050
            }
1051

1052
        } else {
1✔
1053
            List<JTypeMirror> fs = m.getFormalParameters();
1✔
1054

1055
            // test first n-1 params
1056
            int varargIdx = fs.size() - 1;
1✔
1057
            for (int i = 0; i < varargIdx; i++) {
1✔
1058
                if (i >= args.size()) {
1✔
1059
                    // not enough arguments
1060
                    return false;
1✔
1061
                }
1062

1063
                if (!exprOps.isPotentiallyCompatible(m, args.get(i), fs.get(i))) {
1✔
1064
                    return false;
1✔
1065
                }
1066
            }
1067

1068
            if (args.size() == varargIdx - 1) {
1!
1069
                return true;
×
1070
            }
1071

1072
            if (args.size() == fs.size()) {
1✔
1073
                ExprMirror last = args.get(varargIdx);
1✔
1074
                JArrayType t = (JArrayType) fs.get(varargIdx);
1✔
1075

1076
                return exprOps.isPotentiallyCompatible(m, last, t)
1✔
1077
                    || exprOps.isPotentiallyCompatible(m, last, t.getComponentType());
1✔
1078
            }
1079

1080
            if (args.size() > fs.size()) {
1✔
1081
                JTypeMirror t = ((JArrayType) fs.get(varargIdx)).getComponentType();
1✔
1082
                for (int i = varargIdx; i < args.size(); i++) {
1✔
1083
                    if (!exprOps.isPotentiallyCompatible(m, args.get(i), t)) {
1✔
1084
                        return false;
1✔
1085
                    }
1086
                }
1087
            }
1088
        }
1089

1090
        return true;
1✔
1091
    }
1092

1093

1094
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc