mirror of
https://github.com/openjdk/jdk.git
synced 2026-02-22 16:26:05 +00:00
7144506: Attr.checkMethod should be called after inference variables have been fixed
Unify post-inference sanity check with Attr.checkMethod Reviewed-by: jjg, dlsmith
This commit is contained in:
parent
21312c5617
commit
d5036d16cd
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -1518,8 +1518,6 @@ public class Attr extends JCTree.Visitor {
|
||||
Type mpt = newMethTemplate(argtypes, typeargtypes);
|
||||
localEnv.info.varArgs = false;
|
||||
Type mtype = attribExpr(tree.meth, localEnv, mpt);
|
||||
if (localEnv.info.varArgs)
|
||||
Assert.check(mtype.isErroneous() || tree.varargsElement != null);
|
||||
|
||||
// Compute the result type.
|
||||
Type restype = mtype.getReturnType();
|
||||
@ -1553,6 +1551,9 @@ public class Attr extends JCTree.Visitor {
|
||||
// Check that value of resulting type is admissible in the
|
||||
// current context. Also, capture the return type
|
||||
result = check(tree, capture(restype), VAL, pkind, pt);
|
||||
|
||||
if (localEnv.info.varArgs)
|
||||
Assert.check(result.isErroneous() || tree.varargsElement != null);
|
||||
}
|
||||
chk.validate(tree.typeargs, localEnv);
|
||||
}
|
||||
@ -1730,7 +1731,7 @@ public class Attr extends JCTree.Visitor {
|
||||
tree.pos(), rsEnv, clazztype, argtypes, typeargtypes);
|
||||
tree.constructorType = tree.constructor.type.isErroneous() ?
|
||||
syms.errType :
|
||||
checkMethod(clazztype,
|
||||
checkConstructor(clazztype,
|
||||
tree.constructor,
|
||||
rsEnv,
|
||||
tree.args,
|
||||
@ -1805,7 +1806,7 @@ public class Attr extends JCTree.Visitor {
|
||||
tree.constructorType = syms.errType;
|
||||
}
|
||||
else {
|
||||
tree.constructorType = checkMethod(clazztype,
|
||||
tree.constructorType = checkConstructor(clazztype,
|
||||
tree.constructor,
|
||||
localEnv,
|
||||
tree.args,
|
||||
@ -2675,7 +2676,7 @@ public class Attr extends JCTree.Visitor {
|
||||
Warner noteWarner = new Warner();
|
||||
|
||||
/**
|
||||
* Check that method arguments conform to its instantation.
|
||||
* Check that method arguments conform to its instantiation.
|
||||
**/
|
||||
public Type checkMethod(Type site,
|
||||
Symbol sym,
|
||||
@ -2712,107 +2713,37 @@ public class Attr extends JCTree.Visitor {
|
||||
true,
|
||||
useVarargs,
|
||||
noteWarner);
|
||||
boolean warned = noteWarner.hasNonSilentLint(LintCategory.UNCHECKED);
|
||||
|
||||
// If this fails, something went wrong; we should not have
|
||||
// found the identifier in the first place.
|
||||
if (owntype == null) {
|
||||
if (!pt.isErroneous())
|
||||
log.error(env.tree.pos(),
|
||||
"internal.error.cant.instantiate",
|
||||
sym, site,
|
||||
"internal.error.cant.instantiate",
|
||||
sym, site,
|
||||
Type.toString(pt.getParameterTypes()));
|
||||
owntype = types.createErrorType(site);
|
||||
return types.createErrorType(site);
|
||||
} else if (owntype.getReturnType().tag == FORALL) {
|
||||
return owntype;
|
||||
} else {
|
||||
// System.out.println("call : " + env.tree);
|
||||
// System.out.println("method : " + owntype);
|
||||
// System.out.println("actuals: " + argtypes);
|
||||
List<Type> formals = owntype.getParameterTypes();
|
||||
Type last = useVarargs ? formals.last() : null;
|
||||
if (sym.name==names.init &&
|
||||
sym.owner == syms.enumSym)
|
||||
formals = formals.tail.tail;
|
||||
List<JCExpression> args = argtrees;
|
||||
while (formals.head != last) {
|
||||
JCTree arg = args.head;
|
||||
Warner warn = chk.convertWarner(arg.pos(), arg.type, formals.head);
|
||||
assertConvertible(arg, arg.type, formals.head, warn);
|
||||
warned |= warn.hasNonSilentLint(LintCategory.UNCHECKED);
|
||||
args = args.tail;
|
||||
formals = formals.tail;
|
||||
}
|
||||
if (useVarargs) {
|
||||
Type varArg = types.elemtype(last);
|
||||
while (args.tail != null) {
|
||||
JCTree arg = args.head;
|
||||
Warner warn = chk.convertWarner(arg.pos(), arg.type, varArg);
|
||||
assertConvertible(arg, arg.type, varArg, warn);
|
||||
warned |= warn.hasNonSilentLint(LintCategory.UNCHECKED);
|
||||
args = args.tail;
|
||||
}
|
||||
} else if ((sym.flags() & VARARGS) != 0 && allowVarargs) {
|
||||
// non-varargs call to varargs method
|
||||
Type varParam = owntype.getParameterTypes().last();
|
||||
Type lastArg = argtypes.last();
|
||||
if (types.isSubtypeUnchecked(lastArg, types.elemtype(varParam)) &&
|
||||
!types.isSameType(types.erasure(varParam), types.erasure(lastArg)))
|
||||
log.warning(argtrees.last().pos(), "inexact.non-varargs.call",
|
||||
types.elemtype(varParam),
|
||||
varParam);
|
||||
}
|
||||
|
||||
if (warned && sym.type.tag == FORALL) {
|
||||
chk.warnUnchecked(env.tree.pos(),
|
||||
"unchecked.meth.invocation.applied",
|
||||
kindName(sym),
|
||||
sym.name,
|
||||
rs.methodArguments(sym.type.getParameterTypes()),
|
||||
rs.methodArguments(argtypes),
|
||||
kindName(sym.location()),
|
||||
sym.location());
|
||||
owntype = new MethodType(owntype.getParameterTypes(),
|
||||
types.erasure(owntype.getReturnType()),
|
||||
types.erasure(owntype.getThrownTypes()),
|
||||
syms.methodClass);
|
||||
}
|
||||
if (useVarargs) {
|
||||
JCTree tree = env.tree;
|
||||
Type argtype = owntype.getParameterTypes().last();
|
||||
if (owntype.getReturnType().tag != FORALL || warned) {
|
||||
chk.checkVararg(env.tree.pos(), owntype.getParameterTypes(), sym);
|
||||
}
|
||||
Type elemtype = types.elemtype(argtype);
|
||||
switch (tree.getTag()) {
|
||||
case APPLY:
|
||||
((JCMethodInvocation) tree).varargsElement = elemtype;
|
||||
break;
|
||||
case NEWCLASS:
|
||||
((JCNewClass) tree).varargsElement = elemtype;
|
||||
break;
|
||||
default:
|
||||
throw new AssertionError(""+tree);
|
||||
}
|
||||
}
|
||||
return chk.checkMethod(owntype, sym, env, argtrees, argtypes, useVarargs);
|
||||
}
|
||||
return owntype;
|
||||
}
|
||||
|
||||
private void assertConvertible(JCTree tree, Type actual, Type formal, Warner warn) {
|
||||
if (types.isConvertible(actual, formal, warn))
|
||||
return;
|
||||
|
||||
if (formal.isCompound()
|
||||
&& types.isSubtype(actual, types.supertype(formal))
|
||||
&& types.isSubtypeUnchecked(actual, types.interfaces(formal), warn))
|
||||
return;
|
||||
|
||||
if (false) {
|
||||
// TODO: make assertConvertible work
|
||||
chk.typeError(tree.pos(), diags.fragment("incompatible.types"), actual, formal);
|
||||
throw new AssertionError("Tree: " + tree
|
||||
+ " actual:" + actual
|
||||
+ " formal: " + formal);
|
||||
}
|
||||
/**
|
||||
* Check that constructor arguments conform to its instantiation.
|
||||
**/
|
||||
public Type checkConstructor(Type site,
|
||||
Symbol sym,
|
||||
Env<AttrContext> env,
|
||||
final List<JCExpression> argtrees,
|
||||
List<Type> argtypes,
|
||||
List<Type> typeargtypes,
|
||||
boolean useVarargs) {
|
||||
Type owntype = checkMethod(site, sym, env, argtrees, argtypes, typeargtypes, useVarargs);
|
||||
chk.checkType(env.tree.pos(), owntype.getReturnType(), syms.voidType);
|
||||
return owntype;
|
||||
}
|
||||
|
||||
public void visitLiteral(JCLiteral tree) {
|
||||
|
||||
@ -63,6 +63,7 @@ public class Check {
|
||||
|
||||
private final Names names;
|
||||
private final Log log;
|
||||
private final Resolve rs;
|
||||
private final Symtab syms;
|
||||
private final Enter enter;
|
||||
private final Infer infer;
|
||||
@ -95,6 +96,7 @@ public class Check {
|
||||
|
||||
names = Names.instance(context);
|
||||
log = Log.instance(context);
|
||||
rs = Resolve.instance(context);
|
||||
syms = Symtab.instance(context);
|
||||
enter = Enter.instance(context);
|
||||
infer = Infer.instance(context);
|
||||
@ -106,6 +108,7 @@ public class Check {
|
||||
|
||||
Source source = Source.instance(context);
|
||||
allowGenerics = source.allowGenerics();
|
||||
allowVarargs = source.allowVarargs();
|
||||
allowAnnotations = source.allowAnnotations();
|
||||
allowCovariantReturns = source.allowCovariantReturns();
|
||||
allowSimplifiedVarargs = source.allowSimplifiedVarargs();
|
||||
@ -137,6 +140,10 @@ public class Check {
|
||||
*/
|
||||
boolean allowGenerics;
|
||||
|
||||
/** Switch: varargs enabled?
|
||||
*/
|
||||
boolean allowVarargs;
|
||||
|
||||
/** Switch: annotations enabled?
|
||||
*/
|
||||
boolean allowAnnotations;
|
||||
@ -743,22 +750,105 @@ public class Check {
|
||||
(s.flags() & (STATIC | FINAL)) != 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that vararg method call is sound
|
||||
* @param pos Position to be used for error reporting.
|
||||
* @param argtypes Actual arguments supplied to vararg method.
|
||||
*/
|
||||
void checkVararg(DiagnosticPosition pos, List<Type> argtypes, Symbol msym) {
|
||||
Type argtype = argtypes.last();
|
||||
if (!types.isReifiable(argtype) &&
|
||||
(!allowSimplifiedVarargs ||
|
||||
msym.attribute(syms.trustMeType.tsym) == null ||
|
||||
!isTrustMeAllowedOnMethod(msym))) {
|
||||
warnUnchecked(pos,
|
||||
"unchecked.generic.array.creation",
|
||||
argtype);
|
||||
Type checkMethod(Type owntype,
|
||||
Symbol sym,
|
||||
Env<AttrContext> env,
|
||||
final List<JCExpression> argtrees,
|
||||
List<Type> argtypes,
|
||||
boolean useVarargs) {
|
||||
boolean warned = false;
|
||||
// System.out.println("call : " + env.tree);
|
||||
// System.out.println("method : " + owntype);
|
||||
// System.out.println("actuals: " + argtypes);
|
||||
List<Type> formals = owntype.getParameterTypes();
|
||||
Type last = useVarargs ? formals.last() : null;
|
||||
if (sym.name==names.init &&
|
||||
sym.owner == syms.enumSym)
|
||||
formals = formals.tail.tail;
|
||||
List<JCExpression> args = argtrees;
|
||||
while (formals.head != last) {
|
||||
JCTree arg = args.head;
|
||||
Warner warn = convertWarner(arg.pos(), arg.type, formals.head);
|
||||
assertConvertible(arg, arg.type, formals.head, warn);
|
||||
warned |= warn.hasNonSilentLint(LintCategory.UNCHECKED);
|
||||
args = args.tail;
|
||||
formals = formals.tail;
|
||||
}
|
||||
if (useVarargs) {
|
||||
Type varArg = types.elemtype(last);
|
||||
while (args.tail != null) {
|
||||
JCTree arg = args.head;
|
||||
Warner warn = convertWarner(arg.pos(), arg.type, varArg);
|
||||
assertConvertible(arg, arg.type, varArg, warn);
|
||||
warned |= warn.hasNonSilentLint(LintCategory.UNCHECKED);
|
||||
args = args.tail;
|
||||
}
|
||||
} else if ((sym.flags() & VARARGS) != 0 && allowVarargs) {
|
||||
// non-varargs call to varargs method
|
||||
Type varParam = owntype.getParameterTypes().last();
|
||||
Type lastArg = argtypes.last();
|
||||
if (types.isSubtypeUnchecked(lastArg, types.elemtype(varParam)) &&
|
||||
!types.isSameType(types.erasure(varParam), types.erasure(lastArg)))
|
||||
log.warning(argtrees.last().pos(), "inexact.non-varargs.call",
|
||||
types.elemtype(varParam), varParam);
|
||||
}
|
||||
if (warned) {
|
||||
warnUnchecked(env.tree.pos(),
|
||||
"unchecked.meth.invocation.applied",
|
||||
kindName(sym),
|
||||
sym.name,
|
||||
rs.methodArguments(sym.type.getParameterTypes()),
|
||||
rs.methodArguments(argtypes),
|
||||
kindName(sym.location()),
|
||||
sym.location());
|
||||
owntype = new MethodType(owntype.getParameterTypes(),
|
||||
types.erasure(owntype.getReturnType()),
|
||||
types.erasure(owntype.getThrownTypes()),
|
||||
syms.methodClass);
|
||||
}
|
||||
if (useVarargs) {
|
||||
JCTree tree = env.tree;
|
||||
Type argtype = owntype.getParameterTypes().last();
|
||||
if (!types.isReifiable(argtype) &&
|
||||
(!allowSimplifiedVarargs ||
|
||||
sym.attribute(syms.trustMeType.tsym) == null ||
|
||||
!isTrustMeAllowedOnMethod(sym))) {
|
||||
warnUnchecked(env.tree.pos(),
|
||||
"unchecked.generic.array.creation",
|
||||
argtype);
|
||||
}
|
||||
Type elemtype = types.elemtype(argtype);
|
||||
switch (tree.getTag()) {
|
||||
case APPLY:
|
||||
((JCMethodInvocation) tree).varargsElement = elemtype;
|
||||
break;
|
||||
case NEWCLASS:
|
||||
((JCNewClass) tree).varargsElement = elemtype;
|
||||
break;
|
||||
default:
|
||||
throw new AssertionError(""+tree);
|
||||
}
|
||||
}
|
||||
return owntype;
|
||||
}
|
||||
//where
|
||||
private void assertConvertible(JCTree tree, Type actual, Type formal, Warner warn) {
|
||||
if (types.isConvertible(actual, formal, warn))
|
||||
return;
|
||||
|
||||
if (formal.isCompound()
|
||||
&& types.isSubtype(actual, types.supertype(formal))
|
||||
&& types.isSubtypeUnchecked(actual, types.interfaces(formal), warn))
|
||||
return;
|
||||
|
||||
if (false) {
|
||||
// TODO: make assertConvertible work
|
||||
typeError(tree.pos(), diags.fragment("incompatible.types"), actual, formal);
|
||||
throw new AssertionError("Tree: " + tree
|
||||
+ " actual:" + actual
|
||||
+ " formal: " + formal);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that type 't' is a valid instantiation of a generic class
|
||||
|
||||
@ -445,16 +445,19 @@ public class Infer {
|
||||
return List.nil();
|
||||
}
|
||||
@Override
|
||||
void check(List<Type> inferred, Types types) throws NoInstanceException {
|
||||
void instantiateReturnType(Type restype, List<Type> inferred, Types types) throws NoInstanceException {
|
||||
Type owntype = new MethodType(types.subst(getParameterTypes(), tvars, inferred),
|
||||
restype,
|
||||
types.subst(getThrownTypes(), tvars, inferred),
|
||||
qtype.tsym);
|
||||
// check that actuals conform to inferred formals
|
||||
checkArgumentsAcceptable(env, capturedArgs, getParameterTypes(), allowBoxing, useVarargs, warn);
|
||||
checkArgumentsAcceptable(env, capturedArgs, owntype.getParameterTypes(), allowBoxing, useVarargs, warn);
|
||||
// check that inferred bounds conform to their bounds
|
||||
checkWithinBounds(all_tvars,
|
||||
types.subst(inferredTypes, tvars, inferred), warn);
|
||||
if (useVarargs) {
|
||||
chk.checkVararg(env.tree.pos(), getParameterTypes(), msym);
|
||||
}
|
||||
}};
|
||||
qtype = chk.checkMethod(owntype, msym, env, TreeInfo.args(env.tree), capturedArgs, useVarargs);
|
||||
}
|
||||
};
|
||||
}
|
||||
else {
|
||||
// check that actuals conform to inferred formals
|
||||
@ -520,16 +523,7 @@ public class Infer {
|
||||
return qtype.map(f);
|
||||
}
|
||||
|
||||
void instantiateReturnType(Type restype, List<Type> inferred, Types types) throws NoInstanceException {
|
||||
//update method type with newly inferred type-arguments
|
||||
qtype = new MethodType(types.subst(getParameterTypes(), tvars, inferred),
|
||||
restype,
|
||||
types.subst(UninferredMethodType.this.getThrownTypes(), tvars, inferred),
|
||||
UninferredMethodType.this.qtype.tsym);
|
||||
check(inferred, types);
|
||||
}
|
||||
|
||||
abstract void check(List<Type> inferred, Types types) throws NoInstanceException;
|
||||
abstract void instantiateReturnType(Type restype, List<Type> inferred, Types types);
|
||||
|
||||
abstract List<Type> getConstraints(TypeVar tv, ConstraintKind ck);
|
||||
|
||||
@ -544,7 +538,7 @@ public class Infer {
|
||||
if (rs.verboseResolutionMode.contains(VerboseResolutionMode.DEFERRED_INST)) {
|
||||
log.note(pos, "deferred.method.inst", msym, UninferredMethodType.this.qtype, newRestype);
|
||||
}
|
||||
return newRestype;
|
||||
return UninferredMethodType.this.qtype.getReturnType();
|
||||
}
|
||||
@Override
|
||||
public List<Type> getConstraints(TypeVar tv, ConstraintKind ck) {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -102,6 +102,16 @@ public class TreeInfo {
|
||||
setOpname(MOD, "%", names);
|
||||
}
|
||||
|
||||
public static List<JCExpression> args(JCTree t) {
|
||||
switch (t.getTag()) {
|
||||
case APPLY:
|
||||
return ((JCMethodInvocation)t).args;
|
||||
case NEWCLASS:
|
||||
return ((JCNewClass)t).args;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/** Return name of operator with given tree tag.
|
||||
*/
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
T6758789b.java:16:11: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), T6758789a.Foo, T6758789a.Foo<X>
|
||||
T6758789b.java:16:11: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), T6758789a.Foo, T6758789a.Foo<java.lang.Object>
|
||||
T6758789b.java:16:10: compiler.warn.unchecked.meth.invocation.applied: kindname.method, m, T6758789a.Foo<X>, T6758789a.Foo, kindname.class, T6758789a
|
||||
- compiler.err.warnings.and.werror
|
||||
1 error
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
T6723444.java:42:9: compiler.err.unreported.exception.need.to.catch.or.throw: X2
|
||||
T6723444.java:43:9: compiler.err.unreported.exception.need.to.catch.or.throw: X2
|
||||
T6723444.java:42:9: compiler.err.unreported.exception.need.to.catch.or.throw: java.lang.Throwable
|
||||
T6723444.java:43:9: compiler.err.unreported.exception.need.to.catch.or.throw: java.lang.Throwable
|
||||
T6723444.java:45:32: compiler.err.unreported.exception.need.to.catch.or.throw: java.lang.Throwable
|
||||
T6723444.java:46:17: compiler.err.unreported.exception.need.to.catch.or.throw: java.lang.Throwable
|
||||
T6723444.java:48:9: compiler.err.unreported.exception.need.to.catch.or.throw: java.lang.Throwable
|
||||
|
||||
@ -1,14 +1,14 @@
|
||||
T7015430.java:41:15: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), java.lang.Iterable, java.lang.Iterable<E>
|
||||
T7015430.java:41:15: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), java.lang.Iterable, java.lang.Iterable<java.lang.Exception>
|
||||
T7015430.java:41:14: compiler.warn.unchecked.meth.invocation.applied: kindname.method, empty, java.lang.Iterable<E>, java.lang.Iterable, kindname.class, T7015430
|
||||
T7015430.java:50:42: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), java.lang.Iterable, java.lang.Iterable<java.lang.RuntimeException>
|
||||
T7015430.java:50:41: compiler.warn.unchecked.meth.invocation.applied: kindname.method, empty, java.lang.Iterable<E>, java.lang.Iterable, kindname.class, T7015430
|
||||
T7015430.java:68:22: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), java.lang.Iterable, java.lang.Iterable<E>
|
||||
T7015430.java:68:22: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), java.lang.Iterable, java.lang.Iterable<java.lang.Exception>
|
||||
T7015430.java:68:9: compiler.warn.unchecked.meth.invocation.applied: kindname.constructor, <init>, java.lang.Iterable<E>, java.lang.Iterable, kindname.class, T7015430
|
||||
T7015430.java:77:40: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), java.lang.Iterable, java.lang.Iterable<java.lang.RuntimeException>
|
||||
T7015430.java:77:9: compiler.warn.unchecked.meth.invocation.applied: kindname.constructor, <init>, java.lang.Iterable<E>, java.lang.Iterable, kindname.class, T7015430
|
||||
T7015430.java:104:41: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), java.lang.Iterable, java.lang.Iterable<java.lang.RuntimeException>
|
||||
T7015430.java:104:9: compiler.warn.unchecked.meth.invocation.applied: kindname.constructor, <init>, java.lang.Iterable<E>, java.lang.Iterable, kindname.class, T7015430
|
||||
T7015430.java:113:22: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), java.lang.Iterable, java.lang.Iterable<E>
|
||||
T7015430.java:113:22: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), java.lang.Iterable, java.lang.Iterable<java.lang.Exception>
|
||||
T7015430.java:113:9: compiler.warn.unchecked.meth.invocation.applied: kindname.constructor, <init>, java.lang.Iterable<E>, java.lang.Iterable, kindname.class, T7015430
|
||||
T7015430.java:41:14: compiler.err.unreported.exception.need.to.catch.or.throw: java.lang.Exception
|
||||
T7015430.java:68:9: compiler.err.unreported.exception.need.to.catch.or.throw: java.lang.Exception
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user