UnionType implements InferredType { @Override public Optional<Symbol> resolveMember(String memberName) { if (hasUnresolvedHierarchy()) { return Optional.empty(); } Set<Optional<Symbol>> resolved = types.stream() .map(t -> t.resolveMember(memberName)) .filter(Optional::isPresent) .collect(Collectors.toSet()); return resolved.size() == 1 ? resolved.iterator().next() : Optional.empty(); } private  UnionType(Set<InferredType> types); static InferredType or(InferredType type1, InferredType type2); @Override boolean isIdentityComparableWith(InferredType other); @Override boolean canHaveMember(String memberName); @Override boolean declaresMember(String memberName); @Override Optional<Symbol> resolveMember(String memberName); @Override Optional<Symbol> resolveDeclaredMember(String memberName); @Override boolean canOnlyBe(String typeName); @Override boolean canBeOrExtend(String typeName); @Override boolean isCompatibleWith(InferredType other); boolean mustBeOrExtend(String fullyQualifiedName); @Override boolean equals(Object o); @Override int hashCode(); @Override String toString();  }
@Test public void resolveMember() { ClassSymbolImpl x = new ClassSymbolImpl("x", "x"); SymbolImpl foo = new SymbolImpl("foo", null); x.addMembers(Arrays.asList(foo, new SymbolImpl("bar", null))); ClassSymbolImpl y = new ClassSymbolImpl("y", "y"); ClassSymbolImpl z = new ClassSymbolImpl("z", "z"); z.addMembers(Collections.singleton(new SymbolImpl("bar", null))); assertThat(or(runtimeType(x), runtimeType(y)).resolveMember("foo")).contains(foo); assertThat(or(runtimeType(x), runtimeType(z)).resolveMember("bar")).isEmpty(); assertThat(or(runtimeType(x), runtimeType(z)).resolveMember("xxx")).isEmpty(); ClassSymbolImpl classWithUnresolvedHierarchy = new ClassSymbolImpl("u", "u"); classWithUnresolvedHierarchy.addSuperClass(AmbiguousSymbolImpl.create(new HashSet<>(Arrays.asList(x, new ClassSymbolImpl("x", "x"))))); assertThat(or(runtimeType(x), runtimeType(classWithUnresolvedHierarchy)).resolveMember("foo")).isEmpty(); }