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

pmd / pmd / 19

29 May 2025 04:22PM UTC coverage: 77.723% (-0.03%) from 77.757%
19

push

github

adangel
Fix #5621: [java] Fix FPs with UnusedPrivateMethod (#5727)

Merge pull request #5727 from oowekyala:issue5621-unusedprivatemethod

17705 of 23734 branches covered (74.6%)

Branch coverage included in aggregate %.

50 of 52 new or added lines in 9 files covered. (96.15%)

81 existing lines in 6 files now uncovered.

38845 of 49024 relevant lines covered (79.24%)

0.8 hits per line

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

86.02
/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.FieldNamingConventions", "PMD.CompareObjectsWithEquals"})
1✔
48
public final class Infer {
49

50
    final ExprOps exprOps;
51

52
    public final TypeInferenceLogger LOG; // SUPPRESS CHECKSTYLE just easier to read I think
53

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

57
    private final MethodCtDecl NO_CTDECL; // SUPPRESS CHECKSTYLE same
58

59
    /** This is a sentinel for when the CTDecl was resolved, but invocation failed. */
60
    final MethodCtDecl FAILED_INVOCATION; // SUPPRESS CHECKSTYLE same
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.LOG = logger;
1✔
76

77
        this.NO_CTDECL = MethodCtDecl.unresolved(ts);
1✔
78
        this.FAILED_INVOCATION = 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 LOG;
×
93
    }
94

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

99
    public PolySite<FunctionalExprMirror> newFunctionalSite(FunctionalExprMirror mirror, @Nullable JTypeMirror expectedType) {
100
        return new PolySite<>(mirror, expectedType);
1✔
101
    }
102

103
    public MethodCallSite newCallSite(InvocationMirror expr, @Nullable JTypeMirror expectedType) {
104
        return newCallSite(expr, expectedType, null, null, false);
1✔
105
    }
106

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

117
    InferenceContext emptyContext() {
118
        return newContextFor(Collections.emptyList());
1✔
119
    }
120

121
    @NonNull
122
    InferenceContext newContextFor(JMethodSig m) {
123
        return newContextFor(m.getTypeParameters());
1✔
124
    }
125

126
    InferenceContext newContextFor(List<JTypeVar> tvars) {
127
        return newContextFor(tvars, true);
1✔
128
    }
129

130
    InferenceContext newContextFor(List<JTypeVar> tvars, boolean addPrimaryBound) {
131
        return new InferenceContext(ts, supertypeCheckCache, tvars, LOG, addPrimaryBound);
1✔
132
    }
133

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

153

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

180

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

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

203
        }
×
204
        return ts.parameterise(symbol, Collections.nCopies(symbol.getTypeParameterCount(), ts.ERROR));
×
205
    }
206

207
    private MethodCtDecl goToInvocationWithFallback(MethodCallSite site) {
208
        MethodCtDecl ctdecl = getCompileTimeDecl(site);
1✔
209
        if (ctdecl == NO_CTDECL) { // NOPMD CompareObjectsWithEquals
1✔
210
            return NO_CTDECL;
1✔
211
        }
212

213
        site.clearFailures();
1✔
214

215
        // do invocation
216

217
        { // reduce scope of invocType, outside of here it's failed
218
            final MethodCtDecl invocType = finishInstantiation(site, ctdecl);
1✔
219
            if (invocType != FAILED_INVOCATION) { // NOPMD CompareObjectsWithEquals
1✔
220
                return invocType;
1✔
221
            }
222
        }
223
        // ok we failed, we can still use some info from the ctdecl
224

225
        JMethodSig fallback = deleteTypeParams(cast(ctdecl.getMethodType()).adaptedMethod());
1✔
226
        LOG.fallbackInvocation(fallback, site);
1✔
227

228
        return ctdecl.withMethod(fallback, true);
1✔
229
    }
230

231
    private JTypeMirror fallbackType(PolyExprMirror expr) {
232
        JTypeMirror t = expr.unresolvedType();
1✔
233
        return t == null ? ts.UNKNOWN : t;
1✔
234
    }
235

236
    // If the invocation fails, replace type parameters with a placeholder,
237
    // to not hide a bad failure, while preserving the method if possible
238
    private JMethodSig deleteTypeParams(JMethodSig m) {
239
        if (!m.isGeneric()) {
1✔
240
            return m;
1✔
241
        }
242
        List<JTypeVar> tparams = m.getTypeParameters();
1✔
243
        List<JTypeMirror> nErrors = Collections.nCopies(tparams.size(), ts.ERROR);
1✔
244
        return m.subst(Substitution.mapping(tparams, nErrors));
1✔
245
    }
246

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

269
        return finishInstantiation(site, ctdecl);
1✔
270
    }
271

272

