001    /*
002     * The JastAdd Extensible Java Compiler (http://jastadd.org) is covered
003     * by the modified BSD License. You should have received a copy of the
004     * modified BSD license with this compiler.
005     * 
006     * Copyright (c) 2005-2008, Torbjorn Ekman
007     * All rights reserved.
008     */
009    
010    
011    aspect TypeCheck {
012      public void ASTNode.typeCheck() {
013      }
014      
015      syn boolean Expr.isVariable() = false;
016      eq AbstractDot.isVariable() = lastAccess().isVariable();
017      eq VarAccess.isVariable() = true;
018      eq ArrayAccess.isVariable() = true;
019      eq ParExpr.isVariable() = getExpr().isVariable();
020     
021      // 5.2
022      public void VariableDeclaration.typeCheck() {
023        if(hasInit()) {
024          TypeDecl source = getInit().type();
025          TypeDecl dest = type();
026          if(!source.assignConversionTo(dest, getInit()))
027            error("can not assign variable " + name() + " of type " + dest.typeName() +
028                  " a value of type " + source.typeName());
029        }
030      }
031    
032      // 5.2
033      public void FieldDeclaration.typeCheck() {
034        if(hasInit()) {
035          TypeDecl source = getInit().type();
036          TypeDecl dest = type();
037          if(!source.assignConversionTo(dest, getInit()))
038            error("can not assign field " + name() + " of type " + dest.typeName() +
039                  " a value of type " + source.typeName());
040        }
041      }
042    
043      // 5.2 Assignment Conversion
044      public void AssignSimpleExpr.typeCheck() {
045        if(!getDest().isVariable())
046          error("left hand side is not a variable");
047        else if(!sourceType().assignConversionTo(getDest().type(), getSource()) && !sourceType().isUnknown())
048          error("can not assign " + getDest() + " of type " + getDest().type().typeName() +
049                " a value of type " + sourceType().typeName());
050      }
051      
052      public void AssignExpr.typeCheck() {
053        if(!getDest().isVariable())
054          error("left hand side is not a variable");
055        else {
056          TypeDecl source = sourceType();
057          TypeDecl dest = getDest().type();
058          if(getSource().type().isPrimitive() && getDest().type().isPrimitive())
059            return;
060          error("can not assign " + getDest() + " of type " + getDest().type().typeName() +
061                " a value of type " + sourceType().typeName());
062        }
063      }
064    
065      public void AssignMultiplicativeExpr.typeCheck() {
066        if(sourceType().isBoolean() || getDest().type().isBoolean())
067          error("Multiplicative operators do not operate on boolean types");
068        super.typeCheck();
069      }
070      
071      public void AssignPlusExpr.typeCheck() {
072        if(!getDest().isVariable())
073          error("left hand side is not a variable");
074        else if(getSource().type().isUnknown() || getDest().type().isUnknown())
075          return;
076        else if(getDest().type().isString() && !(getSource().type().isVoid()))
077          return;
078        else if(getSource().type().isBoolean() || getDest().type().isBoolean())
079          error("Operator + does not operate on boolean types");
080        else if(getSource().type().isPrimitive() && getDest().type().isPrimitive())
081          return;
082        else
083          error("can not assign " + getDest() + " of type " + getDest().type().typeName() +
084                " a value of type " + sourceType().typeName());
085      }
086      public void AssignMinusExpr.typeCheck() {
087        if(sourceType().isBoolean() || getDest().type().isBoolean())
088          error("Operator - does not operate on boolean types");
089        super.typeCheck();
090      }
091      
092      public void AssignShiftExpr.typeCheck() {
093        if(!sourceType().isIntegralType() || !getDest().type().isIntegralType())
094          error("Shift operators only operate on integral types");
095        super.typeCheck();
096      }
097      
098      public void AssignBitwiseExpr.typeCheck() {
099        TypeDecl source = sourceType();
100        TypeDecl dest = getDest().type();
101        if(source.isIntegralType() && dest.isIntegralType())
102          super.typeCheck();
103        else if(source.isBoolean() && dest.isBoolean())
104          super.typeCheck();
105        else
106          error("Operator only operates on integral and boolean types");
107      }
108    
109      syn TypeDecl AssignExpr.sourceType() = getSource().type().isPrimitive() ? getSource().type() : unknownType();
110      
111      eq AssignPlusExpr.sourceType() {
112        TypeDecl left = getDest().type();
113        TypeDecl right = getSource().type();
114        if(!left.isString() && !right.isString())
115          return super.sourceType();
116        if(left.isVoid() || right.isVoid())
117          return unknownType();
118        return left.isString() ? left : right;
119      }
120      
121      syn TypeDecl AssignSimpleExpr.sourceType() = getSource().type();
122    
123      // 5.3 Method Invocation Conversion
124      public void MethodAccess.typeCheck() {
125        for(int i = 0; i < decl().getNumParameter(); i++) {
126          TypeDecl exprType = getArg(i).type();
127          TypeDecl parmType = decl().getParameter(i).type();
128          if(!exprType.methodInvocationConversionTo(parmType) && !exprType.isUnknown() && !parmType.isUnknown()) {
129            error("The type " + exprType.typeName() + " of expr " +
130                getArg(i) + " is not compatible with the method parameter " +
131                decl().getParameter(i));
132          }
133        }
134      }
135              
136      // 15.13
137      public void ArrayAccess.typeCheck() {
138        if(isQualified() && !qualifier().type().isArrayDecl() && !qualifier().type().isUnknown())
139          error("the type " + qualifier().type().name() + " of the indexed element is not an array");
140        if(!getExpr().type().unaryNumericPromotion().isInt() || !getExpr().type().isIntegralType())
141          error("array index must be int after unary numeric promotion which " + getExpr().type().typeName() + " is not");
142      }
143    
144      public void ArrayInit.typeCheck() {
145        TypeDecl initializerType = declType().componentType();
146        if(initializerType.isUnknown())
147          error("the dimension of the initializer is larger than the expected dimension");
148        for(int i = 0; i < getNumInit(); i++) {
149          Expr e = getInit(i);
150          if(!e.type().assignConversionTo(initializerType, e))
151            error("the type " + e.type().name() + " of the initializer is not compatible with " + initializerType.name()); 
152        }
153      }
154    
155      // 15.17
156      public void MultiplicativeExpr.typeCheck() {
157        if(!getLeftOperand().type().isNumericType())
158          error(getLeftOperand().type().typeName() + " is not numeric");
159        if(!getRightOperand().type().isNumericType())
160          error(getRightOperand().type().typeName() + " is not numeric");
161      }
162    
163      // 15.18
164      public void AdditiveExpr.typeCheck() {
165        if(!getLeftOperand().type().isNumericType())
166          error(getLeftOperand().type().typeName() + " is not numeric");
167        if(!getRightOperand().type().isNumericType())
168          error(getRightOperand().type().typeName() + " is not numeric");
169      }
170      
171      // 15.18
172      public void AddExpr.typeCheck() {
173        TypeDecl left = getLeftOperand().type();
174        TypeDecl right = getRightOperand().type();
175        if(!left.isString() && !right.isString())
176          super.typeCheck();
177        else if(left.isVoid())
178          error("The type void of the left hand side is not numeric");
179        else if(right.isVoid())
180          error("The type void of the right hand side is not numeric");
181      }     
182    
183      // 15.19
184      public void ShiftExpr.typeCheck() {
185        if(!getLeftOperand().type().isIntegralType())
186          error(getLeftOperand().type().typeName() + " is not integral");
187        if(!getRightOperand().type().isIntegralType())
188          error(getRightOperand().type().typeName() + " is not integral");
189      }
190      
191      // 15.22
192      public void BitwiseExpr.typeCheck() {
193        TypeDecl left = getLeftOperand().type();
194        TypeDecl right = getRightOperand().type();
195        if(left.isIntegralType() && right.isIntegralType())
196          return;
197        else if(left.isBoolean() && right.isBoolean())
198          return;
199        else
200          error(left.typeName() + " is not compatible with " + right.typeName());
201      }
202    
203      // 15.20
204      public void RelationalExpr.typeCheck() {
205        if(!getLeftOperand().type().isNumericType())
206          error(getLeftOperand().type().typeName() + " is not numeric");
207        if(!getRightOperand().type().isNumericType())
208          error(getRightOperand().type().typeName() + " is not numeric");
209      }
210    
211      // 15.23, 15.24
212      public void LogicalExpr.typeCheck() {
213        if(!getLeftOperand().type().isBoolean())
214          error(getLeftOperand().type().typeName() + " is not boolean");
215        if(!getRightOperand().type().isBoolean())
216          error(getRightOperand().type().typeName() + " is not boolean");
217      }
218    
219      // 15.21
220      public void EqualityExpr.typeCheck() {
221        TypeDecl left = getLeftOperand().type();
222        TypeDecl right = getRightOperand().type();
223        if(left.isNumericType() && right.isNumericType())
224          return;
225        else if(left.isBoolean() && right.isBoolean())
226          return;
227        else if((left.isReferenceType() || left.isNull()) && (right.isReferenceType() || right.isNull())) {
228          if(left.castingConversionTo(right) || right.castingConversionTo(left))
229            return;
230        }
231        error(left.typeName() + " can not be compared to " + right.typeName());
232      }
233    
234      // 15.20.2
235      public void InstanceOfExpr.typeCheck() {
236        TypeDecl relationalExpr = getExpr().type();
237        TypeDecl referenceType = getTypeAccess().type();
238        if(!relationalExpr.isUnknown()) {
239          if(!relationalExpr.isReferenceType() && !relationalExpr.isNull())
240            error("The relational expression in instance of must be reference or null type");
241          if(!referenceType.isReferenceType())
242            error("The reference expression in instance of must be reference type");
243          if(!relationalExpr.castingConversionTo(referenceType))
244            error("The type " + relationalExpr.typeName() + " of the relational expression " + 
245              getExpr() +  " can not be cast into the type " + referenceType.typeName());
246          if(getExpr().isTypeAccess())
247            error("The relational expression " + getExpr() + " must not be a type name");
248        }
249      }
250      
251      // 15.16
252      public void CastExpr.typeCheck() {
253        TypeDecl expr = getExpr().type();
254        TypeDecl type = getTypeAccess().type();
255        if(!expr.isUnknown()) {
256          if(!expr.castingConversionTo(type))
257            error(expr.typeName() + " can not be cast into " + type.typeName());
258          if(!getTypeAccess().isTypeAccess())
259            error("" + getTypeAccess() + " is not a type access in cast expression");
260        }
261      }
262    
263      public void ParExpr.typeCheck() {
264        if(getExpr().isTypeAccess())
265          error("" + getExpr() + " is a type and may not be used in parenthesized expression");
266      }
267      
268      // 15.15.3
269      public void PlusExpr.typeCheck() {
270        if(!getOperand().type().isNumericType())
271          error("unary plus only operates on numeric types");
272      }
273      
274      // 15.15.4
275      public void MinusExpr.typeCheck() {
276        if(!getOperand().type().isNumericType())
277          error("unary minus only operates on numeric types");
278      }
279    
280      // 15.15.5
281      public void BitNotExpr.typeCheck() {
282        if(!getOperand().type().isIntegralType())
283          error("unary ~ only operates on integral types");
284      }
285    
286      // 15.15.6
287      public void LogNotExpr.typeCheck() {
288        if(!getOperand().type().isBoolean())
289          error("unary ! only operates on boolean types");
290      }
291    
292      // 15.14
293      public void PostfixExpr.typeCheck() {
294        if(!getOperand().isVariable())
295          error("postfix expressions only work on variables");
296        else if(!getOperand().type().isNumericType())
297          error("postfix expressions only operates on numeric types");
298      }
299    
300      // 15.15.1
301      public void PreIncExpr.typeCheck() {
302        if(!getOperand().isVariable())
303          error("prefix increment expression only work on variables");
304        else if(!getOperand().type().isNumericType())
305          error("unary increment only operates on numeric types");
306      }
307      
308      // 15.15.2
309      public void PreDecExpr.typeCheck() {
310        if(!getOperand().isVariable())
311          error("prefix decrement expression only work on variables");
312        else if(!getOperand().type().isNumericType())
313          error("unary decrement only operates on numeric types");
314      }
315    
316      public void IfStmt.typeCheck() {
317        TypeDecl cond = getCondition().type();
318        if(!cond.isBoolean()) {
319          error("the type of \"" + getCondition() + "\" is " + cond.name() + " which is not boolean");
320        }
321      }
322      public void WhileStmt.typeCheck() {
323        TypeDecl cond = getCondition().type();
324        if(!cond.isBoolean()) {
325          error("the type of \"" + getCondition() + "\" is " + cond.name() + " which is not boolean");
326        }
327      }
328      public void DoStmt.typeCheck() {
329        TypeDecl cond = getCondition().type();
330        if(!cond.isBoolean()) {
331          error("the type of \"" + getCondition() + "\" is " + cond.name() + " which is not boolean");
332        }
333      }
334      public void ForStmt.typeCheck() {
335        if(hasCondition()) {
336          TypeDecl cond = getCondition().type();
337          if(!cond.isBoolean()) {
338            error("the type of \"" + getCondition() + "\" is " + cond.name() + " which is not boolean");
339          }
340        }
341      }
342    
343      public void SwitchStmt.typeCheck() {
344        TypeDecl type = getExpr().type();
345        if(!type.isIntegralType() || type.isLong())
346          error("Switch expression must be of char, byte, short, or int");
347      }
348    
349      public void ConstCase.typeCheck() {
350        TypeDecl switchType = switchType();
351        TypeDecl type = getValue().type();
352        if(!type.assignConversionTo(switchType, getValue()))
353          error("Constant expression must be assignable to Expression");
354        if(!getValue().isConstant() && !getValue().type().isUnknown()) 
355          error("Switch expression must be constant");
356      }
357    
358      inh TypeDecl Case.switchType();
359      eq SwitchStmt.getBlock().switchType() = getExpr().type();
360      eq Program.getChild().switchType() = unknownType();
361    
362      public void SynchronizedStmt.typeCheck() {
363        TypeDecl type = getExpr().type();
364        if(!type.isReferenceType() || type.isNull())
365          error("*** The type of the expression must be a reference");
366      }
367    
368      public void BasicCatch.typeCheck() {
369        if(!getParameter().type().instanceOf(typeThrowable()))
370          error("*** The catch variable must extend Throwable");
371      }
372    
373      public void ThrowStmt.typeCheck() {
374        if(!getExpr().type().instanceOf(typeThrowable()))
375          error("*** The thrown expression must extend Throwable");
376      }
377    
378      public void AssertStmt.typeCheck() {
379        // 14.10
380        if(!getfirst().type().isBoolean())
381          error("Assert requires boolean condition");
382        if(hasExpr() && getExpr().type().isVoid())
383          error("The second part of an assert statement may not be void");
384      }
385    
386      public void MethodDecl.typeCheck() {
387        // Thrown vs super class method see MethodDecl.nameCheck
388        // 8.4.4
389        TypeDecl exceptionType = typeThrowable();
390        for(int i = 0; i < getNumException(); i++) {
391          TypeDecl typeDecl = getException(i).type();
392          if(!typeDecl.instanceOf(exceptionType))
393            error(signature() + " throws non throwable type " + typeDecl.fullName());
394        }
395    
396        // check returns
397        if(!isVoid() && hasBlock() && getBlock().canCompleteNormally())
398          error("the body of a non void method may not complete normally");
399    
400      }
401      // 14.16
402      inh TypeDecl TypeDecl.typeVoid();
403      inh TypeDecl ReturnStmt.returnType();
404      eq TypeDecl.getBodyDecl().returnType() = typeVoid();
405      eq MethodDecl.getBlock().returnType() = type();
406      eq Program.getChild().returnType() = typeVoid();
407    
408      public void ReturnStmt.typeCheck() {
409        if(hasResult() && !returnType().isVoid()) {
410          if(!getResult().type().assignConversionTo(returnType(), getResult()))
411            error("return value must be an instance of " + returnType().typeName() + " which " + getResult().type().typeName() + " is not");
412        }
413        // 8.4.5 8.8.5
414        if(returnType().isVoid() && hasResult())
415          error("return stmt may not have an expression in void methods");
416        // 8.4.5
417        if(!returnType().isVoid() && !hasResult())
418          error("return stmt must have an expression in non void methods");
419        if(enclosingBodyDecl() instanceof InstanceInitializer || enclosingBodyDecl() instanceof StaticInitializer)
420          error("Initializers may not return");
421    
422      }
423    
424      public void ConstructorDecl.typeCheck() {
425        // 8.8.4 (8.4.4)
426        TypeDecl exceptionType = typeThrowable();
427        for(int i = 0; i < getNumException(); i++) {
428          TypeDecl typeDecl = getException(i).type();
429          if(!typeDecl.instanceOf(exceptionType))
430            error(signature() + " throws non throwable type " + typeDecl.fullName());
431        }
432      }
433    
434      public void ClassInstanceExpr.typeCheck() {
435        if(isQualified() && qualifier().isTypeAccess() && !qualifier().type().isUnknown())
436          error("*** The expression in a qualified class instance expr must not be a type name");
437        // 15.9
438        if(isQualified() && !type().isInnerClass() && !((ClassDecl)type()).superclass().isInnerClass() && !type().isUnknown()) {
439          error("*** Qualified class instance creation can only instantiate inner classes and their anonymous subclasses");
440        }
441        if(!type().isClassDecl()) {
442          error("*** Can only instantiate classes, which " + type().typeName() + " is not"); 
443        }
444        typeCheckEnclosingInstance();
445        typeCheckAnonymousSuperclassEnclosingInstance();
446      }
447    
448      public void ClassInstanceExpr.typeCheckEnclosingInstance() {
449        TypeDecl C = type();
450        if(!C.isInnerClass())
451          return;
452    
453        TypeDecl enclosing = null;
454        if(C.isAnonymous()) {
455          if(noEnclosingInstance()) {
456            enclosing = null;
457          }
458          else {
459            enclosing = hostType();
460          }
461        }
462        else if(C.isLocalClass()) {
463          if(C.inStaticContext()) {
464            enclosing = null;
465          }
466          else if(noEnclosingInstance()) {
467            enclosing = unknownType();
468          }
469          else {
470            TypeDecl nest = hostType();
471            while(nest != null && !nest.instanceOf(C.enclosingType()))
472              nest = nest.enclosingType();
473            enclosing = nest;
474          }
475        }
476        else if(C.isMemberType()) {
477          if(!isQualified()) {
478            if(noEnclosingInstance()) {
479              error("No enclosing instance to initialize " + C.typeName() + " with");
480              //System.err.println("ClassInstanceExpr: Non qualified MemberType " + C.typeName() + " is in a static context when instantiated in " + this);
481              enclosing = unknownType();
482            }
483            else {
484              TypeDecl nest = hostType();
485              while(nest != null && !nest.instanceOf(C.enclosingType()))
486                nest = nest.enclosingType();
487              enclosing = nest == null ? unknownType() : nest;
488            }
489          }
490          else {
491            enclosing = enclosingInstance();
492          }
493        }
494        if(enclosing != null && !enclosing.instanceOf(type().enclosingType())) {
495          String msg = enclosing == null ? "None" : enclosing.typeName();
496          error("*** Can not instantiate " + type().typeName() + " with the enclosing instance " + msg + " due to incorrect enclosing instance");
497        }
498        else if(!isQualified() && C.isMemberType() && inExplicitConstructorInvocation() && enclosing == hostType()) {
499          error("*** The innermost enclosing instance of type " + enclosing.typeName() + " is this which is not yet initialized here.");
500        }
501      }
502    
503      inh TypeDecl SuperConstructorAccess.enclosingInstance();
504      inh TypeDecl ClassInstanceExpr.enclosingInstance();
505      inh TypeDecl TypeDecl.enclosingInstance();
506      eq Program.getChild().enclosingInstance() = null;
507      eq StaticInitializer.getBlock().enclosingInstance() = null;
508      //eq InstanceInitializer.getBlock().enclosingInstance() = null;
509      eq TypeDecl.getBodyDecl().enclosingInstance() {
510        if(getBodyDecl(childIndex) instanceof MemberTypeDecl && !((MemberTypeDecl)getBodyDecl(childIndex)).typeDecl().isInnerType())
511          return null;
512        if(getBodyDecl(childIndex) instanceof ConstructorDecl)
513          return enclosingInstance();
514        return this;
515      }
516      eq AbstractDot.getRight().enclosingInstance() = getLeft().type();
517      eq ConstructorDecl.getConstructorInvocation().enclosingInstance() = unknownType();
518    
519      syn boolean ClassInstanceExpr.noEnclosingInstance() = isQualified() ? qualifier().staticContextQualifier() : inStaticContext();
520    
521      public void ClassInstanceExpr.typeCheckAnonymousSuperclassEnclosingInstance() {
522        if(type().isAnonymous() && ((ClassDecl)type()).superclass().isInnerType()) {
523          TypeDecl S = ((ClassDecl)type()).superclass();
524          if(S.isLocalClass()) {
525            if(S.inStaticContext()) {
526            }
527            else if(noEnclosingInstance()) {
528              error("*** No enclosing instance to class " + type().typeName() + " due to static context");
529            }
530            else if(inExplicitConstructorInvocation())
531              error("*** No enclosing instance to superclass " + S.typeName() + " of " + type().typeName() + " since this is not initialized yet");
532          }
533          else if(S.isMemberType()) {
534            if(!isQualified()) {
535              // 15.9.2 2nd paragraph
536              if(noEnclosingInstance()) {
537                error("*** No enclosing instance to class " + type().typeName() + " due to static context");
538              }
539              else {
540                TypeDecl nest = hostType();
541                while(nest != null && !nest.instanceOf(S.enclosingType()))
542                  nest = nest.enclosingType();
543                if(nest == null) {
544                  error("*** No enclosing instance to superclass " + S.typeName() + " of " + type().typeName());
545                }
546                else if(inExplicitConstructorInvocation()) {
547                  error("*** No enclosing instance to superclass " + S.typeName() + " of " + type().typeName() + " since this is not initialized yet");
548                }
549              }
550            }
551          }
552        }
553      }
554    
555      public void ArrayTypeWithSizeAccess.typeCheck() {
556        super.typeCheck();
557        if(!getExpr().type().unaryNumericPromotion().isInt())
558          error(getExpr().type().typeName() + " is not int after unary numeric promotion");
559      }
560    
561      // 15.25
562      public void ConditionalExpr.typeCheck() {
563        if(!getCondition().type().isBoolean())
564          error("The first operand of a conditional expression must be a boolean");
565        if(type().isUnknown() && !getTrueExpr().type().isUnknown() && !getFalseExpr().type().isUnknown()) {
566          error("The types of the second and third operand in this conditional expression do not match"); 
567        }
568      }
569    
570     public void IntegerLiteral.typeCheck() {
571       if(constant().error)
572         error("The value of an int literal must be a decimal value in the range -2147483648..2147483647 or a hexadecimal or octal literal that fits in 32 bits.");
573    
574     }
575     public void LongLiteral.typeCheck() {
576       if(constant().error)
577         error("The value of the long literal " + getLITERAL() + " is not legal");
578    
579     }
580    
581     public void FloatingPointLiteral.typeCheck() {
582       if(!isZero() && constant().floatValue() == 0.0f)
583         error("It is an error for nonzero floating-point " + getLITERAL() + " to round to zero");
584       if(constant().floatValue() == Float.NEGATIVE_INFINITY || constant().floatValue() == Float.POSITIVE_INFINITY)
585         error("It is an error for floating-point " + getLITERAL() + " to round to an infinity");
586         
587     }
588     public void DoubleLiteral.typeCheck() {
589       if(!isZero() && constant().doubleValue() == 0.0f)
590         error("It is an error for nonzero floating-point " + getLITERAL() + " to round to zero");
591       if(constant().doubleValue() == Double.NEGATIVE_INFINITY || constant().doubleValue() == Double.POSITIVE_INFINITY)
592         error("It is an error for floating-point " + getLITERAL() + " to round to an infinity");
593     }
594    }