001/* -*- mode: Java; c-basic-offset: 2; indent-tabs-mode: nil; coding: utf-8-unix -*- 002 * 003 * Copyright © 2025 microBean™. 004 * 005 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 006 * the License. You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 011 * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 012 * specific language governing permissions and limitations under the License. 013 */ 014package org.microbean.assign; 015 016import java.util.Comparator; 017 018import javax.lang.model.type.TypeMirror; 019 020import org.microbean.construct.Domain; 021 022import static java.util.Objects.requireNonNull; 023 024/** 025 * A {@link Comparator} of {@link TypeMirror}s that establishes a <dfn>partial order</dfn> on its arguments, enforcing 026 * only that more specialized types precede less specialized ones. 027 * 028 * <strong>Instances of this class are (deliberately) not consistent with equals.</strong> 029 * 030 * @author <a href="https://about.me/lairdnelson" target="_top">Laird Nelson</a> 031 * 032 * @see #compare(TypeMirror, TypeMirror) 033 */ 034public final class SpecializationComparator implements Comparator<TypeMirror> { 035 036 private final Domain domain; 037 038 /** 039 * Creates a new {@link SpecializationComparator}. 040 * 041 * @param domain a {@link Domain}; must not be {@code null} 042 * 043 * @exception NullPointerException if {@code domain} is {@code null} 044 */ 045 public SpecializationComparator(final Domain domain) { 046 super(); 047 this.domain = requireNonNull(domain, "domain"); 048 } 049 050 /** 051 * Compares two {@link TypeMirror}s and returns the result. 052 * 053 * <p>The following rules are evaluated in order to calculate the returned result:</p> 054 * 055 * <p>If {@code t} {@code ==} {@code s}, or {@linkplain Domain#sameType(TypeMirror, TypeMirror) <code>t</code> and 056 * <code>s</code> are the same time}, returns {@code 0}.</p> 057 * 058 * <p>If {@code t} is {@code null} and {@code s} is not, returns a positive value.</p> 059 * 060 * <p>If {@code s} is {@code null} and {@code t} is not, returns a negative value.</p> 061 * 062 * <p>If {@code t} {@linkplain Domain#subtype(TypeMirror, TypeMirror) is a subtype of} {@code s}, returns a negative 063 * value.</p> 064 * 065 * <p>If {@code s} {@linkplain Domain#subtype(TypeMirror, TypeMirror) is a subtype of} {@code t}, returns a positive 066 * value.</p> 067 * 068 * <p>In all other cases {@code 0} is returned.</p>. 069 * 070 * @param t a {@link TypeMirror}; may be {@code null} 071 * 072 * @param s a {@link TypeMirror}; may be {@code null} 073 * 074 * @return a comparison result 075 * 076 * @see Domain#sameType(TypeMirror, TypeMirror) 077 * 078 * @see Domain#subtype(TypeMirror, TypeMirror) 079 */ 080 @Override // Comparator<TypeMirror, TypeMirror> 081 public final int compare(final TypeMirror t, final TypeMirror s) { 082 if (t == s) { 083 return 0; 084 } else if (t == null) { 085 return 1; // nulls right 086 } else if (s == null) { 087 return -1; // nulls right 088 } else if (domain.sameType(t, s)) { 089 return 0; 090 } else if (domain.subtype(t, s)) { 091 // t is a subtype of s; s is a proper supertype of t 092 return -1; 093 } else if (domain.subtype(s, t)) { 094 // s is a subtype of t; t is a proper supertype of s 095 return 1; 096 } else { 097 return 0; 098 } 099 } 100 101}