273
    public @NonNull MethodCtDecl getCompileTimeDecl(MethodCallSite site) {
274
        if (site.getExpr().getCtDecl() == null) {
1✔
275
            MethodCtDecl ctdecl = computeCompileTimeDecl(site);
1✔
276
            site.getExpr().setCompileTimeDecl(ctdecl); // cache it for later
1✔
277
        }
278
        return site.getExpr().getCtDecl();
1✔
279
    }
280

281
    /**
282
     * Determines the most specific applicable method for the given call site.
283
     *
284
     * <p>The returned method type may be null, in which case no method is
285
     * applicable (compile-time error).
286
     */
287
    private @NonNull MethodCtDecl computeCompileTimeDecl(MethodCallSite site) {
288

289
        /*
290
         *  The process starts with a set of candidates and refines it
291
         *  iteratively. Applicability/best applicability are the only
292
         *  ones which needs inference.
293
         *
294
         *  visible ⊇ accessible ⊇ potentially applicable ⊇ applicable ⊇ best applicable
295
         */
296
        List<JMethodSig> potentiallyApplicable = new ArrayList<>();
1✔
297
        for (JMethodSig it : site.getExpr().getAccessibleCandidates()) {
1✔
298
            if (isPotentiallyApplicable(it, site.getExpr())) {
1✔
299
                potentiallyApplicable.add(it);
1✔
300
            }
301
        }
1✔
302

303
        if (potentiallyApplicable.isEmpty()) {
1✔
304
            LOG.noApplicableCandidates(site);
1✔
305
            return NO_CTDECL;
1✔
306
        }
307

308
        for (MethodResolutionPhase phase : MethodResolutionPhase.APPLICABILITY_TESTS) {
1✔
309
            PhaseOverloadSet applicable = new PhaseOverloadSet(this, phase, site);
1✔
310
            for (JMethodSig m : potentiallyApplicable) {
1✔
311
                site.resetInferenceData();
1✔
312

313
                MethodCtDecl candidate = logInference(site, phase, m);
1✔
314

315
                if (!candidate.isFailed()) {
1✔
316
                    applicable.add(candidate);
1✔
317
                }
318
            }
1✔
319

320
            if (applicable.nonEmpty()) {
1✔
321
                MethodCtDecl bestApplicable = applicable.getMostSpecificOrLogAmbiguity(LOG);
1✔
322
                JMethodSig adapted = ExprOps.adaptGetClass(bestApplicable.getMethodType(),
1✔
323
                                                           site.getExpr()::getErasedReceiverType);
1✔
324
                return bestApplicable.withMethod(adapted);
1✔
325
            }
326
        }
1✔
327

328

329
        LOG.noCompileTimeDeclaration(site);
1✔
330

331
        return NO_CTDECL;
1✔
332
    }
333

334
    @NonNull MethodCtDecl finishInstantiation(MethodCallSite site, MethodCtDecl ctdecl) {
335
        JMethodSig m = ctdecl.getMethodType();
1✔
336
        InvocationMirror expr = site.getExpr();
1✔
337

338
        site.loadInferenceData(ctdecl);
1✔
339
        site.setInInvocation();
1✔
340

341
        if (site.canSkipInvocation()) {
1✔
342
            assert assertReturnIsGround(m);
1!
343

344
            expr.setInferredType(m.getReturnType());
1✔
345
            LOG.skipInstantiation(m, site);
1✔
346
            return ctdecl;
1✔
347
        }
348

349
        // start the inference over with the original method, including
350
        // arguments that are not pertinent to applicability (lambdas)
351
        // to instantiate all tvars
352

353
        return logInference(site,
1✔
354
                            ctdecl.getResolvePhase().asInvoc(),
1✔
355
                            cast(ctdecl.getMethodType()).adaptedMethod());
1✔
356
    }
357

358
    // this is skipped when running without assertions
359
    private boolean assertReturnIsGround(JMethodSig t) {
360
        subst(t.getReturnType(), var -> {
1✔
361
            assert !(var instanceof InferenceVar)
1!
362
                : "Expected a ground type " + t;
363
            assert !(var instanceof JTypeVar) || !t.getTypeParameters().contains(var)
1!
364
                : "Some type parameters have not been instantiated";
365
            return var;
1✔
366
        });
367
        return true;
1✔
368
    }
369

370

371
    private @NonNull MethodCtDecl logInference(MethodCallSite site, MethodResolutionPhase phase, JMethodSig m) {
372
        LOG.startInference(m, site, phase);
1✔
373
        @Nullable JMethodSig candidate = instantiateMethodOrCtor(site, phase, m);
1✔
374
        LOG.endInference(candidate);
1✔
375

376
        if (candidate == null) {
1✔
377
            return FAILED_INVOCATION;
1✔
378
        } else {
379
            return new MethodCtDecl(candidate,
1✔
380
                                    phase,
381
                                    site.canSkipInvocation(),
1✔
382
                    OptionalBool.definitely(site.needsUncheckedConversion()),
1✔
383
                                    false,
384
                                    site.getExpr());
1✔
385
        }
386
    }
