diff options
| author | Stephan Herrmann | 2014-02-25 12:25:54 +0000 |
|---|---|---|
| committer | Stephan Herrmann | 2014-02-25 13:15:26 +0000 |
| commit | 745840be480d4e43f22d0c4f40c198cdee6926a4 (patch) | |
| tree | 1fc539b8d95c72b6b0a8902ee0cc254efc741547 | |
| parent | f700051affab74804180d3a8bb296f6cabd751a0 (diff) | |
| download | eclipse.jdt.core-745840be480d4e43f22d0c4f40c198cdee6926a4.tar.gz eclipse.jdt.core-745840be480d4e43f22d0c4f40c198cdee6926a4.tar.xz eclipse.jdt.core-745840be480d4e43f22d0c4f40c198cdee6926a4.zip | |
Bug 428985 - [1.8][null] help the type inference to find a
nullness-annotated type if possible
- test & fix
3 files changed, 59 insertions, 1 deletions
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullTypeAnnotationTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullTypeAnnotationTest.java index 10125bd158..8132e223dd 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullTypeAnnotationTest.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullTypeAnnotationTest.java @@ -2531,6 +2531,35 @@ public class NullTypeAnnotationTest extends AbstractNullAnnotationTest { "----------\n"); } + // the only null annotation is on the target type, which propagates into the implicitly typed lambda argument + public void testNullTypeInference2d() { + runNegativeTestWithLibs( + new String[] { + "PolyNull.java", + "import org.eclipse.jdt.annotation.*;\n" + + "\n" + + "interface Func<T> {\n" + + " T a(T i);\n" + + "}\n" + + "public class PolyNull {\n" + + " <X> X extract(Func<X> f, X s) { return f.a(s); }\n" + + " @NonNull String testOK() {\n" + + " return extract(i -> i, \"hallo\");\n" + + " }\n" + + " @NonNull String testERR() {\n" + + " return extract(i -> null, \"hallo\"); // err\n" + + " }\n" + + "}\n" + }, + getCompilerOptions(), + "----------\n" + + "1. ERROR in PolyNull.java (at line 12)\n" + + " return extract(i -> null, \"hallo\"); // err\n" + + " ^^^^\n" + + "Null type mismatch: required \'@NonNull String\' but the provided value is null\n" + + "----------\n"); + } + // missing return type should not cause NPE public void testBug415850_01() { runNegativeTestWithLibs( diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BoundSet.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BoundSet.java index 228cb5b0df..242027709a 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BoundSet.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BoundSet.java @@ -72,17 +72,21 @@ class BoundSet { public TypeBinding[] lowerBounds(boolean onlyProper, LookupEnvironment environment) { TypeBinding[] boundTypes = new TypeBinding[this.superBounds.size()]; Iterator<TypeBound> it = this.superBounds.iterator(); + long nullHints = 0; int i = 0; while(it.hasNext()) { TypeBound current = it.next(); TypeBinding boundType = current.right; - if (!onlyProper || boundType.isProperType(true)) + if (!onlyProper || boundType.isProperType(true)) { boundTypes[i++] = boundType; + nullHints |= current.nullHints; + } } if (i == 0) return Binding.NO_TYPES; if (i < boundTypes.length) System.arraycopy(boundTypes, 0, boundTypes=new TypeBinding[i], 0, i); + useNullHints(nullHints, boundTypes, environment); InferenceContext18.sortTypes(boundTypes); return boundTypes; } @@ -91,12 +95,14 @@ class BoundSet { ReferenceBinding[] rights = new ReferenceBinding[this.subBounds.size()]; TypeBinding simpleUpper = null; Iterator<TypeBound> it = this.subBounds.iterator(); + long nullHints = 0; int i = 0; while(it.hasNext()) { TypeBinding right=it.next().right; if (!onlyProper || right.isProperType(true)) { if (right instanceof ReferenceBinding) { rights[i++] = (ReferenceBinding) right; + nullHints |= right.tagBits & TagBits.AnnotationNullMASK; } else { if (simpleUpper != null) return Binding.NO_TYPES; // shouldn't @@ -110,6 +116,7 @@ class BoundSet { return new TypeBinding[] { simpleUpper }; // no nullHints since not a reference type if (i < rights.length) System.arraycopy(rights, 0, rights=new ReferenceBinding[i], 0, i); + useNullHints(nullHints, rights, environment); InferenceContext18.sortTypes(rights); return rights; } @@ -223,6 +230,20 @@ class BoundSet { } return wrapperBound; } + /** + * Not per JLS: enhance the given type bounds using the nullHints, if useful. + * Will only ever be effective if any TypeBounds carry nullHints, + * which only happens if any TypeBindings have non-zero (tagBits & AnnotationNullMASK), + * which only happens if null annotations are enabled in the first place. + */ + private void useNullHints(long nullHints, TypeBinding[] boundTypes, LookupEnvironment environment) { + AnnotationBinding[] annot = environment.nullAnnotationsFromTagBits(nullHints); + if (annot != null) { + // only get here if exactly one of @NonNull or @Nullable was hinted; now apply this hint: + for (int i = 0; i < boundTypes.length; i++) + boundTypes[i] = environment.createAnnotatedType(boundTypes[i], annot); + } + } } // main storage of type bounds: HashMap<InferenceVariable, ThreeSets> boundsPerVariable = new HashMap<InferenceVariable, ThreeSets>(); @@ -410,6 +431,11 @@ class BoundSet { return false; // TODO here and below: better checking if constraint really added to the boundset (optimization)? hasUpdate = true; + // not per JLS: if the new constraint relates types where at least one has a null annotations, + // record all null tagBits as hints for the final inference solution. + long nullHints = (newConstraint.left.tagBits | newConstraint.right.tagBits) & TagBits.AnnotationNullMASK; + boundI.nullHints |= nullHints; + boundJ.nullHints |= nullHints; } ConstraintFormula[] typeArgumentConstraints = deriveTypeArgumentConstraints(boundI, boundJ); if (typeArgumentConstraints != null) { diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeBound.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeBound.java index b8671b41a9..61335439c6 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeBound.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeBound.java @@ -26,6 +26,9 @@ public class TypeBound extends ReductionResult { // this flag contributes to the workaround controlled by InferenceContext18.ARGUMENT_CONSTRAINTS_ARE_SOFT: boolean isSoft; + + // here we accumulate null tagBits from any types that have been related to this type bound during incorporation: + long nullHints; static TypeBound createBoundOrDependency(InferenceContext18 context, TypeBinding type, InferenceVariable variable) { // Part of JLS8 sect 18.1.3: |
