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 LambdaExpr { 029 030 eq LambdaAnonymousDecl.unqualifiedLookupMethod(String name) { 031 if (getParent().getParent().getParent() instanceof MethodReference) { 032 return ((MethodReference) getParent().getParent().getParent()).lookupMethod(name); 033 } else if (getParent().getParent().getParent() instanceof ConstructorReference) { 034 return ((ConstructorReference) getParent().getParent().getParent()).lookupMethod(name); 035 } else { 036 return enclosingLambda().lookupMethod(name); 037 } 038 } 039 040 syn lazy int LambdaExpr.arity() = numParameters(); 041 042 syn lazy int LambdaParameters.numParameters(); 043 syn lazy int LambdaExpr.numParameters() = getLambdaParameters().numParameters(); 044 045 eq InferredLambdaParameters.numParameters() = getNumParameter(); 046 eq DeclaredLambdaParameters.numParameters() = getNumParameter(); 047 048 syn lazy boolean LambdaParameters.congruentTo(FunctionDescriptor f); 049 050 // 15.27.3 051 eq InferredLambdaParameters.congruentTo(FunctionDescriptor f) = 052 numParameters() == f.method.getNumParameter(); 053 054 // 15.27.3 055 eq DeclaredLambdaParameters.congruentTo(FunctionDescriptor f) { 056 if (numParameters() != f.method.getNumParameter()) { 057 return false; 058 } 059 for (int i = 0; i < numParameters(); i++) { 060 //Lambdas can't declare type variables so that doesn't need to be taken into account 061 if (getParameter(i).type() != f.method.getParameter(i).type()) { 062 return false; 063 } 064 } 065 return true; 066 } 067 068 syn lazy boolean LambdaExpr.isImplicit() = getLambdaParameters() instanceof InferredLambdaParameters; 069 syn lazy boolean LambdaExpr.isExplicit() = !isImplicit(); 070 071 syn lazy boolean LambdaBody.congruentTo(FunctionDescriptor f); 072 073 // 15.27.3 074 eq ExprLambdaBody.congruentTo(FunctionDescriptor f) { 075 if (f.method.type().isVoid()) { 076 return getExpr().stmtCompatible(); 077 } else { 078 return getExpr().assignConversionTo(f.method.type()); 079 } 080 } 081 082 // 15.27.3 083 eq BlockLambdaBody.congruentTo(FunctionDescriptor f) { 084 if (f.method.type().isVoid()) { 085 return voidCompatible(); 086 } else { 087 if (!valueCompatible()) { 088 return false; 089 } 090 for (ReturnStmt returnStmt : lambdaReturns()) { 091 if (!returnStmt.getResult().assignConversionTo(f.method.type())) { 092 return false; 093 } 094 } 095 return true; 096 } 097 } 098 099 /* BEWARE! READ THIS BEFORE USING THIS METHOD! 100 The congruency check will currently not infer different types for eventual inferred parameters, 101 but the target type function descriptor will always be used for inference. Thus this check will 102 NOT work for arbitrary function descriptors if there are inferred parameters in the lambda. Currently, 103 there is no use for this to work anyway because a lambda with inferred parameters will never be 104 pertinent to applicability and thus not need to be congruency checked, but in case there is need 105 for arbitary congruency checks that handle inferrence differently depending on the function descriptor 106 input to this method, then this check must be altered! */ 107 // 15.27.3 108 syn lazy boolean LambdaExpr.congruentTo(FunctionDescriptor f) = 109 !f.isGeneric() && getLambdaParameters().congruentTo(f) && getLambdaBody().congruentTo(f); 110 111 refine LookupParTypeDecl 112 public Access ParTypeDecl.substitute(Parameterization parTypeDecl) { 113 // TODO: include nesting as well.... 114 if (parTypeDecl.isRawType()) { 115 return ((GenericTypeDecl) genericDecl()).rawType().createBoundAccess(); 116 } 117 118 /* These lines have been removed because they erase arguments from 119 parameter types when they are not using type variables, for example 120 C<String> is substituted to only C, which I don't think is correct? 121 And if the ParTypeDecl doesn't use any type variables, why is there 122 even any need for further substitution? 123 124 if (!usesTypeVariable()) { 125 return super.substitute(parTypeDecl); 126 } 127 */ 128 List<Access> list = new List<Access>(); 129 for (Access argument : getArgumentList()) { 130 list.add(argument.type().substitute(parTypeDecl)); 131 } 132 return new ParTypeAccess(genericDecl().createQualifiedAccess(), list); 133 } 134 } 135 136 aspect StmtCompatible { 137 syn lazy boolean Expr.stmtCompatible() = false; 138 syn lazy boolean ConstructorAccess.stmtCompatible() = true; 139 syn lazy boolean ClassInstanceExpr.stmtCompatible() = true; 140 syn lazy boolean AssignExpr.stmtCompatible() = true; 141 syn lazy boolean PostIncExpr.stmtCompatible() = true; 142 syn lazy boolean PostDecExpr.stmtCompatible() = true; 143 syn lazy boolean PreIncExpr.stmtCompatible() = true; 144 syn lazy boolean PreDecExpr.stmtCompatible() = true; 145 syn lazy boolean MethodAccess.stmtCompatible() = true; 146 syn lazy boolean AbstractDot.stmtCompatible() = getRight().stmtCompatible(); 147 } 148 149 aspect ExceptionHandling { 150 eq LambdaExpr.getLambdaBody().handlesException(TypeDecl exceptionType) { 151 InterfaceDecl iDecl = targetInterface(); 152 if (iDecl == null) { 153 return false; 154 } else if (!iDecl.isFunctional()) { 155 return false; 156 } 157 for (TypeDecl exception : iDecl.functionDescriptor().throwsList) { 158 if (exceptionType.strictSubtype(exception)) { 159 return true; 160 } 161 } 162 return false; 163 } 164 }