387

388

389
    private @Nullable JMethodSig instantiateMethodOrCtor(MethodCallSite site, MethodResolutionPhase phase, JMethodSig m) {
390
        return site.getExpr() instanceof CtorInvocationMirror ? instantiateConstructor(m, site, phase)
1✔
391
                                                              : instantiateMethod(m, site, phase);
1✔
392
    }
393

394

395
    /**
396
     * Infer type arguments for the given method at the method call.
397
     * Returns null if no instantiations exist, ie the method is not
398
     * applicable.
399
     *
400
     * @param m     Candidate method
401
     * @param site  Descriptor of the context of the call.
402
     * @param phase Phase in which the method is reviewed
403
     */
404
    private @Nullable JMethodSig instantiateMethod(JMethodSig m,
405
                                                   MethodCallSite site,
406
                                                   MethodResolutionPhase phase) {
407
        if (phase.requiresVarargs() && !m.isVarargs()) {
1✔
408
            return null; // don't log such a dumb mistake
1✔
409
        }
410
        try {
411
            return instantiateMaybeNoInfer(m, site, phase);
1✔
412
        } catch (ResolutionFailedException e) {
1✔
413
            ResolutionFailure failure = e.getFailure();
1✔
414
            failure.addContext(m, site, phase);
1✔
415
            LOG.logResolutionFail(failure);
1✔
416
            return null;
1✔
417
        }
418
    }
419

420
    private @Nullable JMethodSig instantiateConstructor(JMethodSig cons,
421
                                                        MethodCallSite site,
422
                                                        MethodResolutionPhase phase) {
423

424
        CtorInvocationMirror expr = (CtorInvocationMirror) site.getExpr();
1✔
425

426
        JTypeMirror newTypeMaybeInvalid = expr.getNewType();
1✔
427
        if (!(newTypeMaybeInvalid instanceof JClassType)) {
1!
428
            // no constructor, note also, that array type constructors
429
            // don't go through these routines because there's no overloading
430
            // of array ctors. They're handled entirely in LazyTypeResolver.
431
            return null;
×
432
        }
433

434
        JClassType newType = (JClassType) newTypeMaybeInvalid;
1✔
435
        boolean isAdapted = needsAdaptation(expr, newType);
1✔
436
        JMethodSig adapted = isAdapted
1✔
437
                             ? adaptGenericConstructor(cons, newType, expr)
1✔
438
                             : cons;
1✔
439

440
        site.maySkipInvocation(!isAdapted);
1✔
441

442
        @Nullable JMethodSig result = instantiateMethod(adapted, site, phase);
1✔
443
        if (isAdapted && result != null) {
1✔
444
            // undo the adaptation
445

446
            JTypeMirror rtype = result.getReturnType();
1✔
447
            if (!rtype.isInterface()) {
1✔
448
                // this is for anonymous class ctors
449
                // an interface cannot declare a constructor
450
                result = cast(result).withOwner(rtype);
1✔
451
            }
452
            return cast(result).withTypeParams(null);
1✔
453

454
        }
455
        return result;
1✔
456
    }
457

458
    private boolean needsAdaptation(CtorInvocationMirror expr, JClassType newType) {
459
        return expr.isDiamond()
1✔
460
            || newType.isParameterizedType() // ???
1✔
461
            || expr.isAnonymous();
1✔
462
    }
463

464
    /**
465
     * Transform the constructor of a generic class so that its type parameters
466
     * mention the type params of the declaring class. This enables diamond
467
     * inference, we just treat the class type params to infer as
468
     * additional inference variables.
469
     *
470
     * <p>E.g. for
471
     *
472
     * {@code class ArrayList<T> { ArrayList() {} } }
473
     *
474
     * the constructor is represented as a method type:
475
     *
476
     * {@code <T> ArrayList<T> new() }
477
     *
478
     * the return type being that of the created instance.
479
     */
480
    private static JMethodSig adaptGenericConstructor(JMethodSig cons, JClassType newType, CtorInvocationMirror expr) {
481
        assert cons.isConstructor() : cons + " should be a constructor";
1!
482

483
        if (cons.getDeclaringType().isArray()) {
1!
484
            // array methods do not need to be adapted and don't support it
485
            return cons;
×
486
        }
487

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

491
        List<JTypeVar> newTypeFormals = newType.getFormalTypeParams();
1✔
492
        if (newTypeFormals.isEmpty()) {
1✔
493
            // non-generic type
494
            return adaptedSig;
1✔
495
        } else {
496
            // else transform the constructor to add the type parameters
497
            // of the constructed type
498
            List<JTypeVar> consParams = cons.getTypeParameters();
1✔
499
            if (consParams.size() > cons.getSymbol().getTypeParameterCount()) {
1✔
500
                // it's already been adapted
501
                assert consParams.equals(CollectionUtil.concatView(cons.getSymbol().getTypeParameters(), newTypeFormals));
1!
502
                return adaptedSig;
1✔
503
            } else if (!expr.isDiamond()) {
1✔
504
                // it doesn't need adaptation, we're not doing diamond inference
505
                return adaptedSig;
1✔
506
            }
507

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

510
            // type parameters are not part of the adapted signature, so that when we reset
511
            // the signature for invocation inference, we don't duplicate new type parameters
512
            return cast(cast(adaptedSig).withTypeParams(tparams)).markAsAdapted();
1✔
513
        }
514
    }
