001 /* Copyright (c) 2014, Erik Hogeman <Erik.Hogemn@gmail.com> 002 * All rights reserved. 003 * 004 * Redistribution and use in source and binary forms, with or without 005 * modification, are permitted provided that the following conditions are met: 006 * 007 * * Redistributions of source code must retain the above copyright notice, 008 * this list of conditions and the following disclaimer. 009 * * Redistributions in binary form must reproduce the above copyright 010 * notice, this list of conditions and the following disclaimer in the 011 * documentation and/or other materials provided with the distribution. 012 * * Neither the name of the Lund University nor the names of its 013 * contributors may be used to endorse or promote products derived from 014 * this software without specific prior written permission. 015 * 016 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 017 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 018 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 019 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 020 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 021 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 022 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 023 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 024 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 025 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 026 * POSSIBILITY OF SUCH DAMAGE. 027 */ 028 aspect FunctionalInterface { 029 030 syn lazy boolean TypeDecl.isFunctionalInterface() = false; 031 eq InterfaceDecl.isFunctionalInterface() = isFunctional(); 032 033 syn lazy boolean InterfaceDecl.isFunctional(); 034 035 //8.4.2 036 syn boolean GenericMethodDecl.sameSignature(MethodDecl m) { 037 if (!m.isGeneric()) { 038 return false; 039 } 040 GenericMethodDecl gm = m.genericDecl(); 041 return !(!name().equals(gm.name()) || !sameTypeParameters(gm) || !sameFormalParameters(gm)); 042 } 043 044 refine MethodDecl 045 eq MethodDecl.fullSignature() { 046 StringBuilder sb = new StringBuilder(); 047 sb.append(name() + "("); 048 for (int i = 0; i < getNumParameter(); i++) { 049 if (i != 0) { 050 sb.append(", "); 051 } 052 if (getParameter(i).type() instanceof PrimitiveType) { 053 sb.append(getParameter(i).type().typeName()); 054 } else { 055 sb.append(getParameter(i).type().fullName()); 056 } 057 } 058 sb.append(")"); 059 return sb.toString(); 060 } 061 062 syn lazy boolean MethodDecl.subsignatureTo(MethodDecl m) { 063 if (fullSignature().equals(m.fullSignature())) { 064 return true; 065 } else if (fullSignature().equals(m.signature())) { 066 return true; 067 } else { 068 return false; 069 } 070 } 071 072 syn lazy boolean GenericMethodDecl.subsignatureTo(MethodDecl m) { 073 if (m.isGeneric()) { 074 GenericMethodDecl gm = m.genericDecl(); 075 if (this == gm) { 076 return true; 077 } 078 return sameSignature(gm); 079 } else { 080 // A generic method can never be subsignature to a non-generic method. 081 return false; 082 } 083 } 084 085 //8.4.5 086 syn lazy boolean MethodDecl.returnTypeSubstitutableFor(MethodDecl m) { 087 TypeDecl t1 = type(); 088 TypeDecl t2 = m.type(); 089 if (t1 instanceof VoidType && t2 instanceof VoidType) { 090 return true; 091 } else if (t1 instanceof PrimitiveType && t2 instanceof PrimitiveType) { 092 PrimitiveType p1 = (PrimitiveType)t1; 093 PrimitiveType p2 = (PrimitiveType)t2; 094 return p1 == p2; 095 } else if (t1.isReferenceType() && t2.isReferenceType()) { 096 if (t1.strictSubtype(t2)) { 097 return true; 098 } else { 099 return t1 == t2.erasure(); 100 } 101 } else { 102 return false; 103 } 104 } 105 106 107 //8.4.4 108 syn lazy boolean GenericMethodDecl.sameTypeParameters(GenericMethodDecl gm) { 109 if (getNumTypeParameter() != gm.getNumTypeParameter()) { 110 return false; 111 } 112 113 for (int i = 0; i < getNumTypeParameter(); i++) { 114 TypeVariable tv1 = getTypeParameter(i); 115 TypeVariable tv2 = gm.getTypeParameter(i); 116 if (tv1.getNumTypeBound() != tv2.getNumTypeBound()) { 117 return false; 118 } 119 120 /* The bounds have to be the same in the way that a bound 121 that exists in type variable tv1 must exist exactly the same 122 number of times in tv2, but the order doesn't matter */ 123 124 boolean[] checkedBound = new boolean[tv1.getNumTypeBound()]; 125 126 for (int j = 0; j < tv1.getNumTypeBound(); j++) { 127 boolean found = false; 128 for (int k = 0; k < tv2.getNumTypeBound(); k++) { 129 if (checkedBound[k]) { 130 continue; 131 } 132 Access a1 = tv1.getTypeBound(j); 133 Access a2 = tv2.getTypeBound(k); 134 135 if (a1.sameType(a2)) { 136 checkedBound[k] = true; 137 found = true; 138 break; 139 } 140 } 141 if (!found) { 142 return false; 143 } 144 } 145 } 146 return true; 147 } 148 149 //8.4.2 150 syn lazy boolean GenericMethodDecl.sameFormalParameters(GenericMethodDecl gm) { 151 if (getNumParameter() != gm.getNumParameter()) { 152 return false; 153 } 154 if (getNumParameter() == 0) { 155 return true; 156 } 157 158 for (int i = 0; i < getNumParameter(); i++) { 159 ParameterDeclaration p1 = getParameter(i); 160 ParameterDeclaration p2 = gm.getParameter(i); 161 Access a1 = p1.getTypeAccess(); 162 Access a2 = p2.getTypeAccess(); 163 if (!a1.sameType(a2)) { 164 return false; 165 } 166 } 167 return true; 168 } 169 170 /* 171 Checks that two type accesses are the same, while taking type variable substitution 172 into account. 173 */ 174 public boolean Access.sameType(Access a) { 175 if (this instanceof ArrayTypeAccess && a instanceof ArrayTypeAccess) { 176 ArrayTypeAccess at1 = (ArrayTypeAccess) this; 177 ArrayTypeAccess at2 = (ArrayTypeAccess) a; 178 return at1.sameType(at2); 179 } else if (this instanceof AbstractWildcard && a instanceof AbstractWildcard) { 180 AbstractWildcard w1 = (AbstractWildcard) this; 181 AbstractWildcard w2 = (AbstractWildcard) a; 182 return w1.sameType(w2); 183 } else if (this instanceof TypeAccess && a instanceof TypeAccess) { 184 TypeAccess t1 = (TypeAccess) this; 185 TypeAccess t2 = (TypeAccess) a; 186 return t1.sameType(t2); 187 } else if (this instanceof ParTypeAccess && a instanceof ParTypeAccess) { 188 ParTypeAccess pta1 = (ParTypeAccess) this; 189 ParTypeAccess pta2 = (ParTypeAccess) a; 190 return pta1.sameType(pta2); 191 } else { 192 return false; 193 } 194 } 195 196 public boolean TypeAccess.sameType(TypeAccess t) { 197 /* 198 First, two type variables that are to be compared are checked to see if they are 199 both declared by methods and that one of the methods is not inside the scope of the other 200 method. If this is the case it is enough to simply check that the positions are equal. 201 Otherwise the types has to equal. 202 */ 203 204 if (type() instanceof TypeVariable && t.type() instanceof TypeVariable) { 205 TypeVariable t1 = (TypeVariable) type(); 206 TypeVariable t2 = (TypeVariable) t.type(); 207 if (t1.typeVarInMethod() && t2.typeVarInMethod() 208 && t1.genericMethodLevel() == t2.genericMethodLevel()) { 209 return t1.typeVarPosition() == t2.typeVarPosition(); 210 } else { 211 return t1 == t2; 212 } 213 } else if (type() instanceof TypeVariable && !(t.type() instanceof TypeVariable) 214 || t.type() instanceof TypeVariable && !(type() instanceof TypeVariable) ) { 215 return false; 216 } else if (type() == t.type()) { 217 return true; 218 } else { 219 return false; 220 } 221 } 222 223 public boolean ParTypeAccess.sameType(ParTypeAccess p) { 224 TypeAccess ta1 = (TypeAccess) getTypeAccess(); 225 TypeAccess ta2 = (TypeAccess) p.getTypeAccess(); 226 if (!ta1.sameType(ta2)) { 227 return false; 228 } 229 230 if (getNumTypeArgument() != p.getNumTypeArgument()) { 231 return false; 232 } 233 234 for (int i = 0; i < getNumTypeArgument(); i++) { 235 Access a1 = getTypeArgument(i); 236 Access a2 = p.getTypeArgument(i); 237 if (!a1.sameType(a2)) { 238 return false; 239 } 240 } 241 242 return true; 243 } 244 245 public boolean AbstractWildcard.sameType(AbstractWildcard w) { 246 if (this instanceof Wildcard && w instanceof Wildcard) { 247 return true; 248 } else if (this instanceof WildcardExtends && w instanceof WildcardExtends) { 249 Access a1 = ((WildcardExtends) this).getAccess(); 250 Access a2 = ((WildcardExtends) w).getAccess(); 251 return a1.sameType(a2); 252 } else if (this instanceof WildcardSuper && w instanceof WildcardSuper) { 253 Access a1 = ((WildcardSuper) this).getAccess(); 254 Access a2 = ((WildcardSuper) w).getAccess(); 255 return a1.sameType(a2); 256 } else { 257 return false; 258 } 259 } 260 261 public boolean ArrayTypeAccess.sameType(ArrayTypeAccess a) { 262 ArrayTypeAccess at1 = this; 263 ArrayTypeAccess at2 = a; 264 while (true) { 265 Access a1 = at1.getAccess(); 266 Access a2 = at2.getAccess(); 267 if (a1 instanceof ArrayTypeAccess && a2 instanceof ArrayTypeAccess) { 268 at1 = (ArrayTypeAccess) a1; 269 at2 = (ArrayTypeAccess) a2; 270 continue; 271 } else { 272 return a1.sameType(a2); 273 } 274 } 275 } 276 277 // 9.8 278 eq InterfaceDecl.isFunctional() { 279 LinkedList<MethodDecl> methods = collectAbstractMethods(); 280 boolean foundMethod = false; 281 282 if (methods.size() == 0) { 283 return false; 284 } else if (methods.size() == 1) { 285 return true; 286 } else { 287 for (MethodDecl current : methods) { 288 foundMethod = true; 289 for (MethodDecl inner : methods) { 290 if (!current.subsignatureTo(inner) || !current.returnTypeSubstitutableFor(inner)) { 291 foundMethod = false; 292 } 293 } 294 if (foundMethod) { 295 break; 296 } 297 } 298 } 299 return foundMethod; 300 } 301 302 eq ParInterfaceDecl.isFunctional() = ((InterfaceDecl) original()).isFunctional(); 303 304 //9.8 305 syn lazy LinkedList<MethodDecl> InterfaceDecl.collectAbstractMethods() { 306 LinkedList<MethodDecl> methods = new LinkedList<MethodDecl>(); 307 Map<String, SimpleSet> map = localMethodsSignatureMap(); 308 Map<String, SimpleSet> objectMethods = typeObject().methodsSignatureMap(); 309 MethodDecl inObject; 310 311 for (Map.Entry<String,SimpleSet> entry: map.entrySet()) { 312 SimpleSet set = entry.getValue(); 313 MethodDecl m = (MethodDecl) set.iterator().next(); 314 315 SimpleSet objectSet = objectMethods.get(m.signature()); 316 if (m.isAbstract()) { 317 if (objectSet == null || objectSet.isEmpty()) { 318 methods.add(m); 319 } else { 320 inObject = (MethodDecl) objectSet.iterator().next(); 321 if (!inObject.isPublic()) { 322 methods.add(m); 323 } 324 } 325 } 326 } 327 328 for (Iterator outerIter = interfacesIterator(); outerIter.hasNext();) { 329 TypeDecl typeDecl = (TypeDecl) outerIter.next(); 330 for (Iterator iter = typeDecl.methodsIterator(); iter.hasNext();) { 331 MethodDecl m = (MethodDecl) iter.next(); 332 333 if (m.isAbstract() && !m.isPrivate() && m.accessibleFrom(this)) { 334 SimpleSet objectSet = objectMethods.get(m.signature()); 335 if (objectSet == null || objectSet.isEmpty()) { 336 methods.add(m); 337 } else { 338 inObject = (MethodDecl) objectSet.iterator().next(); 339 if (!inObject.isPublic()) { 340 methods.add(m); 341 } 342 } 343 } 344 } 345 } 346 return methods; 347 } 348 349 eq GenericMethodDecl.usesTypeVariable() = 350 super.usesTypeVariable() || getTypeParameterList().usesTypeVariable(); 351 352 /*List<Access> GenericMethodDecl.substituteTypeParameters(List<Access> typeParameters, Parameterization parTypeDecl) { 353 List l = new List<Access>(); 354 for (Access a : typeParameters) { 355 l.add(a.type().substitute(parTypeDecl)); 356 } 357 return l; 358 } 359 360 refine LookupParTypeDecl 361 public BodyDecl GenericMethodDecl.substitutedBodyDecl(Parameterization parTypeDecl) { 362 //System.out.println("Begin substituting generic " + signature() + " in " + hostType().typeName() + " with " + parTypeDecl.typeSignature()); 363 List tmpList = getTypeParameterList().treeCopyNoTransform(); 364 for (Object o : tmpList) { 365 TypeVariable v = (TypeVariable)o; 366 v.setTypeBoundList(substituteTypeParameters(v.getTypeBoundList(), parTypeDecl)); 367 } 368 369 GenericMethodDecl m = new GenericMethodDecl( 370 (Modifiers)getModifiers().treeCopyNoTransform(), 371 getTypeAccess().type().substituteReturnType(parTypeDecl), 372 getID(), 373 getParameterList().substitute(parTypeDecl), 374 getExceptionList().substitute(parTypeDecl), 375 new Opt(), 376 tmpList 377 ); 378 m.original = this; 379 //System.out.println("End substituting generic " + signature()); 380 return m; 381 }*/ 382 }