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 TypeCheck { 029 inh TypeDecl LambdaParameters.unknownType(); 030 inh TypeDecl InferredParameterDeclaration.unknownType(); 031 inh TypeDecl LambdaBody.unknownType(); 032 eq LambdaExpr.getLambdaParameters().unknownType() = unknownType(); 033 eq LambdaExpr.getLambdaBody().unknownType() = unknownType(); 034 035 syn lazy TypeDecl IntersectionCastExpr.type() = unknownType(); 036 037 // Lambdas should propagate target return type to returns in lambda body. 038 eq BlockLambdaBody.getBlock().returnType() { 039 TypeDecl decl = enclosingLambda().targetType(); 040 if (decl == null) { 041 return unknownType(); 042 } else if (!(decl instanceof InterfaceDecl)) { 043 return unknownType(); 044 } else { 045 InterfaceDecl iDecl = (InterfaceDecl)decl; 046 if (!iDecl.isFunctional()) { 047 return unknownType(); 048 } else { 049 return iDecl.functionDescriptor().method.type(); 050 } 051 } 052 } 053 054 055 syn lazy TypeDecl LambdaExpr.type() { 056 // 15.27.3 057 if (!assignmentContext() && !castContext() && !invocationContext()) { 058 return unknownType(); 059 } 060 if (targetInterface() == null) { 061 return unknownType(); 062 } 063 064 InterfaceDecl iDecl = targetInterface(); 065 if (!iDecl.isFunctional()) { 066 return unknownType(); 067 } 068 if (congruentTo(iDecl.functionDescriptor())) { 069 return iDecl; 070 } else { 071 return unknownType(); 072 } 073 } 074 075 syn lazy TypeDecl MethodReference.type() { 076 // 15.13.1 077 if (!assignmentContext() && !castContext() && !invocationContext()) { 078 return unknownType(); 079 } 080 if (targetInterface() == null) { 081 return unknownType(); 082 } 083 084 InterfaceDecl iDecl = targetInterface(); 085 if (!iDecl.isFunctional()) { 086 return unknownType(); 087 } 088 089 if (congruentTo(iDecl.functionDescriptor())) { 090 return iDecl; 091 } else { 092 return unknownType(); 093 } 094 } 095 096 syn lazy TypeDecl ConstructorReference.type() { 097 // 15.13.1 098 if (!assignmentContext() && !castContext() && !invocationContext()) { 099 return unknownType(); 100 } 101 if (targetInterface() == null) { 102 return unknownType(); 103 } 104 105 InterfaceDecl iDecl = targetInterface(); 106 if (!iDecl.isFunctional()) { 107 return unknownType(); 108 } 109 110 return iDecl; 111 } 112 113 114 /* TODO: Type check that works for wildcard-parameterized interfaces */ 115 public void LambdaExpr.typeCheck() { 116 if (!assignmentContext() && !castContext() && !invocationContext()) { 117 // 15.27 118 error("Lambda expressions must target a functional interface"); 119 return; 120 } 121 122 // This means there was an error in the overload resolution, will be reported elsewhere 123 if (invocationContext() && targetType() == unknownType()) { 124 return; 125 } 126 127 if (!targetType().isFunctionalInterface()) { 128 // 15.27 129 error("Lambda expressions must target a functional interface"); 130 return; 131 } 132 133 InterfaceDecl iDecl = targetInterface(); 134 135 if (!iDecl.isFunctional()) { 136 // 15.27 137 errorf("Interface %s is not functional and can therefore not be targeted by a lambda expression", 138 iDecl.typeName()); 139 return; 140 } 141 142 FunctionDescriptor f = iDecl.functionDescriptor(); 143 144 if (f.isGeneric()) { 145 // 15.27 146 errorf("Illegal lambda expression: Method %s in interface %s is generic", 147 iDecl.functionDescriptor().method.name(), iDecl.typeName()); 148 return; 149 } 150 151 if (!getLambdaParameters().congruentTo(f)) { 152 errorf("Lambda expression parameters incompatible with" 153 + " parameters in method %s in interface %s", 154 f.method.name(), iDecl.typeName()); 155 } 156 157 if (getLambdaBody() instanceof ExprLambdaBody) { 158 ExprLambdaBody exprBody = (ExprLambdaBody)getLambdaBody(); 159 if (f.method.type().isVoid()) { 160 if (!exprBody.getExpr().stmtCompatible()) { 161 errorf("Lambda expression body must be a statement expression," 162 + " because the method %s in interface %s has return type void", 163 f.method.name(), iDecl.typeName()); 164 } 165 } else { 166 if (!exprBody.getExpr().type().assignConversionTo(f.method.type(), exprBody.getExpr())) { 167 errorf("Lambda expression body is not compatible with" 168 + " the return type %s in method %s in interface %s", 169 f.method.type().typeName(), f.method.name(), iDecl.typeName()); 170 } 171 } 172 } else { 173 BlockLambdaBody blockBody = (BlockLambdaBody)getLambdaBody(); 174 if (f.method.type().isVoid()) { 175 if (!blockBody.voidCompatible()) { 176 errorf("Lambda expression body is not allowed to return a value," 177 + " because the method %s in interface %s has return type void", 178 f.method.name(), iDecl.typeName()); 179 } 180 } else if (!blockBody.valueCompatible()) { 181 errorf("Lambda expression body must not complete normally or contain empty return" 182 + " statments, because the method %s in interface" 183 + " %s has a return type which is non-void", 184 f.method.name(), iDecl.typeName()); 185 } 186 } 187 } 188 189 public void BlockLambdaBody.typeCheck() { 190 // 15.27.2 191 if (!voidCompatible() && !valueCompatible()) { 192 error("Block lambda bodies must be either void or value compatible"); 193 } 194 } 195 196 refine TypeCheck 197 public void ReturnStmt.typeCheck() { 198 if (enclosingLambda() == null || enclosingLambda().hostType() != hostType()) { 199 if (hasResult() && !returnType().isVoid()) { 200 if (!getResult().type().assignConversionTo(returnType(), getResult())) { 201 errorf("return value must be an instance of %s which %s is not", 202 returnType().typeName(), getResult().type().typeName()); 203 } 204 } 205 // 8.4.5 8.8.5 206 if (returnType().isVoid() && hasResult()) { 207 error("return stmt may not have an expression in void methods"); 208 } 209 // 8.4.5 210 if (!returnType().isVoid() && !hasResult()) { 211 error("return stmt must have an expression in non void methods"); 212 } 213 if (enclosingBodyDecl() instanceof InstanceInitializer 214 || enclosingBodyDecl() instanceof StaticInitializer) { 215 error("Initializers may not return"); 216 } 217 } else { 218 if (hasResult() && !returnType().isVoid() && !(getResult() instanceof LambdaExpr)) { 219 if (!getResult().type().assignConversionTo(returnType(), getResult())) { 220 errorf("return value must be an instance of %s which %s is not", 221 returnType().typeName(), getResult().type().typeName()); 222 } 223 } 224 } 225 } 226 227 public void MethodReference.typeCheck() { 228 // 15.13.1 229 if (!assignmentContext() && !castContext() && !invocationContext()) { 230 error("Method references must target a functional interface"); 231 return; 232 } 233 234 // This means there was an error in the overload resolution, will be reported elsewhere. 235 if (invocationContext() && targetType() == unknownType()) { 236 return; 237 } 238 239 if (!targetType().isFunctionalInterface()) { 240 error("Method references must target a functional interface"); 241 return; 242 } 243 244 InterfaceDecl iDecl = targetInterface(); 245 246 if (!iDecl.isFunctional()) { 247 errorf("Interface %s is not functional and can therefore not be targeted by a method reference", 248 iDecl.typeName()); 249 return; 250 } 251 252 MethodDecl found = null; 253 FunctionDescriptor f = iDecl.functionDescriptor(); 254 // Lookup method here and check that one most specific can be found 255 if (this instanceof ExprMethodReference) { 256 ExprMethodReference ref = (ExprMethodReference)this; 257 found = ref.targetMethod(f); 258 if (unknownMethod() == found) { 259 // 15.13.1 260 errorf("No method %s that is compatible with the method %s in the interface %s was found", 261 name(), iDecl.functionDescriptor().method.fullSignature(), iDecl.typeName()); 262 } else if (found.isStatic()) { 263 errorf("The method %s in type %s must be accessed in a static way", 264 found.fullSignature(), found.hostType().typeName()); 265 } else if (ref.getExpr() instanceof Access && ((Access)ref.getExpr()).lastAccess() instanceof SuperAccess) { 266 // 15.13.2 267 if (found.isAbstract()) { 268 errorf("Cannot directly invoke the abstract method %s in type %s", 269 found.fullSignature(), found.hostType().typeName()); 270 } 271 272 SuperAccess superAccess = (SuperAccess)((Access)ref.getExpr()).lastAccess(); 273 if (superAccess.isQualified() && superAccess.decl() instanceof InterfaceDecl) { 274 if (hostType().isClassDecl()) { 275 ClassDecl classDecl = (ClassDecl)hostType(); 276 if (classDecl.hasOverridingMethodInSuper(found)) { 277 errorf("Cannot make a super reference to method %s, there is a more specific override", 278 found.fullSignature()); 279 } 280 } else if (hostType().isInterfaceDecl()) { 281 InterfaceDecl interfaceDecl = (InterfaceDecl)hostType(); 282 if (interfaceDecl.hasOverridingMethodInSuper(found)) { 283 errorf("Cannot make a super reference to method %s, there is a more specific override", 284 found.fullSignature()); 285 } 286 } 287 } 288 289 } 290 } else if (this instanceof TypeMethodReference) { 291 TypeMethodReference ref = (TypeMethodReference) this; 292 MethodDecl staticMethod = ref.targetStaticMethod(f); 293 MethodDecl instanceMethod = ref.targetInstanceMethod(f); 294 if (ref.validStaticMethod(f) && ref.validInstanceMethod(f)) { 295 errorf("Ambiguity error: two possible methods %s was found", staticMethod.name()); 296 return; 297 } else if (unknownMethod() == staticMethod && unknownMethod() == instanceMethod) { 298 errorf("No method %s that is compatible with the method %s in the interface %s was found", 299 name(), iDecl.functionDescriptor().method.fullSignature(), iDecl.typeName()); 300 return; 301 } else if (ref.validStaticMethod(f)) { 302 if (ref.getTypeAccess() instanceof ParTypeAccess) { 303 error("Parameterized qualifier is not allowed for static method references"); 304 } else { 305 found = staticMethod; 306 } 307 } else if (ref.validInstanceMethod(f)) { 308 found = instanceMethod; 309 } else if (unknownMethod() != staticMethod && !staticMethod.isStatic()) { 310 errorf("Cannot make a static reference to the non-static method %s in type %s", 311 staticMethod.fullSignature(), staticMethod.hostType().typeName()); 312 return; 313 } else if (instanceMethod.isStatic()) { 314 errorf("The method %s in type %s must be accessed in a static way", 315 instanceMethod.fullSignature(), instanceMethod.hostType().typeName()); 316 return; 317 } 318 } 319 320 if (found != null && unknownMethod() != found) { 321 // Check that found is compatible with the function descriptor 322 if (!iDecl.functionDescriptor().method.type().isVoid()) { 323 // 15.13.1 324 if (found.type().isVoid() 325 || !found.type().assignConversionTo(iDecl.functionDescriptor().method.type(), null)) { 326 errorf("Return type of referenced method %s is not compatible with method %s in interface %s", 327 found.fullSignature(), iDecl.functionDescriptor().method.fullSignature(), 328 iDecl.typeName()); 329 } 330 } 331 332 for (int i = 0; i < found.getNumException(); i++) { 333 TypeDecl exception = found.getException(i).type(); 334 if (exception.isUncheckedException()) { 335 continue; 336 } 337 338 boolean legalException = false; 339 for (TypeDecl descriptorThrows : iDecl.functionDescriptor().throwsList) { 340 if (exception.strictSubtype(descriptorThrows)) { 341 legalException = true; 342 break; 343 } 344 } 345 if (!legalException) { 346 // 15.13.1 347 errorf("Referenced method %s throws unhandled exception type %s", 348 found.name(), exception.typeName()); 349 } 350 } 351 } 352 } 353 354 public void ConstructorReference.typeCheck() { 355 // 15.13.1 356 if (!assignmentContext() && !castContext() && !invocationContext()) { 357 error("Constructor references must target a functional interface"); 358 return; 359 } 360 361 // This means there was an error in the overload resolution, will be reported elsewhere 362 if (invocationContext() && targetType() == unknownType()) { 363 return; 364 } 365 366 if (!targetType().isFunctionalInterface()) { 367 error("Constructor references must target a functional interface"); 368 return; 369 } 370 InterfaceDecl iDecl = targetInterface(); 371 372 if (!iDecl.isFunctional()) { 373 errorf("Interface %s is not functional and can therefore not be targeted by a constructor reference", 374 iDecl.typeName()); 375 return; 376 } 377 378 FunctionDescriptor f = iDecl.functionDescriptor(); 379 380 if (this instanceof ClassReference) { 381 ClassReference ref = (ClassReference)this; 382 ConstructorDecl decl = ref.targetConstructor(f); 383 if (unknownConstructor() == decl) { 384 errorf("No constructor for the type %s that is compatible with the method %s in the interface %s was found", 385 getTypeAccess().type().typeName(), f.method.fullSignature(), iDecl.typeName()); 386 } 387 if (!f.method.type().isVoid()) { 388 // 15.13.1 389 TypeDecl returnType = ref.syntheticInstanceExpr(f).type(); 390 if (!returnType.assignConversionTo(f.method.type(), null)) { 391 errorf("Return type of method %s in interface %s is not compatible with" 392 + " referenced constructor which has return type: %s", 393 f.method.fullSignature(), iDecl.typeName(), returnType.typeName()); 394 } 395 } 396 for (int i = 0; i < decl.getNumException(); i++) { 397 TypeDecl exception = decl.getException(i).type(); 398 if (exception.isUncheckedException()) { 399 continue; 400 } 401 402 boolean legalException = false; 403 for (TypeDecl descriptorThrows : iDecl.functionDescriptor().throwsList) { 404 if (exception.strictSubtype(descriptorThrows)) { 405 legalException = true; 406 break; 407 } 408 } 409 if (!legalException) { 410 // 15.13.1 411 errorf("Referenced constructor %s throws unhandled exception type %s", 412 decl.name(), exception.typeName()); 413 } 414 } 415 ref.syntheticInstanceExpr(f).typeCheck(); 416 } else { 417 ArrayReference ref = (ArrayReference)this; 418 if (f.method.getNumParameter() != 1) { 419 errorf("Array reference not compatible with method %s in interface %s," 420 + " should have a single parameter of type int", 421 f.method.fullSignature(), iDecl.typeName()); 422 return; 423 } 424 if (!f.method.getParameter(0).type().assignConversionTo(iDecl.typeInt(), null)) { 425 errorf("Array reference not compatible with method %s in interface %s," 426 + " should have a single parameter of type int", 427 f.method.fullSignature(), iDecl.typeName()); 428 return; 429 } 430 if (!f.method.type().isVoid()) { 431 if (!getTypeAccess().type().assignConversionTo(f.method.type(), null)) { 432 errorf("Return type %s of method %s in interface %s is not compatible with" 433 + " the array reference type %s", 434 f.method.type().typeName(), f.method.fullSignature(), iDecl.typeName(), 435 getTypeAccess().type().typeName()); 436 } 437 } 438 } 439 } 440 441 refine TypeCheck 442 eq MethodDecl.mayOverride(MethodDecl m) { 443 // 9.4.3 444 if (isDefault() && m.hostType() == type().typeObject() && !m.isPrivate()) { 445 return false; 446 } else { 447 return returnTypeSubstitutableFor(m); 448 } 449 } 450 } 451 452 aspect LambdaParametersInference { 453 inh lazy TypeDecl InferredParameterDeclaration.inferredType(); 454 eq InferredLambdaParameters.getParameter(int i).inferredType() { 455 if (enclosingLambda().targetInterface() == null) { 456 return unknownType(); 457 } 458 InterfaceDecl iDecl = (InterfaceDecl)enclosingLambda().targetInterface(); 459 if (!iDecl.isFunctional()) { 460 return unknownType(); 461 } else if (iDecl.functionDescriptor().method.getNumParameter() < i + 1) { 462 return unknownType(); 463 } else { 464 return iDecl.functionDescriptor().method.getParameter(i).type(); 465 } 466 } 467 }