515

516
    /**
517
     * Catch the easy cases before starting inference.
518
     */
519
    private JMethodSig instantiateMaybeNoInfer(JMethodSig m, MethodCallSite site, MethodResolutionPhase phase) {
520

521
        if (!m.isGeneric()) {
1✔
522
            // non-generic methods may mention explicit type arguments
523
            // for compatibility, they must be ignored.
524

525
            // check that the arguments are conformant
526
            // the inference context is empty because all param types are ground.
527
            addArgsConstraints(emptyContext(), m, site, phase);
1✔
528
            return m;
1✔
529
        }
530

531
        InvocationMirror expr = site.getExpr();
1✔
532
        List<JTypeMirror> explicitTargs = expr.getExplicitTypeArguments();
1✔
533

534
        if (!explicitTargs.isEmpty()) {
1✔
535
            // we have explicit type arguments
536
            List<JTypeVar> tparams = m.getTypeParameters();
1✔
537

538
            if (tparams.size() != explicitTargs.size()) {
1!
539
                // normally checked by isPotentiallyApplicable
540
                throw ResolutionFailedException.incompatibleTypeParamCount(LOG, site.getExpr(), m, explicitTargs.size(), tparams.size());
×
541
            }
542

543
            Substitution explicitSubst = Substitution.mapping(tparams, explicitTargs);
1✔
544

545
            for (int i = 0; i < tparams.size(); i++) {
1✔
546
                JTypeMirror explicit = explicitTargs.get(i);
1✔
547
                JTypeMirror upperBound = tparams.get(i).getUpperBound().subst(explicitSubst);
1✔
548

549
                if (explicit.isConvertibleTo(upperBound).never()) {
1!
550
                    throw ResolutionFailedException.incompatibleBound(LOG, explicit, upperBound, expr.getExplicitTargLoc(i));
×
551
                }
552
            }
553

554

555
            JMethodSig subst = m.subst(explicitSubst);
1✔
556

557
            // check that the arguments are conformant
558
            // the inference context is empty because all param types are ground.
559
            addArgsConstraints(emptyContext(), subst, site, phase);
1✔
560

561
            return subst;
1✔
562
        }
563

564

565
        site.maySkipInvocation(!ExprOps.isContextDependent(m) && site.getOuterCtx().isGround(m.getReturnType()));
1!
566

567
        return instantiateImpl(m, site, phase);
1✔
568
    }
569

570
    /**
571
     * Perform actual inference. If the method is return-type-polymorphic,
572
     * then we delegate the solving to the call site's inference context,
573
     * which knows more, however we add inference vars and their constraints
574
     * to it.
575
     * During non-invocation phases, this inference
576
     * checks for validity but doesn't commit any inferred types.
577
     */
578
    private JMethodSig instantiateImpl(JMethodSig m, MethodCallSite site, MethodResolutionPhase phase) {
579

580
        InferenceContext infCtx = newContextFor(m); // b0
1✔
581
        LOG.ctxInitialization(infCtx, m);
1✔
582

583
        try {
584

585
            if (phase.isInvocation() && !isPreJava8) {
1✔
586
                m = doReturnChecksAndChangeReturnType(m, site, infCtx);
1✔
587
            }
588

589
            addArgsConstraints(infCtx, m, site, phase); // c
1✔
590
            infCtx.incorporate(); // b2
1✔
591

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

612
                // don't commit any types
613
                return infCtx.mapToIVars(m);
1✔
614
            }
615
        } finally {
616
            // Note that even if solve succeeded, listeners checking deferred
617
            // bounds may still throw ResolutionFailedException, in which case
618
            // by the laws of finally, this exception will be thrown and the
619
            // return value will be ignored.
620
            if (phase.isInvocation() || site.canSkipInvocation()) {
1✔
621
                infCtx.callListeners();
1✔
622
            }
623
        }
624
    }
625

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

634
        //propagate outwards if needed
635
        if (shouldPropagate) {
1✔
636
            // propagate inference context outwards and exit
637
            // the outer context will solve the variables and call listeners
638
            // of this context
639
            LOG.propagateAndAbort(infCtx, site.getOuterCtx());
1✔
640
            infCtx.duplicateInto(site.getOuterCtx());
1✔
641
            return infCtx.mapToIVars(m);
1✔
642
        }
