Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

On upgrade to 3.47.0 supplier seems to get inferred as nullable #6789

Open
agentgt opened this issue Sep 5, 2024 · 3 comments
Open

On upgrade to 3.47.0 supplier seems to get inferred as nullable #6789

agentgt opened this issue Sep 5, 2024 · 3 comments
Assignees

Comments

@agentgt
Copy link

agentgt commented Sep 5, 2024

The following code the supplier is inferred as @Nullable when it should be @NonNull.

	@SuppressWarnings("unchecked")
	@Override
	public <T> T putIfAbsent(Class<T> type, String name, Supplier<T> supplier) {
		var t = (T) services.computeIfAbsent(new ServiceKey(type, name), k -> Objects.requireNonNull(supplier.get()));
		return t;
	}

https://github.com/jstachio/rainbowgum/blob/c8bfceaef5e07c75c76b1d59f59ef5ba4288b8b6/core/src/main/java/io/jstach/rainbowgum/ServiceRegistry.java#L168

I will try to add an isolated reproducible example so that you don't need my entire project.

Reproducible is here:

https://github.com/agentgt/checker-issues/tree/main/checker-issue-6789

[ERROR] /Users/agent/projects/checker-issues/checker-issue-6789/src/main/java/io/jstach/checker/issue6689/ServiceRegistry.java:[165,107] error: [argument] incompatible argument for parameter obj of Objects.requireNonNull.
[ERROR]   found   : T extends @Initialized @Nullable Object
[ERROR]   required: T extends @Initialized @NonNull Object
@kelloggm
Copy link
Contributor

kelloggm commented Sep 5, 2024

Here's a relatively small test case that reproduces the problem (automatically produced by Specimin):

package io.jstach.rainbowgum;

import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.BiConsumer;
import java.util.function.Supplier;

public sealed interface ServiceRegistry extends AutoCloseable permits DefaultServiceRegistry {

    public default <T> T putIfAbsent(Class<T> type, String name, Supplier<T> supplier) {
        throw new Error();
    }

    public default void close() {
        throw new Error();
    }
}

record ServiceKey(Class<?> type, String name) {

    ServiceKey {
        Objects.requireNonNull(type);
        Objects.requireNonNull(name);
    }
}

final class DefaultServiceRegistry implements ServiceRegistry {

    private final Map<ServiceKey, Object> services = null;

    public <T> void put(Class<T> type, String name, T service) {
        throw new Error();
    }

    @SuppressWarnings("unchecked")
    public <T> T findOrNull(Class<T> type, String name) {
        throw new Error();
    }

    @SuppressWarnings("unchecked")
    public <T> List<T> find(Class<T> type) {
        throw new Error();
    }

    @SuppressWarnings("unchecked")
    public <T> void forEach(Class<T> type, BiConsumer<String, T> consumer) {
        throw new Error();
    }

    @SuppressWarnings("unchecked")
    public <T> T putIfAbsent(Class<T> type, String name, Supplier<T> supplier) {
        var t = (T) services.computeIfAbsent(new ServiceKey(type, name), k -> Objects.requireNonNull(supplier.get()));
        return t;
    }

    public void onClose(AutoCloseable closeable) {
        throw new Error();
    }

    public void close() {
        throw new Error();
    }
}

Running the Nullness Checker from CF 3.47.0 on that code produces:

(base) ➜  rainbowgum-out $CHECKERFRAMEWORK/checker/bin/javac -processor nullness **/*.java
io/jstach/rainbowgum/ServiceRegistry.java:30: error: [assignment] incompatible types in assignment.
    private final Map<ServiceKey, Object> services = null;
                                                     ^
  found   : null (NullType)
  required: @Initialized @NonNull Map<@Initialized @NonNull ServiceKey, @Initialized @NonNull Object>
io/jstach/rainbowgum/ServiceRegistry.java:53: error: [argument] incompatible argument for parameter obj of Objects.requireNonNull.
        var t = (T) services.computeIfAbsent(new ServiceKey(type, name), k -> Objects.requireNonNull(supplier.get()));
                                                                                                                 ^
  found   : T extends @Initialized @Nullable Object
  required: T extends @Initialized @NonNull Object
2 errors

@kelloggm
Copy link
Contributor

kelloggm commented Sep 5, 2024

Oh, I didn't see that the reporter had added a reproducer. @agentgt beat me to it by a few minutes :)

@agentgt
Copy link
Author

agentgt commented Sep 5, 2024

@kelloggm That specimin tool looks cool! Starred it for future exploring. Thanks for the link to it!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants