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; 017import java.util.Objects; 018 019import javax.lang.model.type.TypeMirror; 020 021import org.microbean.construct.Domain; 022 023/** 024 * A {@link Comparator} of {@link TypeMirror}s that establishes a <dfn>partial order</dfn> on its arguments, enforcing 025 * only that more specialized types precede less specialized ones. 026 * 027 * <strong>Instances of this class are (deliberately) not consistent with equals.</strong> 028 * 029 * @author <a href="https://about.me/lairdnelson" target="_top">Laird Nelson</a> 030 * 031 * @see #compare(TypeMirror, TypeMirror) 032 */ 033public final class SpecializationComparator implements Comparator<TypeMirror> { 034 035 private final Domain domain; 036 037 /** 038 * Creates a new {@link SpecializationComparator}. 039 * 040 * @param domain a {@link Domain}; must not be {@code null} 041 * 042 * @exception NullPointerException if {@code domain} is {@code null} 043 */ 044 public SpecializationComparator(final Domain domain) { 045 super(); 046 this.domain = Objects.requireNonNull(domain, "domain"); 047 } 048 049 /** 050 * Compares two {@link TypeMirror}s and returns the result. 051 * 052 * <p>The following rules are evaluated in order to calculate the returned result:</p> 053 * 054 * <p>If {@code t} {@code ==} {@code s}, or {@linkplain Domain#sameType(TypeMirror, TypeMirror) <code>t</code> and 055 * <code>s</code> are the same time}, returns {@code 0}.</p> 056 * 057 * <p>If {@code t} is {@code null} and {@code s} is not, returns a positive value.</p> 058 * 059 * <p>If {@code s} is {@code null} and {@code t} is not, returns a negative value.</p> 060 * 061 * <p>If {@code t} {@linkplain Domain#subtype(TypeMirror, TypeMirror) is a subtype of} {@code s}, returns a negative 062 * value.</p> 063 * 064 * <p>If {@code s} {@linkplain Domain#subtype(TypeMirror, TypeMirror) is a subtype of} {@code t}, returns a positive 065 * value.</p> 066 * 067 * <p>In all other cases {@code 0} is returned.</p>. 068 * 069 * @param t a {@link TypeMirror}; may be {@code null} 070 * 071 * @param s a {@link TypeMirror}; may be {@code null} 072 * 073 * @return a comparison result 074 * 075 * @see Domain#sameType(TypeMirror, TypeMirror) 076 * 077 * @see Domain#subtype(TypeMirror, TypeMirror) 078 */ 079 @Override // Comparator<TypeMirror, TypeMirror> 080 public final int compare(final TypeMirror t, final TypeMirror s) { 081 if (t == s) { 082 return 0; 083 } else if (t == null) { 084 return 1; // nulls right 085 } else if (s == null) { 086 return -1; // nulls right 087 } else if (domain.sameType(t, s)) { 088 return 0; 089 } else if (domain.subtype(t, s)) { 090 // t is a subtype of s; s is a proper supertype of t 091 return -1; 092 } else if (domain.subtype(s, t)) { 093 // s is a subtype of t; t is a proper supertype of s 094 return 1; 095 } else { 096 return 0; 097 } 098 } 099 100}