643

644
        // this may throw for incompatible bounds
645
        boolean isDone = infCtx.solve(/*onlyBoundedVars:*/isPreJava8());
1✔
646

647
        if (isPreJava8() && !isDone) {
1✔
648
            // this means we're not in an invocation context,
649
            // if we are, we must ignore it in java 7
650
            if (site.getOuterCtx().isEmpty()) {
1✔
651
                // Then add the return contraints late
652
                // Java 7 only uses the context type if the arguments are not enough
653
                // https://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.12.2.8
654
                m = doReturnChecksAndChangeReturnType(m, site, infCtx);
1✔
655
            }
656
            // otherwise force solving remaining vars
657
            infCtx.solve();
1✔
658
        }
659

660
        // instantiate vars and return
661
        return InferenceContext.finalGround(infCtx.mapToIVars(m));
1✔
662
    }
663

664
    private JMethodSig doReturnChecksAndChangeReturnType(JMethodSig m, MethodCallSite site, InferenceContext infCtx) {
665
        LOG.startReturnChecks();
1✔
666
        JTypeMirror actualResType = addReturnConstraints(infCtx, m, site); // b3
1✔
667
        LOG.endReturnChecks();
1✔
668
        m = cast(m).withReturnType(actualResType);
1✔
669
        return m;
1✔
670
    }
671

672

673
    private boolean shouldPropagateOutwards(JTypeMirror resultType, MethodCallSite target, InferenceContext inferenceContext) {
674
        return !isPreJava8
1✔
675
            && !target.getOuterCtx().isEmpty()  //enclosing context is a generic method
1✔
676
            && !inferenceContext.isGround(resultType)   //return type contains inference vars
1✔
677
            && !(resultType instanceof InferenceVar    //no eager instantiation is required (as per 18.5.2)
678
            && needsEagerInstantiation((InferenceVar) resultType, target.getExpectedType(), inferenceContext));
1!
679
    }
680

681
    /**
682
     * Add more constraints on the inference vars based on the expected
683
     * return type at the call site. This is described in
684
     *
685
     * https://docs.oracle.com/javase/specs/jls/se9/html/jls-18.html#jls-18.5.2.1
686
     *
687
     * under "Let B3 be the bound set derived from B2 as follows."
688
     *
689
     * <p>This binds the ivars of this context to those of the outer context.
690
     */
691
    private JTypeMirror addReturnConstraints(InferenceContext infCtx, JMethodSig m, MethodCallSite site) {
692

693
        /*
694
            Remember: calling stuff like isConvertible or isSubtype
695
            adds constraints on the type variables that are found there.
696
         */
697

698
        JTypeMirror resultType = m.getReturnType();
1✔
699
        if (site.needsUncheckedConversion()) {
1✔
700
            // if unchecked conversion is necessary, the result type,
701
            // and all thrown exception types, are erased.
702
            resultType = resultType.getErasure();
1✔
703
        }
704
        resultType = infCtx.mapToIVars(resultType);
1✔
705
        InferenceContext outerInfCtx = site.getOuterCtx();
1✔
706

707
        if (!infCtx.isGround(resultType) && !outerInfCtx.isEmpty() && resultType instanceof JClassType) {
1✔
708
            JClassType resClass = capture((JClassType) resultType);
1✔
709
            resultType = resClass;
1✔
710

711
            for (JTypeMirror targ : resClass.getTypeArgs()) {
1✔
712
                if (targ instanceof JTypeVar && ((JTypeVar) targ).isCaptured()) {
1!
713
                    infCtx.addVar((JTypeVar) targ);
1✔
714
                }
715
            }
1✔
716
            resultType = infCtx.mapToIVars(resultType);
1✔
717
        }
718

719
        JTypeMirror actualRes = site.getExpectedType();
1✔
720
        if (actualRes == null) {
1✔
721
            actualRes = ts.OBJECT;
1✔
722
        }
723

724
        if (resultType instanceof InferenceVar) {
1✔
725
            InferenceVar retVar = (InferenceVar) resultType;
1✔
726
            if (needsEagerInstantiation(retVar, actualRes, infCtx)) {
1!
727
                infCtx.solve(retVar);
×
728
                infCtx.callListeners();
×
729
                if (isConvertible(retVar.getInst(), actualRes, true).never()) {
×
730
                    actualRes = ts.OBJECT;
×
731
                }
732
            } else if (actualRes.isPrimitive()) {
1✔
733
                actualRes = actualRes.box();
1✔
734
            }
735
        }
736

737
        if (isConvertible(resultType, outerInfCtx.mapToIVars(actualRes), true).never()) {
1✔
738
            throw ResolutionFailedException.incompatibleReturn(LOG, site.getExpr(), resultType, actualRes);
1✔
739
        }
740

741
        return resultType;
1✔
742
    }
