diff --git a/plugins/org.eclipse.n4js/src/org/eclipse/n4js/typesbuilder/N4JSMethodTypesBuilder.java b/plugins/org.eclipse.n4js/src/org/eclipse/n4js/typesbuilder/N4JSMethodTypesBuilder.java new file mode 100644 index 0000000000..78e40e301c --- /dev/null +++ b/plugins/org.eclipse.n4js/src/org/eclipse/n4js/typesbuilder/N4JSMethodTypesBuilder.java @@ -0,0 +1,173 @@ +/** + * Copyright (c) 2016 NumberFour AG. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * NumberFour AG - Initial API and implementation + */ +package org.eclipse.n4js.typesbuilder; + +import static org.eclipse.xtext.xbase.lib.IteratorExtensions.exists; + +import org.eclipse.emf.ecore.EObject; +import org.eclipse.n4js.AnnotationDefinition; +import org.eclipse.n4js.n4JS.Block; +import org.eclipse.n4js.n4JS.FunctionDeclaration; +import org.eclipse.n4js.n4JS.FunctionDefinition; +import org.eclipse.n4js.n4JS.N4JSPackage; +import org.eclipse.n4js.n4JS.N4MethodDeclaration; +import org.eclipse.n4js.n4JS.SuperLiteral; +import org.eclipse.n4js.n4JS.ThisLiteral; +import org.eclipse.n4js.scoping.builtin.BuiltInTypeScope; +import org.eclipse.n4js.ts.typeRefs.ThisTypeRef; +import org.eclipse.n4js.ts.types.AbstractNamespace; +import org.eclipse.n4js.ts.types.TClassifier; +import org.eclipse.n4js.ts.types.TMethod; +import org.eclipse.n4js.ts.types.TypesFactory; +import org.eclipse.n4js.types.utils.TypeUtils; +import org.eclipse.n4js.utils.EcoreUtilN4; +import org.eclipse.n4js.utils.N4JSLanguageUtils; + +import com.google.inject.Inject; +import com.google.inject.Singleton; + +@Singleton +class N4JSMethodTypesBuilder extends AbstractFunctionDefinitionTypesBuilder { + + @Inject + N4JSTypeVariableTypesBuilder _n4JSTypeVariableTypesBuilder; + @Inject + N4JSVariableStatementTypesBuilder _n4JSVariableStatementTypesBuilder; + @Inject + N4JSTypesBuilderHelper _n4JSTypesBuilderHelper; + + boolean canCreate(N4MethodDeclaration methodDecl) { + EObject methodDefinedType = (EObject) methodDecl.eGet( + N4JSPackage.eINSTANCE.getTypeDefiningElement_DefinedType(), + false); + if (methodDefinedType != null && !methodDefinedType.eIsProxy()) { + throw new IllegalStateException("TMethod already created for N4MethodDeclaration"); + } + if (methodDecl.getName() == null && !methodDecl.hasComputedPropertyName() && !methodDecl.isCallSignature()) { + return false; + } + return true; + } + + boolean relinkMethod(N4MethodDeclaration methodDecl, TClassifier classifier, boolean preLinkingPhase, int idx) { + if (!canCreate(methodDecl)) { + return false; + } + return relinkMethod(methodDecl, (TMethod) classifier.getOwnedMembers().get(idx), preLinkingPhase); + } + + boolean relinkMethod(N4MethodDeclaration methodDecl, TMethod tMethod, boolean preLinkingPhase) { + TMethod methodType = tMethod; + _n4JSTypesBuilderHelper.ensureEqualName(methodDecl, methodType); + + relinkFormalParameters(methodType, methodDecl, preLinkingPhase); + + // link + methodType.setAstElement(methodDecl); + methodDecl.setDefinedType(methodType); + + return true; + } + + /** + * Creates TMethod for the given method declaration (and links it to that method). + * + * @param methodDecl + * declaration for which the TMethod is created, must not be linked to a TMethod yet (i.e. its defined + * type must be null). + */ + TMethod createMethod(N4MethodDeclaration methodDecl, AbstractNamespace target, boolean preLinkingPhase) { + if (!canCreate(methodDecl)) { + return null; + } + TMethod methodType = TypesFactory.eINSTANCE.createTMethod(); + if (methodDecl.isCallSignature()) { + methodType.setName(N4JSLanguageUtils.CALL_SIGNATURE_NAME); + } else { + _n4JSTypesBuilderHelper.setMemberName(methodType, methodDecl); + } + methodType.setDeclaredAbstract(methodDecl.isAbstract()); + methodType.setDeclaredStatic(methodDecl.isDeclaredStatic()); + methodType.setDeclaredFinal(methodDecl.isDeclaredFinal()); + methodType.setDeclaredOverride(AnnotationDefinition.OVERRIDE.hasAnnotation(methodDecl)); + methodType.setConstructor(methodDecl.isConstructor()); + methodType.setDeclaredAsync(methodDecl.isAsync()); + methodType.setDeclaredGenerator(methodDecl.isGenerator()); + + boolean providesDefaultImpl = AnnotationDefinition.PROVIDES_DEFAULT_IMPLEMENTATION.hasAnnotation(methodDecl); + methodType.setHasNoBody(methodDecl.getBody() == null && !providesDefaultImpl); + + methodType.setLacksThisOrSuperUsage( + hasNonNullBody(methodDecl.getBody()) && !containsThisOrSuperUsage(methodDecl.getBody())); + + BuiltInTypeScope builtInTypeScope = BuiltInTypeScope.get(methodDecl.eResource().getResourceSet()); + _n4JSVariableStatementTypesBuilder.createImplicitArgumentsVariable(methodDecl, target, builtInTypeScope, + preLinkingPhase); + + setMemberAccessModifier(methodType, methodDecl); + _n4JSTypeVariableTypesBuilder.addTypeParameters(methodType, methodDecl, preLinkingPhase); + addFormalParameters(methodType, methodDecl, builtInTypeScope, preLinkingPhase); + setReturnTypeConsideringThis(methodType, methodDecl, builtInTypeScope, preLinkingPhase); + _n4JSTypesBuilderHelper.setDeclaredThisTypeFromAnnotation(methodType, methodDecl, preLinkingPhase); + + _n4JSTypesBuilderHelper.copyAnnotations(methodType, methodDecl, preLinkingPhase); + + // link + methodType.setAstElement(methodDecl); + methodDecl.setDefinedType(methodType); + + return methodType; + } + + private void setMemberAccessModifier(TMethod methodType, N4MethodDeclaration n4Method) { + _n4JSTypesBuilderHelper.setMemberAccessModifier( + modifier -> methodType.setDeclaredMemberAccessModifier(modifier), + n4Method.getDeclaredModifiers(), n4Method.getAnnotations()); + } + + /** + * Sets the return type. If the declared return type is 'this', a ComputedTypeRef will be created to generate a + * bound this type. + */ + private void setReturnTypeConsideringThis(TMethod methodType, N4MethodDeclaration methodDecl, + BuiltInTypeScope builtInTypeScope, boolean preLinkingPhase) { + if (methodDecl.isConstructor() || methodDecl.getDeclaredReturnTypeRefInAST() instanceof ThisTypeRef) { + // special case: TypeDeferredProcessor will create a BoundThisTypeRef via Xsemantics judgment 'thisTypeRef' + methodType.setReturnTypeRef(TypeUtils.createDeferredTypeRef()); + } else { + // standard case + setReturnType(methodType, methodDecl, builtInTypeScope, preLinkingPhase); + } + } + + private boolean hasNonNullBody(Block body) { + return (null != body) && (null != body.getAllStatements()); + } + + /** + * Checks for the presence of 'this' or 'super' usages in the given body, also including sub-expressions (eg, 'if + * (sub-expr)'), without delving inside function definitions or declarations. + *
+ * Static methods refer to static members via ThisLiteral. + */ + private boolean containsThisOrSuperUsage(Block body) { + return exists(body.getAllStatements(), stmt -> isThisOrSuperUsage(stmt) || + exists(EcoreUtilN4.getAllContentsFiltered(stmt, s -> !isFnDefOrDecl(s)), s -> isThisOrSuperUsage(s))); + } + + private boolean isFnDefOrDecl(EObject ast) { + return ast instanceof FunctionDeclaration || ast instanceof FunctionDefinition; + } + + private boolean isThisOrSuperUsage(EObject expr) { + return expr instanceof SuperLiteral || expr instanceof ThisLiteral; + } +} diff --git a/plugins/org.eclipse.n4js/src/org/eclipse/n4js/typesbuilder/N4JSMethodTypesBuilder.xtend b/plugins/org.eclipse.n4js/src/org/eclipse/n4js/typesbuilder/N4JSMethodTypesBuilder.xtend deleted file mode 100644 index 46eead69b1..0000000000 --- a/plugins/org.eclipse.n4js/src/org/eclipse/n4js/typesbuilder/N4JSMethodTypesBuilder.xtend +++ /dev/null @@ -1,166 +0,0 @@ -/** - * Copyright (c) 2016 NumberFour AG. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * NumberFour AG - Initial API and implementation - */ -package org.eclipse.n4js.typesbuilder - -import com.google.inject.Inject -import com.google.inject.Singleton -import org.eclipse.emf.ecore.EObject -import org.eclipse.n4js.AnnotationDefinition -import org.eclipse.n4js.n4JS.Block -import org.eclipse.n4js.n4JS.FunctionDeclaration -import org.eclipse.n4js.n4JS.FunctionDefinition -import org.eclipse.n4js.n4JS.N4JSPackage -import org.eclipse.n4js.n4JS.N4MethodDeclaration -import org.eclipse.n4js.n4JS.SuperLiteral -import org.eclipse.n4js.n4JS.ThisLiteral -import org.eclipse.n4js.scoping.builtin.BuiltInTypeScope -import org.eclipse.n4js.ts.typeRefs.ThisTypeRef -import org.eclipse.n4js.ts.types.AbstractNamespace -import org.eclipse.n4js.ts.types.MemberAccessModifier -import org.eclipse.n4js.ts.types.TClassifier -import org.eclipse.n4js.ts.types.TMethod -import org.eclipse.n4js.ts.types.TypesFactory -import org.eclipse.n4js.types.utils.TypeUtils -import org.eclipse.n4js.utils.EcoreUtilN4 -import org.eclipse.n4js.utils.N4JSLanguageUtils - -@Singleton -package class N4JSMethodTypesBuilder extends AbstractFunctionDefinitionTypesBuilder { - - @Inject extension N4JSTypeVariableTypesBuilder - @Inject extension N4JSVariableStatementTypesBuilder - @Inject extension N4JSTypesBuilderHelper - - def boolean canCreate(N4MethodDeclaration methodDecl) { - val methodDefinedType = methodDecl.eGet(N4JSPackage.eINSTANCE.typeDefiningElement_DefinedType, false) as EObject; - if (methodDefinedType !== null && !methodDefinedType.eIsProxy) { - throw new IllegalStateException("TMethod already created for N4MethodDeclaration"); - } - if (methodDecl.name === null && !methodDecl.hasComputedPropertyName && !methodDecl.callSignature) { - return false; - } - return true; - } - - def package boolean relinkMethod(N4MethodDeclaration methodDecl, TClassifier classifier, boolean preLinkingPhase, int idx) { - if (!canCreate(methodDecl)) { - return false; - } - relinkMethod(methodDecl, classifier.ownedMembers.get(idx) as TMethod, preLinkingPhase); - } - - def package boolean relinkMethod(N4MethodDeclaration methodDecl, TMethod tMethod, boolean preLinkingPhase) { - val methodType = tMethod; - ensureEqualName(methodDecl, methodType); - - methodType.relinkFormalParameters(methodDecl, preLinkingPhase) - - // link - methodType.astElement = methodDecl - methodDecl.definedType = methodType - - return true; - } - - /** - * Creates TMethod for the given method declaration (and links it to that method). - * - * @param methodDecl declaration for which the TMethod is created, must not be linked to a TMethod yet (i.e. its defined type must be null). - * @param preLinkingPhase - */ - def package TMethod createMethod(N4MethodDeclaration methodDecl, AbstractNamespace target, boolean preLinkingPhase) { - if (!canCreate(methodDecl)) { - return null; - } - val methodType = TypesFactory::eINSTANCE.createTMethod(); - if (methodDecl.isCallSignature) { - methodType.name = N4JSLanguageUtils.CALL_SIGNATURE_NAME; - } else { - methodType.setMemberName(methodDecl); - } - methodType.declaredAbstract = methodDecl.abstract - methodType.declaredStatic = methodDecl.declaredStatic - methodType.declaredFinal = methodDecl.declaredFinal - methodType.declaredOverride = AnnotationDefinition.OVERRIDE.hasAnnotation(methodDecl); - methodType.constructor = methodDecl.constructor - methodType.declaredAsync = methodDecl.async - methodType.declaredGenerator = methodDecl.generator - - val providesDefaultImpl = AnnotationDefinition.PROVIDES_DEFAULT_IMPLEMENTATION.hasAnnotation(methodDecl); - methodType.hasNoBody = methodDecl.body===null && !providesDefaultImpl; - - methodType.lacksThisOrSuperUsage = hasNonNullBody(methodDecl.body) && !containsThisOrSuperUsage(methodDecl.body) - - val builtInTypeScope = BuiltInTypeScope.get(methodDecl.eResource.resourceSet) - methodDecl.createImplicitArgumentsVariable(target, builtInTypeScope, preLinkingPhase); - - methodType.setMemberAccessModifier(methodDecl) - methodType.addTypeParameters(methodDecl, preLinkingPhase) - methodType.addFormalParameters(methodDecl, builtInTypeScope, preLinkingPhase) - methodType.setReturnTypeConsideringThis(methodDecl, builtInTypeScope, preLinkingPhase) - methodType.setDeclaredThisTypeFromAnnotation(methodDecl, preLinkingPhase) - - methodType.copyAnnotations(methodDecl, preLinkingPhase) - - // link - methodType.astElement = methodDecl - methodDecl.definedType = methodType - - return methodType; - } - - def private void setMemberAccessModifier(TMethod methodType, N4MethodDeclaration n4Method) { - setMemberAccessModifier([MemberAccessModifier modifier|methodType.declaredMemberAccessModifier = modifier], - n4Method.declaredModifiers, n4Method.annotations) - } - - /** - * Sets the return type. If the declared return type is 'this', a ComputedTypeRef will - * be created to generate a bound this type. - */ - def private void setReturnTypeConsideringThis(TMethod methodType, N4MethodDeclaration methodDecl, - BuiltInTypeScope builtInTypeScope, boolean preLinkingPhase) { - if (methodDecl.isConstructor || methodDecl.declaredReturnTypeRefInAST instanceof ThisTypeRef) { - // special case: TypeDeferredProcessor will create a BoundThisTypeRef via Xsemantics judgment 'thisTypeRef' - methodType.returnTypeRef = TypeUtils.createDeferredTypeRef - } else { - // standard case - methodType.setReturnType(methodDecl, builtInTypeScope, preLinkingPhase) - } - } - - private def boolean hasNonNullBody(Block body) { - (null !== body) && - (null !== body.allStatements) - } - - /** - * Checks for the presence of 'this' or 'super' usages in the given body, - * also including sub-expressions (eg, 'if (sub-expr)'), - * without delving inside function definitions or declarations. - *
- * Static methods refer to static members via ThisLiteral. - */ - private def boolean containsThisOrSuperUsage(Block body) { - body.allStatements.exists[ stmt | - isThisOrSuperUsage(stmt) || - EcoreUtilN4.getAllContentsFiltered(stmt, [!isFnDefOrDecl(it)]).exists[isThisOrSuperUsage(it)]; - ] - } - - private def boolean isFnDefOrDecl(EObject ast) { - ast instanceof FunctionDeclaration || ast instanceof FunctionDefinition - } - - private def boolean isThisOrSuperUsage(EObject expr) { - expr instanceof SuperLiteral || expr instanceof ThisLiteral - } -} diff --git a/plugins/org.eclipse.n4js/src/org/eclipse/n4js/typesbuilder/N4JSObjectLiteralTypesBuilder.java b/plugins/org.eclipse.n4js/src/org/eclipse/n4js/typesbuilder/N4JSObjectLiteralTypesBuilder.java new file mode 100644 index 0000000000..36e7349342 --- /dev/null +++ b/plugins/org.eclipse.n4js/src/org/eclipse/n4js/typesbuilder/N4JSObjectLiteralTypesBuilder.java @@ -0,0 +1,206 @@ +/** + * Copyright (c) 2016 NumberFour AG. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * NumberFour AG - Initial API and implementation + */ +package org.eclipse.n4js.typesbuilder; + +import static org.eclipse.xtext.xbase.lib.IterableExtensions.map; +import static org.eclipse.xtext.xbase.lib.IterableExtensions.toList; + +import java.util.Arrays; + +import org.eclipse.n4js.n4JS.ObjectLiteral; +import org.eclipse.n4js.n4JS.PropertyAssignment; +import org.eclipse.n4js.n4JS.PropertyGetterDeclaration; +import org.eclipse.n4js.n4JS.PropertyMethodDeclaration; +import org.eclipse.n4js.n4JS.PropertyNameValuePair; +import org.eclipse.n4js.n4JS.PropertySetterDeclaration; +import org.eclipse.n4js.scoping.builtin.BuiltInTypeScope; +import org.eclipse.n4js.ts.typeRefs.TypeRef; +import org.eclipse.n4js.ts.types.AbstractNamespace; +import org.eclipse.n4js.ts.types.TFormalParameter; +import org.eclipse.n4js.ts.types.TStructField; +import org.eclipse.n4js.ts.types.TStructGetter; +import org.eclipse.n4js.ts.types.TStructMember; +import org.eclipse.n4js.ts.types.TStructMethod; +import org.eclipse.n4js.ts.types.TStructSetter; +import org.eclipse.n4js.ts.types.TStructuralType; +import org.eclipse.n4js.ts.types.TypesFactory; +import org.eclipse.n4js.types.utils.TypeUtils; + +import com.google.inject.Inject; + +/** + */ +public class N4JSObjectLiteralTypesBuilder { + + @Inject + N4JSTypesBuilderHelper _n4JSTypesBuilderHelper; + @Inject + N4JSFormalParameterTypesBuilder _n4JSFormalParameterTypesBuilder; + + void createObjectLiteral(ObjectLiteral objectLiteral, AbstractNamespace target, boolean preLinkingPhase) { + BuiltInTypeScope builtInTypeScope = BuiltInTypeScope.get(objectLiteral.eResource().getResourceSet()); + TStructuralType structType = TypesFactory.eINSTANCE.createTStructuralType(); + + for (PropertyAssignment it : objectLiteral.getPropertyAssignments()) { + if (it.getName() != null || it.hasComputedPropertyName()) { + TStructMember typeModelElement = createTypeModelElement(it, builtInTypeScope, preLinkingPhase); + if (typeModelElement != null) { + typeModelElement.setAstElement(it); + structType.getOwnedMembers().add(typeModelElement); + } + } + } + + structType.setAstElement(objectLiteral); + objectLiteral.setDefinedType(structType); + + target.getContainingModule().getInternalTypes().add(structType); + } + + // TODO GH-1337 add support for spread operator + private TStructMember createTypeModelElement( + PropertyAssignment getterDecl, BuiltInTypeScope builtInTypeScope, boolean preLinkingPhase) { + + if (getterDecl instanceof PropertyGetterDeclaration) { + return createTypeModelElement((PropertyGetterDeclaration) getterDecl, + builtInTypeScope, preLinkingPhase); + } else if (getterDecl instanceof PropertyMethodDeclaration) { + return createTypeModelElement((PropertyMethodDeclaration) getterDecl, + builtInTypeScope, preLinkingPhase); + } else if (getterDecl instanceof PropertyNameValuePair) { + return createTypeModelElement((PropertyNameValuePair) getterDecl, + builtInTypeScope, preLinkingPhase); + } else if (getterDecl instanceof PropertySetterDeclaration) { + return createTypeModelElement((PropertySetterDeclaration) getterDecl, + builtInTypeScope, preLinkingPhase); + } else if (getterDecl != null) { + return null; + } else { + throw new IllegalArgumentException("Unhandled parameter types: " + + Arrays.asList(getterDecl, builtInTypeScope, preLinkingPhase).toString()); + } + } + + /** + * Creates a TStructField. + */ + private TStructField createTypeModelElement( + PropertyNameValuePair nameValuePair, BuiltInTypeScope builtInTypeScope, boolean preLinkingPhase) { + TStructField field = TypesFactory.eINSTANCE.createTStructField(); + _n4JSTypesBuilderHelper.setMemberName(field, nameValuePair); + field.setOptional(nameValuePair.isDeclaredOptional()); + if (nameValuePair.getDeclaredTypeRefInAST() != null) { + if (!preLinkingPhase) { + field.setTypeRef(TypeUtils.copyWithProxies(nameValuePair.getDeclaredTypeRefInAST())); + } + } else if (nameValuePair.getExpression() != null) { + field.setTypeRef(TypeUtils.createDeferredTypeRef()); + } else { + // FIXME inconsistent with getter/setter case; should use DeferredTypeRef also if expression===null + field.setTypeRef(builtInTypeScope.getAnyTypeRef()); + } + // else { + // // in all other cases: + // // leave it to the corresponding xsemantics rule to infer the type (e.g. from the initializer expression, if + // given) + // if(!preLinkingPhase) { + // field.typeRef = + // TypeUtils.createComputedTypeRef([resolveAllComputedTypeRefsInTStructuralType(structType,objectLiteral,builtInTypeScope)]) + // } + // } + field.setAstElement(nameValuePair); + nameValuePair.setDefinedField(field); + return field; + } + + /** + * Creates a TStructGetter. + */ + private TStructGetter createTypeModelElement(PropertyGetterDeclaration getterDecl, + @SuppressWarnings("unused") BuiltInTypeScope builtInTypeScope, boolean preLinkingPhase) { + + TStructGetter getter = TypesFactory.eINSTANCE.createTStructGetter(); + _n4JSTypesBuilderHelper.setMemberName(getter, getterDecl); + getter.setOptional(getterDecl.isDeclaredOptional()); + if (getterDecl.getDeclaredTypeRefInAST() != null) { + if (!preLinkingPhase) { + getter.setTypeRef(TypeUtils.copyWithProxies(getterDecl.getDeclaredTypeRefInAST())); + } + } else { + getter.setTypeRef(TypeUtils.createDeferredTypeRef()); + } + getter.setAstElement(getterDecl); + getterDecl.setDefinedGetter(getter); + return getter; + } + + /** + * Creates a TStructSetter. + */ + private TStructSetter createTypeModelElement(PropertySetterDeclaration setterDecl, + @SuppressWarnings("unused") BuiltInTypeScope builtInTypeScope, boolean preLinkingPhase) { + + TStructSetter setter = TypesFactory.eINSTANCE.createTStructSetter(); + _n4JSTypesBuilderHelper.setMemberName(setter, setterDecl); + setter.setOptional(setterDecl.isDeclaredOptional()); + // IMPORTANT: do not create the formal parameter with N4JSFormalParameterTypesBuilder#createFormalParameter() + // because we here use improved type inference (the type of a getter/setter in an object literal is inferred + // similarly to that of a name/value pair) + TFormalParameter param = TypesFactory.eINSTANCE.createTFormalParameter(); + if (setterDecl.getFpar() != null) { + param.setName(setterDecl.getFpar().getName()); + TypeRef fparDeclTypeRef = setterDecl.getFpar().getDeclaredTypeRefInAST(); + if (fparDeclTypeRef != null) { + if (!preLinkingPhase) { + param.setTypeRef(TypeUtils.copyWithProxies(fparDeclTypeRef)); + } + } else { + param.setTypeRef(TypeUtils.createDeferredTypeRef()); + } + param.setAstElement(setterDecl.getFpar()); + setterDecl.getFpar().setDefinedVariable(param); + } else { + // broken AST + param.setTypeRef(TypeUtils.createDeferredTypeRef()); + // (note: using UnknownTypeRef would make more sense, but PolyComputer expects this, because + // setterDecl.declaredTypeRef===setterDecl?.fpar.declaredTypeRef===null, so setterDecl will be poly) + } + setter.setFpar(param); + setter.setAstElement(setterDecl); + setterDecl.setDefinedSetter(setter); + return setter; + } + + /** + * Creates a TStructMethod. + */ + private TStructMethod createTypeModelElement( + PropertyMethodDeclaration methodDecl, BuiltInTypeScope builtInTypeScope, boolean preLinkingPhase) { + + TStructMethod result = TypesFactory.eINSTANCE.createTStructMethod(); + _n4JSTypesBuilderHelper.setMemberName(result, methodDecl); + // IMPORTANT: do not create the formal parameters as above for the property setters but instead create them with + // method N4JSFormalParameterTypesBuilder#createFormalParameter() (for consistency with methods in classes) + result.getFpars().addAll( + toList(map(methodDecl.getFpars(), fp -> _n4JSFormalParameterTypesBuilder.createFormalParameter(fp, + builtInTypeScope, preLinkingPhase)))); + if (methodDecl.getDeclaredReturnTypeRefInAST() != null) { + if (!preLinkingPhase) { + result.setReturnTypeRef(TypeUtils.copyWithProxies(methodDecl.getDeclaredReturnTypeRefInAST())); + } + } else { + result.setReturnTypeRef(builtInTypeScope.getVoidTypeRef()); + } + result.setAstElement(methodDecl); + methodDecl.setDefinedType(result); + return result; + } +} diff --git a/plugins/org.eclipse.n4js/src/org/eclipse/n4js/typesbuilder/N4JSObjectLiteralTypesBuilder.xtend b/plugins/org.eclipse.n4js/src/org/eclipse/n4js/typesbuilder/N4JSObjectLiteralTypesBuilder.xtend deleted file mode 100644 index dc61e8a117..0000000000 --- a/plugins/org.eclipse.n4js/src/org/eclipse/n4js/typesbuilder/N4JSObjectLiteralTypesBuilder.xtend +++ /dev/null @@ -1,164 +0,0 @@ -/** - * Copyright (c) 2016 NumberFour AG. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * NumberFour AG - Initial API and implementation - */ -package org.eclipse.n4js.typesbuilder; - -import com.google.inject.Inject -import org.eclipse.n4js.n4JS.ObjectLiteral -import org.eclipse.n4js.n4JS.PropertyAssignment -import org.eclipse.n4js.n4JS.PropertyGetterDeclaration -import org.eclipse.n4js.n4JS.PropertyMethodDeclaration -import org.eclipse.n4js.n4JS.PropertyNameValuePair -import org.eclipse.n4js.n4JS.PropertySetterDeclaration -import org.eclipse.n4js.scoping.builtin.BuiltInTypeScope -import org.eclipse.n4js.ts.types.AbstractNamespace -import org.eclipse.n4js.ts.types.TStructField -import org.eclipse.n4js.ts.types.TStructGetter -import org.eclipse.n4js.ts.types.TStructMember -import org.eclipse.n4js.ts.types.TStructMethod -import org.eclipse.n4js.ts.types.TStructSetter -import org.eclipse.n4js.ts.types.TStructuralType -import org.eclipse.n4js.ts.types.TypesFactory -import org.eclipse.n4js.types.utils.TypeUtils - -/** - */ -public class N4JSObjectLiteralTypesBuilder { - - @Inject extension N4JSTypesBuilderHelper - @Inject extension N4JSFormalParameterTypesBuilder - - - def package void createObjectLiteral(ObjectLiteral objectLiteral, AbstractNamespace target, boolean preLinkingPhase) { - val builtInTypeScope = BuiltInTypeScope.get(objectLiteral.eResource.resourceSet) - val TStructuralType structType = TypesFactory.eINSTANCE.createTStructuralType - objectLiteral.propertyAssignments.filter[name!==null || hasComputedPropertyName].forEach [ - val TStructMember typeModelElement = createTypeModelElement(structType, objectLiteral, it, builtInTypeScope, preLinkingPhase); - if(typeModelElement!==null) { - typeModelElement.astElement = it; - structType.ownedMembers += typeModelElement - } - ] - - structType.astElement = objectLiteral; - objectLiteral.definedType = structType; - - target.containingModule.internalTypes += structType - } - - // TODO GH-1337 add support for spread operator - private def dispatch TStructMember createTypeModelElement(TStructuralType structType, ObjectLiteral objectLiteral, PropertyAssignment assignment, BuiltInTypeScope builtInTypeScope, boolean preLinkingPhase) { - } - - /** - * Creates a TStructField. - */ - private def dispatch TStructField createTypeModelElement(TStructuralType structType, ObjectLiteral objectLiteral, PropertyNameValuePair nameValuePair, BuiltInTypeScope builtInTypeScope, boolean preLinkingPhase) { - val TStructField field = TypesFactory.eINSTANCE.createTStructField - field.setMemberName(nameValuePair); - field.optional = nameValuePair.declaredOptional; - if (nameValuePair.declaredTypeRefInAST !== null) { - if (!preLinkingPhase) { - field.typeRef = TypeUtils.copyWithProxies(nameValuePair.declaredTypeRefInAST) - } - } - else if(nameValuePair.expression !== null) { - field.typeRef = TypeUtils.createDeferredTypeRef; - } - else { - field.typeRef = builtInTypeScope.anyTypeRef; // FIXME inconsistent with getter/setter case; should use DeferredTypeRef also if expression===null - } -// else { -// // in all other cases: -// // leave it to the corresponding xsemantics rule to infer the type (e.g. from the initializer expression, if given) -// if(!preLinkingPhase) { -// field.typeRef = TypeUtils.createComputedTypeRef([resolveAllComputedTypeRefsInTStructuralType(structType,objectLiteral,builtInTypeScope)]) -// } -// } - field.astElement = nameValuePair; - nameValuePair.definedField = field; - return field - } - - /** - * Creates a TStructGetter. - */ - private def dispatch TStructGetter createTypeModelElement(TStructuralType structType, ObjectLiteral objectLiteral, PropertyGetterDeclaration getterDecl, BuiltInTypeScope builtInTypeScope, boolean preLinkingPhase) { - val TStructGetter getter = TypesFactory.eINSTANCE.createTStructGetter - getter.setMemberName(getterDecl); - getter.optional = getterDecl.declaredOptional; - if (getterDecl.declaredTypeRefInAST !== null) { - if (!preLinkingPhase) { - getter.typeRef = TypeUtils.copyWithProxies(getterDecl.declaredTypeRefInAST) - } - } else { - getter.typeRef = TypeUtils.createDeferredTypeRef; - } - getter.astElement = getterDecl; - getterDecl.definedGetter = getter; - return getter - } - - /** - * Creates a TStructSetter. - */ - private def dispatch TStructSetter createTypeModelElement(TStructuralType structType, ObjectLiteral objectLiteral, PropertySetterDeclaration setterDecl, BuiltInTypeScope builtInTypeScope, boolean preLinkingPhase) { - val TStructSetter setter = TypesFactory.eINSTANCE.createTStructSetter - setter.setMemberName(setterDecl); - setter.optional = setterDecl.declaredOptional; - // IMPORTANT: do not create the formal parameter with N4JSFormalParameterTypesBuilder#createFormalParameter() - // because we here use improved type inference (the type of a getter/setter in an object literal is inferred - // similarly to that of a name/value pair) - val param = TypesFactory.eINSTANCE.createTFormalParameter - if (setterDecl.fpar !== null) { - param.name = setterDecl.fpar.name - val fparDeclTypeRef = setterDecl.fpar.declaredTypeRefInAST; - if(fparDeclTypeRef!==null) { - if (!preLinkingPhase) { - param.typeRef = TypeUtils.copyWithProxies(fparDeclTypeRef); - } - } else { - param.typeRef = TypeUtils.createDeferredTypeRef; - } - param.astElement = setterDecl.fpar; - setterDecl.fpar.definedVariable = param; - } else { - // broken AST - param.typeRef = TypeUtils.createDeferredTypeRef; - // (note: using UnknownTypeRef would make more sense, but PolyComputer expects this, because - // setterDecl.declaredTypeRef===setterDecl?.fpar.declaredTypeRef===null, so setterDecl will be poly) - } - setter.fpar = param - setter.astElement = setterDecl; - setterDecl.definedSetter = setter; - return setter - } - - /** - * Creates a TStructMethod. - */ - private def dispatch TStructMethod createTypeModelElement(TStructuralType structType, ObjectLiteral objectLiteral, PropertyMethodDeclaration methodDecl, BuiltInTypeScope builtInTypeScope, boolean preLinkingPhase) { - val TStructMethod result = TypesFactory.eINSTANCE.createTStructMethod; - result.setMemberName(methodDecl); - // IMPORTANT: do not create the formal parameters as above for the property setters but instead create them with - // method N4JSFormalParameterTypesBuilder#createFormalParameter() (for consistency with methods in classes) - result.fpars += methodDecl.fpars.map[createFormalParameter(builtInTypeScope, preLinkingPhase)]; - if (methodDecl.declaredReturnTypeRefInAST !== null) { - if (!preLinkingPhase) { - result.returnTypeRef = TypeUtils.copyWithProxies(methodDecl.declaredReturnTypeRefInAST); - } - } else { - result.returnTypeRef = builtInTypeScope.voidTypeRef; - } - result.astElement = methodDecl; - methodDecl.definedType = result; - return result; - } -}