Make JetStream 2
[WebKit-https.git] / PerformanceTests / JetStream2 / WSL / NameResolver.js
1 /*
2  * Copyright (C) 2017 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25 "use strict";
26
27 // This only resolves names. After this phase runs, all names will be resolved. This means that all
28 // XYZRef objects now know who they resolve to. This does not yet allow type analysis, because there
29 // are still TypeDefs. This throws type errors for failed name resolutions and for things that are
30 // more convenient to check here than in the Checker. This usually involves things that need to be
31 // checked before TypeRefToTypeDefSkipper.
32 class NameResolver extends Visitor {
33     constructor(nameContext)
34     {
35         super();
36         this._nameContext = nameContext;
37     }
38
39     doStatement(statement)
40     {
41         this._nameContext.doStatement(statement, () => statement.visit(this));
42     }
43     
44     _visitTypeParametersAndBuildNameContext(node)
45     {
46         let nameContext = new NameContext(this._nameContext);
47         for (let typeParameter of node.typeParameters) {
48             nameContext.add(typeParameter);
49             typeParameter.visit(this);
50         }
51         return nameContext;
52     }
53     
54     visitFunc(node)
55     {
56         let checker = new NameResolver(this._visitTypeParametersAndBuildNameContext(node));
57         node.returnType.visit(checker);
58         for (let parameter of node.parameters)
59             parameter.visit(checker);
60     }
61     
62     visitFuncDef(node)
63     {
64         let contextWithTypeParameters = this._visitTypeParametersAndBuildNameContext(node);
65         let checkerWithTypeParameters = new NameResolver(contextWithTypeParameters);
66         node.returnType.visit(checkerWithTypeParameters);
67         let contextWithParameters = new NameContext(contextWithTypeParameters);
68         for (let parameter of node.parameters) {
69             parameter.visit(checkerWithTypeParameters);
70             contextWithParameters.add(parameter);
71         }
72         let checkerWithParameters = new NameResolver(contextWithParameters);
73         node.body.visit(checkerWithParameters);
74     }
75     
76     visitBlock(node)
77     {
78         let checker = new NameResolver(new NameContext(this._nameContext));
79         for (let statement of node.statements)
80             statement.visit(checker);
81     }
82
83     visitIfStatement(node)
84     {
85         node.conditional.visit(this);
86         // The bodies might not be Blocks, so we need to explicitly give them a new context.
87         node.body.visit(new NameResolver(new NameContext(this._nameContext)));
88         if (node.elseBody)
89             node.elseBody.visit(new NameResolver(new NameContext(this._nameContext)));
90     }
91
92     visitWhileLoop(node)
93     {
94         node.conditional.visit(this);
95         // The bodies might not be Blocks, so we need to explicitly give them a new context.
96         node.body.visit(new NameResolver(new NameContext(this._nameContext)));
97     }
98
99     visitDoWhileLoop(node)
100     {
101         // The bodies might not be Blocks, so we need to explicitly give them a new context.
102         node.body.visit(new NameResolver(new NameContext(this._nameContext)));
103         node.conditional.visit(this);
104     }
105
106     visitForLoop(node)
107     {
108         let newResolver = new NameResolver(new NameContext(this._nameContext))
109         if (node.initialization)
110             node.initialization.visit(newResolver);
111         if (node.condition)
112             node.condition.visit(newResolver);
113         if (node.increment)
114             node.increment.visit(newResolver);
115         node.body.visit(newResolver);
116     }
117     
118     visitProtocolDecl(node)
119     {
120         for (let parent of node.extends)
121             parent.visit(this);
122         let nameContext = new NameContext(this._nameContext);
123         nameContext.add(node.typeVariable);
124         let checker = new NameResolver(nameContext);
125         for (let signature of node.signatures)
126             signature.visit(checker);
127     }
128     
129     visitProtocolRef(node)
130     {
131         let result = this._nameContext.get(Protocol, node.name);
132         if (!result)
133             throw new WTypeError(node.origin.originString, "Could not find protocol named " + node.name);
134         node.protocolDecl = result;
135     }
136     
137     visitProtocolFuncDecl(node)
138     {
139         this.visitFunc(node);
140         let funcs = this._nameContext.get(Func, node.name);
141         if (!funcs)
142             throw new WTypeError(node.origin.originString, "Cannot find any functions named " + node.name);
143         node.possibleOverloads = funcs;
144     }
145     
146     visitTypeDef(node)
147     {
148         let nameContext = new NameContext(this._nameContext);
149         for (let typeParameter of node.typeParameters) {
150             typeParameter.visit(this);
151             nameContext.add(typeParameter);
152         }
153         let checker = new NameResolver(nameContext);
154         node.type.visit(checker);
155     }
156     
157     visitStructType(node)
158     {
159         let nameContext = new NameContext(this._nameContext);
160         for (let typeParameter of node.typeParameters) {
161             typeParameter.visit(this);
162             nameContext.add(typeParameter);
163         }
164         let checker = new NameResolver(nameContext);
165         for (let field of node.fields)
166             field.visit(checker);
167     }
168     
169     _resolveTypeArguments(typeArguments)
170     {
171         for (let i = 0; i < typeArguments.length; ++i) {
172             let typeArgument = typeArguments[i];
173             if (typeArgument instanceof TypeOrVariableRef) {
174                 let thing = this._nameContext.get(Anything, typeArgument.name);
175                 if (!thing)
176                     new WTypeError(typeArgument.origin.originString, "Could not find type or variable named " + typeArgument.name);
177                 if (thing instanceof Value)
178                     typeArguments[i] = new VariableRef(typeArgument.origin, typeArgument.name);
179                 else if (thing instanceof Type)
180                     typeArguments[i] = new TypeRef(typeArgument.origin, typeArgument.name, []);
181                 else
182                     throw new WTypeError(typeArgument.origin.originString, "Type argument resolved to wrong kind of thing: " + thing.kind);
183             }
184             
185             if (typeArgument[i] instanceof Value
186                 && !typeArgument[i].isConstexpr)
187                 throw new WTypeError(typeArgument[i].origin.originString, "Expected constexpr");
188         }
189     }
190     
191     visitTypeRef(node)
192     {
193         this._resolveTypeArguments(node.typeArguments);
194         
195         let type = node.type;
196         if (!type) {
197             type = this._nameContext.get(Type, node.name);
198             if (!type)
199                 throw new WTypeError(node.origin.originString, "Could not find type named " + node.name);
200             node.type = type;
201         }
202         
203         if (type.typeParameters.length != node.typeArguments.length)
204             throw new WTypeError(node.origin.originString, "Wrong number of type arguments (passed " + node.typeArguments.length + ", expected " + type.typeParameters.length + ")");
205         for (let i = 0; i < type.typeParameters.length; ++i) {
206             let parameterIsType = type.typeParameters[i] instanceof TypeVariable;
207             let argumentIsType = node.typeArguments[i] instanceof Type;
208             node.typeArguments[i].visit(this);
209             if (parameterIsType && !argumentIsType)
210                 throw new WTypeError(node.origin.originString, "Expected type, but got value at argument #" + i);
211             if (!parameterIsType && argumentIsType)
212                 throw new WTypeError(node.origin.originString, "Expected value, but got type at argument #" + i);
213         }
214     }
215     
216     visitReferenceType(node)
217     {
218         let nameContext = new NameContext(this._nameContext);
219         node.elementType.visit(new NameResolver(nameContext));
220     }
221     
222     visitVariableDecl(node)
223     {
224         this._nameContext.add(node);
225         node.type.visit(this);
226         if (node.initializer)
227             node.initializer.visit(this);
228     }
229
230     visitVariableRef(node)
231     {
232         if (node.variable)
233             return;
234         let result = this._nameContext.get(Value, node.name);
235         if (!result)
236             throw new WTypeError(node.origin.originString, "Could not find variable named " + node.name);
237         node.variable = result;
238     }
239     
240     visitReturn(node)
241     {
242         node.func = this._nameContext.currentStatement;
243         super.visitReturn(node);
244     }
245     
246     _handlePropertyAccess(node)
247     {
248         node.possibleGetOverloads = this._nameContext.get(Func, node.getFuncName);
249         node.possibleSetOverloads = this._nameContext.get(Func, node.setFuncName);
250         node.possibleAndOverloads = this._nameContext.get(Func, node.andFuncName);
251
252         if (!node.possibleGetOverloads && !node.possibleAndOverloads)
253             throw new WTypeError(node.origin.originString, "Cannot find either " + node.getFuncName + " or " + node.andFuncName);
254     }
255     
256     visitDotExpression(node)
257     {
258         // This could be a reference to an enum. Let's resolve that now.
259         if (node.struct instanceof VariableRef) {
260             let enumType = this._nameContext.get(Type, node.struct.name);
261             if (enumType && enumType instanceof EnumType) {
262                 let enumMember = enumType.memberByName(node.fieldName);
263                 if (!enumMember)
264                     throw new WTypeError(node.origin.originString, "Enum " + enumType.name + " does not have a member named " + node.fieldName);
265                 node.become(new EnumLiteral(node.origin, enumMember));
266                 return;
267             }
268         }
269         
270         this._handlePropertyAccess(node);
271         super.visitDotExpression(node);
272     }
273     
274     visitIndexExpression(node)
275     {
276         this._handlePropertyAccess(node);
277         super.visitIndexExpression(node);
278     }
279     
280     visitCallExpression(node)
281     {
282         this._resolveTypeArguments(node.typeArguments);
283         
284         let funcs = this._nameContext.get(Func, node.name);
285         if (funcs)
286             node.possibleOverloads = funcs;
287         else {
288             let type = this._nameContext.get(Type, node.name);
289             if (!type)
290                 throw new WTypeError(node.origin.originString, "Cannot find any function or type named \"" + node.name + "\"");
291             node.becomeCast(type);
292             node.possibleOverloads = this._nameContext.get(Func, "operator cast");
293             if (!node.possibleOverloads)
294                 throw new WTypeError(node.origin.originString, "Cannot find any operator cast implementations in cast to " + type);
295         }
296         
297         super.visitCallExpression(node);
298     }
299 }
300