743

744

745
    /**
746
     * Returns true if the inference var needs to be instantiated eagerly,
747
     * as described in JLS§18.5.2.1. (Poly Method Invocation Compatibility)
748
     *
749
     * https://docs.oracle.com/javase/specs/jls/se9/html/jls-18.html#jls-18.5.2.1
750
     *
751
     * @param alpha  Inference var
752
     * @param t      Target type of the invocation
753
     * @param infCtx Inference context
754
     */
755
    private boolean needsEagerInstantiation(InferenceVar alpha, JTypeMirror t, InferenceContext infCtx) {
756
        if (t == null) {
1!
757
            return false;
×
758
        }
759

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

764
            for (JTypeMirror b : alpha.getBounds(BoundKind.ALL)) {
1✔
765
                if (b.isBoxedPrimitive()) {
1!
766
                    return true;
×
767
                }
768
            }
1✔
769
            return false;
1✔
770
        }
771

772
        // T is a reference type, but is not a wildcard-parameterized type, and either
773

774
        if (!t.isPrimitive() && !isWilcardParameterized(t)) {
1!
775
            // i) B2 contains a bound of one of the forms alpha = S or S <: alpha,
776
            //    where S is a wildcard-parameterized type, or
777
            for (JTypeMirror s : alpha.getBounds(BoundKind.EQ_LOWER)) {
1✔
778
                if (isWilcardParameterized(s)) {
1!
779
                    return true;
×
780
                }
781
            }
1✔
782

783
            // ii) B2 contains two bounds of the forms S1 <: alpha and S2 <: alpha,
784
            // where S1 and S2 have supertypes that are two different
785
            // parameterizations of the same generic class or interface.
786

787
            for (JTypeMirror aLowerBound : alpha.getBounds(BoundKind.LOWER)) {
1✔
788
                for (JTypeMirror anotherLowerBound : alpha.getBounds(BoundKind.LOWER)) {
1✔
789
                    if (aLowerBound != anotherLowerBound // NOPMD CompareObjectsWithEquals
1!
790
                        && infCtx.isGround(aLowerBound)
×
791
                        && infCtx.isGround(anotherLowerBound)
×
792
                        && commonSuperWithDiffParameterization(aLowerBound, anotherLowerBound)) {
×
793
                        return true;
×
794
                    }
795
                }
1✔
796
            }
1✔
797
        }
798

799
        // T is a parameterization of a generic class or interface, G,
800
        // and B2 contains a bound of one of the forms alpha = S or S <: alpha,
801
        // where there exists no type of the form G<...> that is a
802
        // supertype of S, but the raw type G is a supertype of S
803

804
        if (t.isParameterizedType()) {
1✔
805
            for (JTypeMirror b : alpha.getBounds(BoundKind.EQ_LOWER)) {
1✔
806
                JTypeMirror sup = b.getAsSuper(((JClassType) t).getSymbol());
1✔
807
                if (sup != null && sup.isRaw()) {
1!
808
                    return true;
×
809
                }
810
            }
1✔
811
        }
812
        return false;
1✔
813
    }
814

815
    private boolean commonSuperWithDiffParameterization(JTypeMirror t, JTypeMirror s) {
816
        JTypeMirror lubResult = ts.lub(listOf(t, s));
×
817
        if (lubResult.isBottom() || lubResult.isTop() || t.isBottom() || s.isBottom()) {
×
818
            return false;
×
819
        }
820
        for (JTypeMirror sup : asList(lubResult)) {
×
821
            if (sup.isParameterizedType()) {
×
822
                JClassSymbol sym = ((JClassType) sup).getSymbol();
×
823
                JTypeMirror asSuperOfT = t.getAsSuper(sym);
×
824
                JTypeMirror asSuperOfS = s.getAsSuper(sym);
×
825
                assert asSuperOfS != null : "s <: sup, because sup is part of the LUB of s";
×
826
                assert asSuperOfT != null : "t <: sup, because sup is part of the LUB of t";
×
827
                if (!asSuperOfS.equals(asSuperOfT)) {
×
828
                    return true;
×
829
                }
830
            }
831
        }
×
832
        return false;
×
833
    }
834

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

866
        InvocationMirror expr = site.getExpr();
1✔
867

868
        boolean varargsRequired = phase.requiresVarargs();
1✔
869

870
        if (!varargsRequired && m.getArity() != expr.getArgumentCount()) {
1✔
871
            throw ResolutionFailedException.incompatibleArity(LOG, expr.getArgumentCount(), m.getArity(), expr);
1✔
872
        }
873

874
        List<JTypeMirror> fs = m.getFormalParameters();
1✔
875

876
        @Nullable
877
        JArrayType varargsParam = varargsRequired && m.isVarargs() ? (JArrayType) fs.get(fs.size() - 1) : null;
