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 ConstructorReference {
029      inh ConstructorDecl ConstructorReference.unknownConstructor();
030    
031      syn lazy ConstructorDecl ClassReference.targetConstructor(FunctionDescriptor f) =
032          syntheticInstanceExpr(f).decl();
033    
034      syn nta lazy ClassInstanceExpr ClassReference.syntheticInstanceExpr(FunctionDescriptor f) {
035        List<Expr> arguments = new List<Expr>();
036        for (int i = 0; i < f.method.getNumParameter(); i++) {
037          TypeDecl argumentType = f.method.getParameter(i).type();
038          arguments.add(new SyntheticTypeAccess(argumentType));
039        }
040    
041        ClassInstanceExpr instanceExpr = null;
042        if (hasTypeArgument()) {
043          instanceExpr = new ParConstructorReferenceAccess(
044              (Access) getTypeAccess().treeCopyNoTransform(), arguments,
045              new Opt(), (List<Access>)getTypeArgumentList().treeCopyNoTransform(), f);
046        } else {
047          // Must check for raw reference type, and in that case infer using diamond (JLS 15.13.1)
048          boolean checkDiamond = true;
049          if (getTypeAccess().type().hostType() != null && !getTypeAccess().type().isStatic()
050              && getTypeAccess().type().hostType().isRawType()) {
051            checkDiamond = false;
052          }
053          if (getTypeAccess().type().isRawType() && checkDiamond) {
054            DiamondAccess diamond = new DiamondAccess((Access)getTypeAccess().treeCopyNoTransform());
055            instanceExpr = new ConstructorReferenceAccess(diamond, arguments, f);
056          } else {
057            instanceExpr = new ConstructorReferenceAccess(
058                (Access) getTypeAccess().treeCopyNoTransform(), arguments, f);
059          }
060        }
061        return instanceExpr;
062      }
063    
064      // Both array and class references always refer to types
065      eq ClassReference.getTypeArgument().nameType() = NameType.TYPE_NAME;
066      eq ConstructorReference.getTypeAccess().nameType() = NameType.TYPE_NAME;
067    
068      syn lazy boolean ConstructorReference.congruentTo(FunctionDescriptor f);
069    
070      eq ClassReference.congruentTo(FunctionDescriptor f) {
071        ConstructorDecl decl = targetConstructor(f);
072        if (unknownConstructor() == decl) {
073          return false;
074        }
075        if (!f.method.type().isVoid()) {
076          TypeDecl returnType = syntheticInstanceExpr(f).type();
077          if (!returnType.assignConversionTo(f.method.type(), null)) {
078            return false;
079          }
080        }
081        return true;
082      }
083    
084      eq ArrayReference.congruentTo(FunctionDescriptor f) {
085        if (f.method.getNumParameter() != 1) {
086          return false;
087        }
088        if (!f.method.getParameter(0).type().assignConversionTo(f.fromInterface().typeInt(), null)) {
089          return false;
090        }
091        if (!f.method.type().isVoid()) {
092          if (!getTypeAccess().type().assignConversionTo(f.method.type(), null)) {
093            return false;
094          }
095        }
096        return true;
097      }
098    
099    
100      syn lazy ArrayList<ConstructorDecl> ClassReference.potentiallyApplicableConstructors(
101          FunctionDescriptor f) {
102        TypeDecl classType = syntheticInstanceExpr(f).type();
103        Collection<ConstructorDecl> col = classType.constructors();
104        ArrayList<ConstructorDecl> applicable = new ArrayList<ConstructorDecl>();
105        for (ConstructorDecl decl : col) {
106          if (!decl.accessibleFrom(hostType())) {
107            continue;
108          }
109          if (!(decl.arity() == f.method.arity())) {
110            continue;
111          }
112          if (hasTypeArgument()) {
113            if (!decl.isGeneric()) {
114              continue;
115            }
116            GenericConstructorDecl genDecl = decl.genericDecl();
117            if (!(getNumTypeArgument() == genDecl.getNumTypeParameter())) {
118              continue;
119            }
120          }
121          applicable.add(decl);
122        }
123        return applicable;
124      }
125    
126      // 15.13.1
127      syn lazy boolean ConstructorReference.isExact();
128    
129      syn lazy ConstructorDecl ClassReference.exactCompileTimeDeclaration() {
130        if (getTypeAccess().type().isRawType()) {
131          if (getTypeAccess().type().hostType() == null || getTypeAccess().type().isStatic()
132              || getTypeAccess().type().hostType().isRawType()) {
133            return unknownConstructor();
134          }
135        }
136        TypeDecl classType = getTypeAccess().type();
137        Collection<ConstructorDecl> col = classType.constructors();
138        ArrayList<ConstructorDecl> applicable = new ArrayList<ConstructorDecl>();
139        int foundCompatible = 0;
140        ConstructorDecl latestDecl = null;
141    
142        for (ConstructorDecl decl : col) {
143          if (decl.accessibleFrom(hostType())) {
144            foundCompatible++;
145            latestDecl = decl;
146          }
147        }
148        if (foundCompatible != 1) {
149          return unknownConstructor();
150        }
151        if (latestDecl.isVariableArity()) {
152          return unknownConstructor();
153        }
154        if (latestDecl.isGeneric()) {
155          GenericConstructorDecl genericDecl = latestDecl.genericDecl();
156          if (getNumTypeArgument() == genericDecl.getNumTypeParameter()) {
157            return latestDecl;
158          } else {
159            return unknownConstructor();
160          }
161        }
162        return latestDecl;
163      }
164    
165      eq ClassReference.isExact() = exactCompileTimeDeclaration() != unknownConstructor();
166    
167      eq ArrayReference.isExact() = true;
168    }