1!
878
        int lastP = varargsParam == null ? fs.size() : fs.size() - 1;
1✔
879

880
        List<ExprMirror> args = expr.getArgumentExpressions();
1✔
881

882
        for (int i = 0; i < lastP; i++) {
1✔
883
            ExprMirror ei = args.get(i);
1✔
884

885

886
            if (phase.isInvocation() || isPertinentToApplicability(ei, m, fs.get(i), expr)) {
1✔
887
                JTypeMirror stdType = ei.getStandaloneType();
1✔
888
                JTypeMirror fi = infCtx.mapToIVars(fs.get(i));
1✔
889

890
                LOG.startArg(i, ei, fi);
1✔
891

892
                if (!phase.canBox()) {
1✔
893
                    // these are cases where applicability is impossible (in strict ctx)
894
                    if (stdType != null && stdType.isPrimitive() != fi.isPrimitive() && stdType != ts.UNKNOWN) {
1✔
895
                        throw ResolutionFailedException.incompatibleFormal(LOG, ei, stdType, fi);
1✔
896
                    }
897
                }
898

899
                addBoundOrDefer(site, infCtx, phase, ei, fi);
1✔
900

901
                LOG.endArg();
1✔
902
            } else {
1✔
903
                // then the final reinvocation is necessary
904
                site.maySkipInvocation(false);
1✔
905
                LOG.skipArgAsNonPertinent(i, ei);
1✔
906
            }
907
        }
908

909
        if (varargsRequired && varargsParam != null) {
1!
910
            JTypeMirror varargsComponent = infCtx.mapToIVars(varargsParam.getComponentType());
1✔
911

912
            // possibly some varargs arguments left
913
            for (int i = lastP; i < args.size(); i++) {
1✔
914
                ExprMirror ei = args.get(i);
1✔
915

916
                if (phase.isInvocation() || isPertinentToApplicability(ei, m, varargsComponent, expr)) {
1!
917
                    LOG.startArg(i, ei, varargsComponent);
1✔
918
                    addBoundOrDefer(site, infCtx, phase, ei, varargsComponent);
1✔
919
                    LOG.endArg();
1✔
920
                } else {
921
                    site.maySkipInvocation(false);
×
922
                    LOG.skipArgAsNonPertinent(i, ei);
×
923
                }
924
            }
925
        }
926
        LOG.endArgsChecks();
1✔
927
    }
1✔
928

929
    /**
930
     * This corresponds to the attribution of expression compatibility
931
     * constraints in https://docs.oracle.com/javase/specs/jls/se9/html/jls-18.html#jls-18.2.1
932
     * although it's not implemented as described.
933
     *
934
     * See {@link ExprCheckHelper#isCompatible(JTypeMirror, ExprMirror)}.
935
     */
936
    private void addBoundOrDefer(@Nullable MethodCallSite site, InferenceContext infCtx, MethodResolutionPhase phase, @NonNull ExprMirror arg, @NonNull JTypeMirror formalType) {
937
        ExprChecker exprChecker =
1✔
938
            (ctx, exprType, formalType1) -> checkConvertibleOrDefer(ctx, exprType, formalType1, arg, phase, site);
1✔
939

940
        ExprCheckHelper helper = new ExprCheckHelper(infCtx, phase, exprChecker, site, this);
1✔
941
        if (!helper.isCompatible(formalType, arg)) {
1✔
942
            throw ResolutionFailedException.incompatibleFormalExprNoReason(LOG, arg, formalType);
1✔
943
        }
944
    }
1✔
945

946
    /**
947
     * Add a compatibility constraint between an exprType and a formalType.
948
     * This asserts {@code exprType <: formalType}, the arg parameter is only
949
     * used for reporting.
950
     *
951
     * <p>This method is called back to by {@link ExprCheckHelper#isCompatible(JTypeMirror, ExprMirror)}.
952
     */
953
    void checkConvertibleOrDefer(InferenceContext infCtx, JTypeMirror exprType, JTypeMirror formalType, ExprMirror arg, MethodResolutionPhase phase, @Nullable MethodCallSite site) {
954
        if (!infCtx.isGround(formalType) || !infCtx.isGround(exprType)) {
1✔
955
            // defer the check
956
            infCtx.addInstantiationListener(setOf(formalType, exprType), solvedCtx -> checkConvertibleOrDefer(solvedCtx, exprType, formalType, arg, phase, site));
1✔
957
        }
958

959
        JTypeMirror groundE = infCtx.ground(exprType);
1✔
960
        JTypeMirror groundF = infCtx.ground(formalType);
1✔
961

962
        // This method call does all the work of adding constraints
963
        // If groundE or groundF are in fact not ground, then constraints
964
        // on the ivars that appear within them are implicitly added during
965
        // the subtyping check. The call then returns true and we return
966
        // normally
967

968
        // If they are ground, then they must conform to each other else
969
        // the exception stops the resolution process.
970
        Convertibility isConvertible = isConvertible(groundE, groundF, phase.canBox());
1✔
971
        if (isConvertible.never()) {
1✔
972
            throw ResolutionFailedException.incompatibleFormal(LOG, arg, groundE, groundF);
1✔
973
        } else if (isConvertible.withUncheckedWarning()) {
1✔
974
            if (site != null) {
1!
975
                site.setNeedsUncheckedConversion();
1✔
976
            } else {
NEW
977
                infCtx.setNeedsUncheckedConversion();
×
978
            }
979
        }
980
    }
1✔
981

982
    /**
983
     * Convertibility in *invocation* context.
984
     *
985
     * https://docs.oracle.com/javase/specs/jls/se8/html/jls-5.html#jls-5.3
986
     */
987
    static Convertibility isConvertible(JTypeMirror exprType, JTypeMirror formalType, boolean canBox) {
988
        if (exprType == formalType) { // NOPMD CompareObjectsWithEquals
1✔
989
            // fast path
990
            return Convertibility.SUBTYPING;
1✔
991
        }
992

993
        if (canBox && exprType.isPrimitive() ^ formalType.isPrimitive()) {
1✔
994
            // then boxing conversions may be useful
995
            Convertibility result = TypeOps.isConvertible(exprType.box(), formalType.box());
1✔
996
            if (!result.never()) {
1✔
997
                return result;
1✔
998
            } else {
999
                return TypeOps.isConvertible(exprType.unbox(), formalType.unbox());
1✔
1000
            }
1001
        }
1002

1003
        return TypeOps.isConvertible(exprType, formalType);
1✔
1004
    }
1005

1006
    /**
1007
     * Returns true if the method is potentially applicable to the invocation
1008
     * expression expr, as specified in JLS§15.12.2.1.
1009
     *
1010
     * https://docs.oracle.com/javase/specs/jls/se9/html/jls-15.html#jls-15.12.2.1
1011
     *
1012
     * <p>This assumes the name of the method matches the expression, and
1013
     * the method is accessible.
1014
     *
1015
     * @param m    Method to test
1016
     * @param expr Invocation expression
1017
     */
1018
    private boolean isPotentiallyApplicable(JMethodSig m, InvocationMirror expr) {
1019

1020
        if (m.isGeneric()
1✔
1021
            && !expr.getExplicitTypeArguments().isEmpty()
1✔
1022
            && expr.getExplicitTypeArguments().size() != m.getTypeParameters().size()) {
1!
1023
            return false;
×
1024
        }
1025

1026
        List<ExprMirror> args = expr.getArgumentExpressions();
1✔
1027

1028
        if (!m.isVarargs()) {
1✔
1029
            // we can avoid computing formal parameters by using getArity here
1030
            if (args.size() != m.getArity()) {
1✔
1031
                return false;
1✔
1032
            }
1033

1034
            List<JTypeMirror> fs = m.getFormalParameters();
1✔
1035
            for (int i = 0; i < args.size(); i++) {
1✔
1036
                if (!exprOps.isPotentiallyCompatible(m, args.get(i), fs.get(i))) {
1✔
1037
                    return false;
1✔
1038
                }
1039
            }
1040

1041
        } else {
1✔
1042
            List<JTypeMirror> fs = m.getFormalParameters();
1✔
1043

1044
            // test first n-1 params
1045
            int varargIdx = fs.size() - 1;
1✔
1046
            for (int i = 0; i < varargIdx; i++) {
1✔
1047
                if (i >= args.size()) {
1✔
1048
                    // not enough arguments
1049
                    return false;
1✔
1050
                }
1051

1052
                if (!exprOps.isPotentiallyCompatible(m, args.get(i), fs.get(i))) {
1✔
1053
                    return false;
1✔
1054
                }
1055
            }
1056

1057
            if (args.size() == varargIdx - 1) {
1!
1058
                return true;
×
1059
            }
1060

1061
            if (args.size() == fs.size()) {
1✔
1062
                ExprMirror last = args.get(varargIdx);
1✔
1063
                JArrayType t = (JArrayType) fs.get(varargIdx);
1✔
1064

1065
                return exprOps.isPotentiallyCompatible(m, last, t)
1✔
1066
                    || exprOps.isPotentiallyCompatible(m, last, t.getComponentType());
1✔
1067
            }
1068

1069
            if (args.size() > fs.size()) {
1✔
1070
                JTypeMirror t = ((JArrayType) fs.get(varargIdx)).getComponentType();
1✔
1071
                for (int i = varargIdx; i < args.size(); i++) {
1✔
1072
                    if (!exprOps.isPotentiallyCompatible(m, args.get(i), t)) {
1!
1073
                        return false;
×
1074
                    }
1075
                }
1076
            }
1077
        }
1078

1079
        return true;
1✔
1080
    }
1081

1082

1083
}
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