From e2460ce92880e9a0d499a0434418dd73872b4c8e Mon Sep 17 00:00:00 2001 From: mmews Date: Thu, 11 Jul 2024 11:30:45 +0200 Subject: [PATCH] migrate --- .../typesystem/utils/ThisTypeComputer.java | 162 +++ .../typesystem/utils/ThisTypeComputer.xtend | 145 --- .../typesystem/utils/TypeSystemHelper.java | 1039 +++++++++++++++++ .../typesystem/utils/TypeSystemHelper.xtend | 820 ------------- 4 files changed, 1201 insertions(+), 965 deletions(-) create mode 100644 plugins/org.eclipse.n4js/src/org/eclipse/n4js/typesystem/utils/ThisTypeComputer.java delete mode 100644 plugins/org.eclipse.n4js/src/org/eclipse/n4js/typesystem/utils/ThisTypeComputer.xtend create mode 100644 plugins/org.eclipse.n4js/src/org/eclipse/n4js/typesystem/utils/TypeSystemHelper.java delete mode 100644 plugins/org.eclipse.n4js/src/org/eclipse/n4js/typesystem/utils/TypeSystemHelper.xtend diff --git a/plugins/org.eclipse.n4js/src/org/eclipse/n4js/typesystem/utils/ThisTypeComputer.java b/plugins/org.eclipse.n4js/src/org/eclipse/n4js/typesystem/utils/ThisTypeComputer.java new file mode 100644 index 0000000000..c74475e7b4 --- /dev/null +++ b/plugins/org.eclipse.n4js/src/org/eclipse/n4js/typesystem/utils/ThisTypeComputer.java @@ -0,0 +1,162 @@ +/** + * Copyright (c) 2018 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.typesystem.utils; + +import static org.eclipse.n4js.types.utils.TypeUtils.createClassifierBoundThisTypeRef; +import static org.eclipse.n4js.types.utils.TypeUtils.createTypeRef; +import static org.eclipse.n4js.types.utils.TypeUtils.createTypeRefWithParamsAsArgs; +import static org.eclipse.n4js.types.utils.TypeUtils.createTypeTypeRef; +import static org.eclipse.n4js.typesystem.utils.RuleEnvironmentExtensions.anyTypeRef; +import static org.eclipse.n4js.typesystem.utils.RuleEnvironmentExtensions.anyTypeRefDynamic; +import static org.eclipse.n4js.typesystem.utils.RuleEnvironmentExtensions.globalObjectTypeRef; +import static org.eclipse.n4js.typesystem.utils.RuleEnvironmentExtensions.isInBody_Of_StaticMethod; +import static org.eclipse.n4js.typesystem.utils.RuleEnvironmentExtensions.isInReturnDeclaration_Of_StaticMethod; + +import org.eclipse.emf.ecore.EObject; +import org.eclipse.n4js.n4JS.ArrowFunction; +import org.eclipse.n4js.n4JS.FunctionDefinition; +import org.eclipse.n4js.n4JS.FunctionOrFieldAccessor; +import org.eclipse.n4js.n4JS.N4ClassDeclaration; +import org.eclipse.n4js.n4JS.N4ClassifierDefinition; +import org.eclipse.n4js.n4JS.N4FieldDeclaration; +import org.eclipse.n4js.n4JS.N4GetterDeclaration; +import org.eclipse.n4js.n4JS.N4JSASTUtils; +import org.eclipse.n4js.n4JS.N4MemberDeclaration; +import org.eclipse.n4js.n4JS.N4MethodDeclaration; +import org.eclipse.n4js.n4JS.N4SetterDeclaration; +import org.eclipse.n4js.n4JS.ObjectLiteral; +import org.eclipse.n4js.n4JS.ThisTarget; +import org.eclipse.n4js.ts.typeRefs.ParameterizedTypeRef; +import org.eclipse.n4js.ts.typeRefs.TypeRef; +import org.eclipse.n4js.ts.typeRefs.TypeRefsFactory; +import org.eclipse.n4js.ts.types.IdentifiableElement; +import org.eclipse.n4js.ts.types.TClass; +import org.eclipse.n4js.ts.types.Type; +import org.eclipse.n4js.ts.types.TypingStrategy; +import org.eclipse.n4js.types.utils.TypeUtils; +import org.eclipse.n4js.typesystem.N4JSTypeSystem; +import org.eclipse.n4js.validation.JavaScriptVariantHelper; +import org.eclipse.xtext.EcoreUtil2; + +import com.google.inject.Inject; + +/** + * @see ThisTypeComputer#getThisTypeAtLocation(RuleEnvironment,EObject) + */ +class ThisTypeComputer extends TypeSystemHelperStrategy { + + @Inject + private N4JSTypeSystem ts; + @Inject + private JavaScriptVariantHelper jsVariantHelper; + + /** + * Computes the this type at the given location. Since ECMAScript does not support lexical this typing, this + * basically is a heuristic. + *

+ * This code was moved here from judgment thisTypeRef in file 'n4js.xsemantics'. + */ + TypeRef getThisTypeAtLocation(RuleEnvironment G, EObject location) { + if (location instanceof ParameterizedTypeRef) { + return TypeUtils.createBoundThisTypeRef((ParameterizedTypeRef) location); + } + + FunctionOrFieldAccessor containingFunctionOrAccessor = N4JSASTUtils.getContainingFunctionOrAccessor(location); + if (containingFunctionOrAccessor instanceof ArrowFunction) { + return getThisTypeAtLocation(G, containingFunctionOrAccessor); + } + + // searching for declaredTypeRefs introduced through @This + IdentifiableElement containingTFunctionOrAccessor = null; + if (containingFunctionOrAccessor != null) { + containingFunctionOrAccessor.getDefinedFunctionOrAccessor(); + } + TypeRef declaredThisTypeRef = TypeSystemHelper.getDeclaredThisType(containingTFunctionOrAccessor); + if (declaredThisTypeRef != null) { + if (declaredThisTypeRef instanceof ParameterizedTypeRef) { + return getThisTypeAtLocation(G, declaredThisTypeRef); + } + return declaredThisTypeRef; + } + + ThisTarget thisTarget = N4JSASTUtils.getProbableThisTarget(location); + if (thisTarget instanceof ObjectLiteral) { + // call rule, type may be created on the fly + return ts.type(G, (ObjectLiteral) thisTarget); + } else if (thisTarget instanceof N4ClassifierDefinition) { + Type thisTargetDefType = ((N4ClassifierDefinition) thisTarget).getDefinedType(); + + // In case of static polyfill (filler), replace defined type with filled type: + if (thisTarget instanceof N4ClassDeclaration) { + TClass clazz = ((N4ClassDeclaration) thisTarget).getDefinedTypeAsClass(); + if (clazz != null && clazz.isStaticPolyfill() && clazz.getSuperClassRef() != null) { + Type actualClazz = clazz.getSuperClassRef().getDeclaredType(); + if (actualClazz != null) { + thisTargetDefType = actualClazz; + } + } + } + + if (thisTargetDefType != null) { + FunctionDefinition containingFunction = N4JSASTUtils.getContainingFunction(location); + if (containingFunction instanceof N4MethodDeclaration && + ((N4MemberDeclaration) containingFunction).isStatic()) { + if (isInReturnDeclaration_Of_StaticMethod(location, (N4MethodDeclaration) containingFunction)) { + return getThisTypeAtLocation(G, createTypeRef(thisTargetDefType, TypingStrategy.DEFAULT, true)); + } else if (isInBody_Of_StaticMethod(location, (N4MethodDeclaration) containingFunction)) { + ParameterizedTypeRef ttRef = createTypeRefWithParamsAsArgs(thisTargetDefType); + if (thisTargetDefType instanceof TClass) { + ParameterizedTypeRef classTypeRef = ttRef; // if (thisTargetDefType.final) ttRef else + // createWildcardExtends(ttRef); + return createTypeTypeRef(TypeUtils.createBoundThisTypeRef(classTypeRef), true); + } else { + return createClassifierBoundThisTypeRef(TypeUtils.createTypeTypeRef(ttRef, false)); + } + } else { + return TypeUtils.createConstructorTypeRef(thisTargetDefType); + } + } else { + N4FieldDeclaration n4Field = EcoreUtil2.getContainerOfType(location, N4FieldDeclaration.class); + if (n4Field != null && n4Field.isStatic()) { + // this case has been disallowed as of GHOLD-263 + return TypeRefsFactory.eINSTANCE.createUnknownTypeRef(); + // old: + // return TypeUtils.createConstructorTypeRef(thisTargetDEFTYPE); + } else { + N4GetterDeclaration n4Getter = EcoreUtil2.getContainerOfType(location, + N4GetterDeclaration.class); + if (n4Getter != null && n4Getter.isStatic()) { + return TypeUtils.createConstructorTypeRef(thisTargetDefType); + } else { + N4SetterDeclaration n4Setter = EcoreUtil2.getContainerOfType(location, + N4SetterDeclaration.class); + if (n4Setter != null && n4Setter.isStatic()) { + return TypeUtils.createConstructorTypeRef(thisTargetDefType); + } else { + return getThisTypeAtLocation(G, createTypeRefWithParamsAsArgs(thisTargetDefType)); + } + } + } + } + } else { + return anyTypeRefDynamic(G); + } + } else { + // if (unrestricted.isActive(location)) { + if (jsVariantHelper.hasGlobalObject(location)) { + return globalObjectTypeRef(G); + } + // note: it is possible to pass in a primitive as "thisArg"; therefore, 'this' in functions must + // actually be inferred to 'any', by default, not to 'Object': + return anyTypeRef(G); + } + } +} diff --git a/plugins/org.eclipse.n4js/src/org/eclipse/n4js/typesystem/utils/ThisTypeComputer.xtend b/plugins/org.eclipse.n4js/src/org/eclipse/n4js/typesystem/utils/ThisTypeComputer.xtend deleted file mode 100644 index e3765d6cda..0000000000 --- a/plugins/org.eclipse.n4js/src/org/eclipse/n4js/typesystem/utils/ThisTypeComputer.xtend +++ /dev/null @@ -1,145 +0,0 @@ -/** - * Copyright (c) 2018 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.typesystem.utils - -import com.google.inject.Inject -import org.eclipse.emf.ecore.EObject -import org.eclipse.n4js.n4JS.ArrowFunction -import org.eclipse.n4js.n4JS.N4ClassDeclaration -import org.eclipse.n4js.n4JS.N4ClassifierDefinition -import org.eclipse.n4js.n4JS.N4FieldDeclaration -import org.eclipse.n4js.n4JS.N4GetterDeclaration -import org.eclipse.n4js.n4JS.N4JSASTUtils -import org.eclipse.n4js.n4JS.N4MemberDeclaration -import org.eclipse.n4js.n4JS.N4MethodDeclaration -import org.eclipse.n4js.n4JS.N4SetterDeclaration -import org.eclipse.n4js.n4JS.ObjectLiteral -import org.eclipse.n4js.ts.typeRefs.ParameterizedTypeRef -import org.eclipse.n4js.ts.typeRefs.TypeRef -import org.eclipse.n4js.ts.typeRefs.TypeRefsFactory -import org.eclipse.n4js.ts.types.TClass -import org.eclipse.n4js.ts.types.TypingStrategy -import org.eclipse.n4js.types.utils.TypeUtils -import org.eclipse.n4js.typesystem.N4JSTypeSystem -import org.eclipse.n4js.validation.JavaScriptVariantHelper -import org.eclipse.xtext.EcoreUtil2 - -import static extension org.eclipse.n4js.types.utils.TypeUtils.* -import static extension org.eclipse.n4js.typesystem.utils.RuleEnvironmentExtensions.* - -/** - * @see ThisTypeComputer#getThisTypeAtLocation(RuleEnvironment,EObject) - */ -class ThisTypeComputer extends TypeSystemHelperStrategy { - - @Inject - private N4JSTypeSystem ts; - @Inject - private JavaScriptVariantHelper jsVariantHelper; - - /** - * Computes the this type at the given location. Since ECMAScript does not support lexical this typing, this - * basically is a heuristic. - *

- * This code was moved here from judgment thisTypeRef in file 'n4js.xsemantics'. - */ - def TypeRef getThisTypeAtLocation(RuleEnvironment G, EObject location) { - if (location instanceof ParameterizedTypeRef) { - return TypeUtils.createBoundThisTypeRef(location); - } - - val containingFunctionOrAccessor = N4JSASTUtils.getContainingFunctionOrAccessor(location); - if (containingFunctionOrAccessor instanceof ArrowFunction) { - return getThisTypeAtLocation(G, containingFunctionOrAccessor); - } - - // searching for declaredTypeRefs introduced through @This - val containingTFunctionOrAccessor = if (containingFunctionOrAccessor !== null) { - containingFunctionOrAccessor.getDefinedFunctionOrAccessor() - }; - val declaredThisTypeRef = TypeSystemHelper.getDeclaredThisType(containingTFunctionOrAccessor); - if (declaredThisTypeRef !== null) { - if (declaredThisTypeRef instanceof ParameterizedTypeRef) { - return getThisTypeAtLocation(G, declaredThisTypeRef); - } - return declaredThisTypeRef; - } - - val thisTarget = N4JSASTUtils.getProbableThisTarget(location); - if (thisTarget instanceof ObjectLiteral) { - // call rule, type may be created on the fly - return ts.type(G, thisTarget); - } else if (thisTarget instanceof N4ClassifierDefinition) { - var thisTargetDefType = thisTarget.definedType; - - // In case of static polyfill (filler), replace defined type with filled type: - if (thisTarget instanceof N4ClassDeclaration) { - val clazz = thisTarget.definedTypeAsClass; - if (clazz !== null && clazz.isStaticPolyfill()) { - val actualClazz = clazz.superClassRef?.declaredType; - if (actualClazz !== null) { - thisTargetDefType = actualClazz; - } - } - } - - if (thisTargetDefType !== null) { - val containingFunction = N4JSASTUtils.getContainingFunction(location); - if (containingFunction instanceof N4MethodDeclaration && - (containingFunction as N4MemberDeclaration).isStatic) { - if (isInReturnDeclaration_Of_StaticMethod(location, containingFunction as N4MethodDeclaration)) { - return getThisTypeAtLocation(G, thisTargetDefType.createTypeRef(TypingStrategy.DEFAULT, true)); - } else if (isInBody_Of_StaticMethod(location, containingFunction as N4MethodDeclaration)) { - val ttRef = createTypeRefWithParamsAsArgs(thisTargetDefType); - if (thisTargetDefType instanceof TClass) { - val classTypeRef = ttRef//if (thisTargetDefType.final) ttRef else createWildcardExtends(ttRef); - return TypeUtils.createTypeTypeRef(TypeUtils.createBoundThisTypeRef(classTypeRef), true); - } else { - return TypeUtils.createClassifierBoundThisTypeRef(TypeUtils.createTypeTypeRef(ttRef, false)); - } - } else { - return TypeUtils.createConstructorTypeRef(thisTargetDefType); - } - } else { - val n4Field = EcoreUtil2.getContainerOfType(location, N4FieldDeclaration); - if (n4Field !== null && n4Field.isStatic) { - // this case has been disallowed as of GHOLD-263 - return TypeRefsFactory.eINSTANCE.createUnknownTypeRef(); - // old: - // return TypeUtils.createConstructorTypeRef(thisTargetDEFTYPE); - } else { - val n4Getter = EcoreUtil2.getContainerOfType(location, N4GetterDeclaration); - if (n4Getter !== null && n4Getter.isStatic) { - return TypeUtils.createConstructorTypeRef(thisTargetDefType); - } else { - val n4Setter = EcoreUtil2.getContainerOfType(location, N4SetterDeclaration); - if (n4Setter !== null && n4Setter.isStatic) { - return TypeUtils.createConstructorTypeRef(thisTargetDefType); - } else { - return getThisTypeAtLocation(G, thisTargetDefType.createTypeRefWithParamsAsArgs); - } - } - } - } - } else { - return G.anyTypeRefDynamic; - } - } else { - // if (unrestricted.isActive(location)) { - if (jsVariantHelper.hasGlobalObject(location)) { - return G.globalObjectTypeRef; - } - // note: it is possible to pass in a primitive as "thisArg"; therefore, 'this' in functions must - // actually be inferred to 'any', by default, not to 'Object': - return G.anyTypeRef; - } - } -} diff --git a/plugins/org.eclipse.n4js/src/org/eclipse/n4js/typesystem/utils/TypeSystemHelper.java b/plugins/org.eclipse.n4js/src/org/eclipse/n4js/typesystem/utils/TypeSystemHelper.java new file mode 100644 index 0000000000..a7565edd62 --- /dev/null +++ b/plugins/org.eclipse.n4js/src/org/eclipse/n4js/typesystem/utils/TypeSystemHelper.java @@ -0,0 +1,1039 @@ +/** + * 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.typesystem.utils; + +import static org.eclipse.n4js.typesystem.utils.RuleEnvironmentExtensions.anyTypeRef; +import static org.eclipse.n4js.typesystem.utils.RuleEnvironmentExtensions.anyTypeRefDynamic; +import static org.eclipse.n4js.typesystem.utils.RuleEnvironmentExtensions.functionTypeRef; +import static org.eclipse.n4js.typesystem.utils.RuleEnvironmentExtensions.generatorType; +import static org.eclipse.n4js.typesystem.utils.RuleEnvironmentExtensions.getContextResource; +import static org.eclipse.n4js.typesystem.utils.RuleEnvironmentExtensions.getPredefinedTypes; +import static org.eclipse.n4js.typesystem.utils.RuleEnvironmentExtensions.isAnyDynamic; +import static org.eclipse.n4js.typesystem.utils.RuleEnvironmentExtensions.nullType; +import static org.eclipse.n4js.typesystem.utils.RuleEnvironmentExtensions.setThisBinding; +import static org.eclipse.n4js.typesystem.utils.RuleEnvironmentExtensions.structuralFunctionTypeRef; +import static org.eclipse.n4js.typesystem.utils.RuleEnvironmentExtensions.undefinedType; +import static org.eclipse.n4js.typesystem.utils.RuleEnvironmentExtensions.voidType; +import static org.eclipse.n4js.typesystem.utils.RuleEnvironmentExtensions.wrap; +import static org.eclipse.xtext.xbase.lib.IterableExtensions.exists; +import static org.eclipse.xtext.xbase.lib.IterableExtensions.map; +import static org.eclipse.xtext.xbase.lib.IterableExtensions.toList; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; + +import org.eclipse.emf.common.util.TreeIterator; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.n4js.n4JS.Expression; +import org.eclipse.n4js.n4JS.FunctionDefinition; +import org.eclipse.n4js.n4JS.FunctionOrFieldAccessor; +import org.eclipse.n4js.n4JS.NewExpression; +import org.eclipse.n4js.n4JS.ParameterizedAccess; +import org.eclipse.n4js.n4JS.ParameterizedCallExpression; +import org.eclipse.n4js.n4JS.ParameterizedPropertyAccessExpression; +import org.eclipse.n4js.n4JS.ReturnStatement; +import org.eclipse.n4js.n4JS.YieldExpression; +import org.eclipse.n4js.scoping.builtin.BuiltInTypeScope; +import org.eclipse.n4js.ts.typeRefs.ComposedTypeRef; +import org.eclipse.n4js.ts.typeRefs.FunctionTypeExprOrRef; +import org.eclipse.n4js.ts.typeRefs.FunctionTypeRef; +import org.eclipse.n4js.ts.typeRefs.IntersectionTypeExpression; +import org.eclipse.n4js.ts.typeRefs.ParameterizedTypeRef; +import org.eclipse.n4js.ts.typeRefs.StructuralTypeRef; +import org.eclipse.n4js.ts.typeRefs.ThisTypeRef; +import org.eclipse.n4js.ts.typeRefs.TypeArgument; +import org.eclipse.n4js.ts.typeRefs.TypeRef; +import org.eclipse.n4js.ts.typeRefs.TypeRefsFactory; +import org.eclipse.n4js.ts.typeRefs.TypeTypeRef; +import org.eclipse.n4js.ts.typeRefs.UnionTypeExpression; +import org.eclipse.n4js.ts.typeRefs.UnknownTypeRef; +import org.eclipse.n4js.ts.types.ContainerType; +import org.eclipse.n4js.ts.types.IdentifiableElement; +import org.eclipse.n4js.ts.types.TClass; +import org.eclipse.n4js.ts.types.TFormalParameter; +import org.eclipse.n4js.ts.types.TFunction; +import org.eclipse.n4js.ts.types.TGetter; +import org.eclipse.n4js.ts.types.TInterface; +import org.eclipse.n4js.ts.types.TMember; +import org.eclipse.n4js.ts.types.TMethod; +import org.eclipse.n4js.ts.types.TSetter; +import org.eclipse.n4js.ts.types.TStructuralType; +import org.eclipse.n4js.ts.types.Type; +import org.eclipse.n4js.ts.types.TypesFactory; +import org.eclipse.n4js.ts.types.util.TypeExtensions; +import org.eclipse.n4js.ts.types.util.Variance; +import org.eclipse.n4js.types.utils.TypeUtils; +import org.eclipse.n4js.typesystem.N4JSTypeSystem; +import org.eclipse.n4js.typesystem.constraints.TypeConstraint; +import org.eclipse.n4js.typesystem.utils.StructuralTypingComputer.StructTypingInfo; +import org.eclipse.n4js.utils.ContainerTypesHelper; +import org.eclipse.n4js.utils.EcoreUtilN4; +import org.eclipse.n4js.utils.StructuralTypesHelper; +import org.eclipse.xtend.lib.annotations.Data; +import org.eclipse.xtext.EcoreUtil2; +import org.eclipse.xtext.xbase.lib.util.ToStringBuilder; + +import com.google.common.base.Optional; +import com.google.common.collect.Iterables; +import com.google.inject.Inject; +import com.google.inject.Singleton; + +/** + * Utility methods used in the XSemantics type system. Must be injected. + * + *

+ * Simple implementations are directly contained here. Complex operations such as join or meet are to be implemented in + * strategy classes. For those operations, this class acts as a facade. + *

+ * + *

+ * EObject Reference Note: All methods prefer using {@link TypeUtils#copyIfContained(EObject)} instead of + * {@link TypeUtils#copy(EObject)}. So, clients should follow this pattern as well. + *

+ * + * Bibliography: [Pierce02a] B. C. Pierce: Types and Programming Languages. The MIT Press, 1, + * 2002. + */ +@Singleton +@SuppressWarnings("javadoc") +public class TypeSystemHelper { + + @Inject + private N4JSTypeSystem ts; + + // ***************************************************************************************************** + // forwarding of utility methods implemented in strategy classes + // ***************************************************************************************************** + + @Inject + private GenericsComputer genericsComputer; + + @Inject + private SimplifyComputer simplifyComputer; + @Inject + private JoinComputer joinComputer; + @Inject + private MeetComputer meetComputer; + + @Inject + private SubtypeComputer subtypeComputer; + @Inject + private ExpectedTypeComputer expectedTypeCompuer; + @Inject + private StructuralTypingComputer structuralTypingComputer; + @Inject + private ThisTypeComputer thisTypeComputer; + @Inject + private IterableComputer iterableComputer; + @Inject + private TypeAliasComputer typeAliasComputer; + + @Inject + private ContainerTypesHelper containerTypesHelper; + + @Inject + private StructuralTypesHelper structuralTypesHelper; + + public StructuralTypesHelper getStructuralTypesHelper() { + return structuralTypesHelper; + } + + public void addSubstitutions(RuleEnvironment G, TypeRef typeRef) { + genericsComputer.addSubstitutions(G, typeRef); + } + + public void addSubstitutions(RuleEnvironment G, ParameterizedCallExpression callExpr, + FunctionTypeExprOrRef targetTypeRef, boolean defaultsTypeArgsToAny) { + genericsComputer.addSubstitutions(G, callExpr, targetTypeRef, defaultsTypeArgsToAny); + } + + public void addSubstitutions(RuleEnvironment G, NewExpression newExpr, TMethod constructSignature) { + genericsComputer.addSubstitutions(G, newExpr, constructSignature); + } + + public void addSubstitutions(RuleEnvironment G, ParameterizedPropertyAccessExpression accessExpr) { + genericsComputer.addSubstitutions(G, accessExpr); + } + + public TypeRef substTypeVariablesInStructuralMembers(RuleEnvironment G, StructuralTypeRef typeRef) { + return genericsComputer.substTypeVariablesInStructuralMembers(G, typeRef); + } + + public void storePostponedSubstitutionsIn(RuleEnvironment G, StructuralTypeRef typeRef) { + genericsComputer.storePostponedSubstitutionsIn(G, typeRef); + } + + public void restorePostponedSubstitutionsFrom(RuleEnvironment G, StructuralTypeRef typeRef) { + genericsComputer.restorePostponedSubstitutionsFrom(G, typeRef); + } + + /** + * See + * {@link GenericsComputer#checkTypeArgumentCompatibility(RuleEnvironment, TypeArgument, TypeArgument, Optional, boolean)}. + */ + public Result checkTypeArgumentCompatibility(RuleEnvironment G, TypeArgument leftArg, TypeArgument rightArg, + Optional varianceOpt, boolean useFancyErrMsg) { + + return genericsComputer.checkTypeArgumentCompatibility(G, leftArg, rightArg, varianceOpt, useFancyErrMsg); + } + + /** + * See + * {@link GenericsComputer#reduceTypeArgumentCompatibilityCheck(RuleEnvironment, TypeArgument, TypeArgument, Optional, boolean)}. + */ + public List reduceTypeArgumentCompatibilityCheck(RuleEnvironment G, TypeArgument leftArg, + TypeArgument rightArg, + Optional varianceOpt, boolean useFancyConstraints) { + + return genericsComputer.reduceTypeArgumentCompatibilityCheck(G, leftArg, rightArg, varianceOpt, + useFancyConstraints); + } + + public TypeRef createUnionType(RuleEnvironment G, TypeRef... elements) { + return simplifyComputer.createUnionType(G, elements); + } + + public TypeRef createIntersectionType(RuleEnvironment G, TypeRef... elements) { + return simplifyComputer.createIntersectionType(G, elements); + } + + public TypeRef simplify(RuleEnvironment G, T composedType) { + return simplify(G, composedType, true); + } + + public TypeRef simplify(RuleEnvironment G, T composedType, boolean checkSubtypes) { + return simplifyComputer.simplify(G, composedType, checkSubtypes); + } + + /** + * Convenience method calling {@link #join(RuleEnvironment, Iterable)} with type references inside an array. + */ + public TypeRef join(RuleEnvironment G, TypeRef... typeRefs) { + return joinComputer.join(G, Arrays.asList(typeRefs)); + } + + /** + * Returns the join, sometimes called least common super type (LCST), of the given types. + * + * @see JoinComputer#join(RuleEnvironment, Iterable) + */ + public TypeRef join(RuleEnvironment G, Iterable typeRefsToJoin) { + return joinComputer.join(G, typeRefsToJoin); + } + + /** + * Convenience method calling {@link #meet(RuleEnvironment, Iterable)} with type references inside an array. + */ + public TypeRef meet(RuleEnvironment G, TypeRef... typeRefs) { + return meetComputer.meet(G, Arrays.asList(typeRefs)); + } + + /** + * Returns the meet (first common sub type) of the given types + * + * @see MeetComputer#meet(RuleEnvironment, Iterable) + */ + public TypeRef meet(RuleEnvironment G, Iterable typeRefs) { + return meetComputer.meet(G, typeRefs); + } + + public boolean isSubtypeFunction(RuleEnvironment G, FunctionTypeExprOrRef left, FunctionTypeExprOrRef right) { + return subtypeComputer.isSubtypeFunction(G, left, right); + } + + public StructuralTypingResult isStructuralSubtype(RuleEnvironment G, TypeRef left, TypeRef right) { + return structuralTypingComputer.isStructuralSubtype(G, left, right); + } + + public List reduceMembers(RuleEnvironment G, TypeRef leftTypeRef, TMember left, TMember right, + StructTypingInfo info) { + return structuralTypingComputer.reduceMembers(G, leftTypeRef, left, right, info); + } + + /** @see ExpectedTypeComputer#getExpectedTypeOfReturnValueExpression(RuleEnvironment,Expression) */ + public TypeRef getExpectedTypeOfReturnValueExpression(RuleEnvironment G, Expression returnValueExpr) { + return expectedTypeCompuer.getExpectedTypeOfReturnValueExpression(G, returnValueExpr); + } + + /** @see ExpectedTypeComputer#getExpectedTypeOfYieldValueExpression(RuleEnvironment,YieldExpression,TypeRef) */ + public TypeRef getExpectedTypeOfYieldValueExpression(RuleEnvironment G, YieldExpression yieldExpr, + TypeRef exprTypeRef) { + return expectedTypeCompuer.getExpectedTypeOfYieldValueExpression(G, yieldExpr, exprTypeRef); + } + + /** @see ExpectedTypeComputer#getExpectedTypeOfYieldValueExpression(RuleEnvironment,YieldExpression,TypeRef) */ + public TypeRef getExpectedTypeOfFunctionOrFieldAccessor(RuleEnvironment G, FunctionOrFieldAccessor fofa) { + return expectedTypeCompuer.getExpectedTypeOfFunctionOrFieldAccessor(G, fofa); + } + + /** @see ThisTypeComputer#getThisTypeAtLocation(RuleEnvironment,EObject) */ + public TypeRef getThisTypeAtLocation(RuleEnvironment G, EObject location) { + return thisTypeComputer.getThisTypeAtLocation(G, location); + } + + /** @see IterableComputer#extractIterableElementTypes(RuleEnvironment, TypeRef) */ + public List extractIterableElementTypes(RuleEnvironment G, TypeRef typeRef) { + return iterableComputer.extractIterableElementTypes(G, typeRef); + } + + /** @see IterableComputer#extractIterableElementType(RuleEnvironment, TypeRef, boolean) */ + public TypeRef extractIterableElementType(RuleEnvironment G, TypeRef typeRef, boolean includeAsyncIterable) { + return iterableComputer.extractIterableElementType(G, typeRef, includeAsyncIterable); + } + + /** @see TypeAliasComputer#resolveTypeAliasFlat(RuleEnvironment, TypeRef) */ + public TypeRef resolveTypeAliasFlat(RuleEnvironment G, TypeRef typeRef) { + return typeAliasComputer.resolveTypeAliasFlat(G, typeRef); + } + + /** @see TypeAliasComputer#resolveTypeAliases(RuleEnvironment, TypeRef) */ + public TypeRef resolveTypeAliases(RuleEnvironment G, TypeRef typeRef) { + return typeAliasComputer.resolveTypeAliases(G, typeRef); + } + + /** @see TypeAliasComputer#resolveTypeAliases(RuleEnvironment, TypeArgument) */ + public TypeArgument resolveTypeAliases(RuleEnvironment G, TypeArgument typeArg) { + return typeAliasComputer.resolveTypeAliases(G, typeArg); + } + + // ***************************************************************************************************** + // small utility methods that do not have their own strategy class + // ***************************************************************************************************** + + public boolean allEqualType(RuleEnvironment G, TypeRef... typeRefs) { + if (typeRefs != null) { + int len = typeRefs.length; + if (len >= 2) { + TypeRef firstRef = typeRefs[0]; + for (var i = 1; i < len; i++) { + if (!ts.equaltypeSucceeded(G, firstRef, typeRefs[i])) + return false; + } + } + } + return true; + } + + public TypeRef sanitizeTypeOfVariableFieldPropertyParameter(RuleEnvironment G, TypeArgument typeRaw, + boolean resolveLiteralTypes) { + if (typeRaw == null || typeRaw instanceof UnknownTypeRef) { + return anyTypeRef(G); + } + // take upper bound to get rid of wildcards, etc. (if any) + TypeRef typeUB = (resolveLiteralTypes) + ? // ... and also replace literal types by their base type + ts.upperBoundWithReopenAndResolveLiteralTypes(G, typeRaw) + : ts.upperBoundWithReopen(G, typeRaw); + // replace silly types + Type declType = typeUB.getDeclaredType(); + if (declType == undefinedType(G) || declType == nullType(G) || declType == voidType(G)) { + return anyTypeRef(G); + } + return typeUB; + } + + public TreeIterator returnStatements(FunctionDefinition definition) { + return EcoreUtilN4.getAllContentsFiltered(definition, + it -> (it instanceof ReturnStatement && ((ReturnStatement) it).getExpression() != null)); + } + + /** + * If possible, a dynamic version of the given type ref is returned. If the type ref is already dynamic, it is + * returned. This is used for making all type refs dynamic in JavaScript mode. + */ + public TypeRef makeDynamic(TypeRef typeRef) { + if (!typeRef.isDynamic()) { + if (typeRef instanceof ParameterizedTypeRef) { + ParameterizedTypeRef dyn = TypeUtils.copyIfContained((ParameterizedTypeRef) typeRef); + dyn.setDynamic(true); + return dyn; + } + } + return typeRef; + } + + /** + * Returns the explicitly declared this type, or null. + * + * @param type + * either subtype of TFunction, of FieldAccessor, or of FunctionTypeExprOrRef can have a declared this + * type ("@This") + * @return declaredThisType if any, null in other cases. + */ + public static TypeRef getDeclaredThisType(IdentifiableElement type) { + if (type instanceof TFunction) { + return ((TFunction) type).getDeclaredThisType(); + } + if (type instanceof TGetter) { + return ((TGetter) type).getDeclaredThisType(); + } + if (type instanceof TSetter) { + return ((TSetter) type).getDeclaredThisType(); + } + if (type instanceof FunctionTypeExprOrRef) { + return ((FunctionTypeExprOrRef) type).getDeclaredThisType(); + } + return null; + } + + /** + * Binds and substitutes the given {@link ThisTypeRef this type reference} after wrapping the given rule + * environment. + * + *

+ * For instance after passing a {@code ~~this} type reference into a method in the context of container + * {@code class A}, the type reference argument will be bound to {@code this[A]} and finally will be substituted + * with {@code ~~this[A]} type reference. That will be the return value of the method. + * + * @param G + * the rule environment that will be wrapped for the operation. + * @param location + * location within the AST for which to create a BoundThisTypeRef. Same as the argument 'location' of + * judgment 'thisTypeRef' in Xsemantics. + * @param typeRef + * type reference to substitute; this can either be an unbound ThisTypeRef or any other kind of TypeRef + * that contains one or more unbound ThisTypeRefs. Need not be contained in the AST (as usual for type + * references). + */ + public TypeRef bindAndSubstituteThisTypeRef(RuleEnvironment G, EObject location, TypeRef typeRef) { + // create a BoundThisTypeRef for given location + TypeRef boundThisTypeRef = getThisTypeAtLocation(G, location); + RuleEnvironment localG = wrap(G); + setThisBinding(localG, boundThisTypeRef); + // substitute all unbound ThisTypeRefs with the newly created BoundThisTypeRef + return ts.substTypeVariables(localG, typeRef); + } + + public static class Callable { + /** + * The actual type reference that contributed function/method. Used for error reporting. + */ + private final TypeRef callableTypeRef; + + /** + * The signature of the function/method being invoked. Used for argument checking and to obtain the type of the + * return value. If absent, the invocation is possible, but no information about the parameters or the return + * value is available (e.g. when invoking values of built-in type {@code Function}). + */ + private final Optional signatureTypeRef; + + /** + * Tells whether the function/method being invoked is {@link TypeRef#isDynamic() dynamic}. + */ + private final boolean dynamic; + + public Callable(final TypeRef callableTypeRef, final Optional signatureTypeRef, + final boolean dynamic) { + super(); + this.callableTypeRef = callableTypeRef; + this.signatureTypeRef = signatureTypeRef; + this.dynamic = dynamic; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((this.callableTypeRef == null) ? 0 : this.callableTypeRef.hashCode()); + result = prime * result + ((this.signatureTypeRef == null) ? 0 : this.signatureTypeRef.hashCode()); + return prime * result + (this.dynamic ? 1231 : 1237); + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + TypeSystemHelper.Callable other = (TypeSystemHelper.Callable) obj; + if (this.callableTypeRef == null) { + if (other.callableTypeRef != null) + return false; + } else if (!this.callableTypeRef.equals(other.callableTypeRef)) + return false; + if (this.signatureTypeRef == null) { + if (other.signatureTypeRef != null) + return false; + } else if (!this.signatureTypeRef.equals(other.signatureTypeRef)) + return false; + if (other.dynamic != this.dynamic) + return false; + return true; + } + + @Override + public String toString() { + ToStringBuilder b = new ToStringBuilder(this); + b.add("callableTypeRef", this.callableTypeRef); + b.add("signatureTypeRef", this.signatureTypeRef); + b.add("dynamic", this.dynamic); + return b.toString(); + } + + public TypeRef getCallableTypeRef() { + return this.callableTypeRef; + } + + public Optional getSignatureTypeRef() { + return this.signatureTypeRef; + } + + public boolean isDynamic() { + return this.dynamic; + } + } + + @Data + public static class Newable { + /** + * The actual type reference that contributed constructor or construct signature. Used for error reporting. + */ + private final TypeRef newableTypeRef; + + /** + * The constructor or construct signature. Used for argument checking. Can be null. + */ + private final TMethod ctorOrConstructSig; + + /** + * The type of the newly created instance. + */ + private final TypeRef instanceTypeRef; + + public Newable(final TypeRef newableTypeRef, final TMethod ctorOrConstructSig, final TypeRef instanceTypeRef) { + super(); + this.newableTypeRef = newableTypeRef; + this.ctorOrConstructSig = ctorOrConstructSig; + this.instanceTypeRef = instanceTypeRef; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((this.newableTypeRef == null) ? 0 : this.newableTypeRef.hashCode()); + result = prime * result + ((this.ctorOrConstructSig == null) ? 0 : this.ctorOrConstructSig.hashCode()); + return prime * result + ((this.instanceTypeRef == null) ? 0 : this.instanceTypeRef.hashCode()); + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + TypeSystemHelper.Newable other = (TypeSystemHelper.Newable) obj; + if (this.newableTypeRef == null) { + if (other.newableTypeRef != null) + return false; + } else if (!this.newableTypeRef.equals(other.newableTypeRef)) + return false; + if (this.ctorOrConstructSig == null) { + if (other.ctorOrConstructSig != null) + return false; + } else if (!this.ctorOrConstructSig.equals(other.ctorOrConstructSig)) + return false; + if (this.instanceTypeRef == null) { + if (other.instanceTypeRef != null) + return false; + } else if (!this.instanceTypeRef.equals(other.instanceTypeRef)) + return false; + return true; + } + + @Override + public String toString() { + ToStringBuilder b = new ToStringBuilder(this); + b.add("newableTypeRef", this.newableTypeRef); + b.add("ctorOrConstructSig", this.ctorOrConstructSig); + b.add("instanceTypeRef", this.instanceTypeRef); + return b.toString(); + } + + public TypeRef getNewableTypeRef() { + return this.newableTypeRef; + } + + public TMethod getCtorOrConstructSig() { + return this.ctorOrConstructSig; + } + + public TypeRef getInstanceTypeRef() { + return this.instanceTypeRef; + } + } + + /** + * Checks if a value of the given type is "callable" (i.e. can be invoked with a call expression). If so, returns an + * instance of class {@link Callable} with further information; if not, returns null. + */ + public Callable getCallableTypeRef(RuleEnvironment G, TypeRef typeRef) { + List result = getCallableTypeRefs(G, typeRef); + if (result.size() == 1) { + return result.get(0); + } + return null; + } + + public List getCallableTypeRefs(RuleEnvironment G, TypeRef typeRef) { + if (typeRef instanceof UnionTypeExpression) { + // TODO implement special handling for unions + } else if (typeRef instanceof IntersectionTypeExpression) { + // TODO improve special handling for intersections + List result = new ArrayList<>(); + var foundWithoutSignature = false; + var foundWithoutSignatureDynamic = false; + for (TypeRef currTypeRef : ((IntersectionTypeExpression) typeRef).getTypeRefs()) { + Callable currCallable = internalGetCallableTypeRef(G, currTypeRef); + if (currCallable != null) { + if (!currCallable.signatureTypeRef.isPresent()) { + foundWithoutSignature = true; + foundWithoutSignatureDynamic = foundWithoutSignatureDynamic || currCallable.dynamic; + } else { + result.add(currCallable); + } + } + } + if (result.isEmpty() && foundWithoutSignature) { + return Collections + .singletonList(new Callable(typeRef, Optional.absent(), foundWithoutSignatureDynamic)); + } + return result; + } + Callable result = internalGetCallableTypeRef(G, typeRef); + if (result != null) { + return Collections.singletonList(result); + } + return Collections.emptyList(); + } + + private Callable internalGetCallableTypeRef(RuleEnvironment G, TypeRef typeRef) { + if (typeRef instanceof UnknownTypeRef) { + return null; + } + if (typeRef instanceof FunctionTypeExprOrRef) { + return new Callable(typeRef, Optional.of((FunctionTypeExprOrRef) typeRef), typeRef.isDynamic()); + } + if (isClassConstructorFunction(G, typeRef)) { + // don't allow direct invocation of class constructors + TMethod callableCtor = getCallableClassConstructorFunction(G, typeRef); + if (callableCtor != null) { + // exception: this is a class that provides a call signature + return new Callable(typeRef, Optional.of((FunctionTypeRef) TypeUtils.createTypeRef(callableCtor)), + typeRef.isDynamic()); + } + return null; + } + TMethod callSig = getCallSignature(G, typeRef); + if (callSig != null) { + return new Callable(typeRef, Optional.of((FunctionTypeRef) TypeUtils.createTypeRef(callSig)), + typeRef.isDynamic()); + } + if (ts.subtypeSucceeded(G, typeRef, functionTypeRef(G)) + || ts.subtypeSucceeded(G, typeRef, structuralFunctionTypeRef(G)) + || (typeRef.isDynamic() && ts.subtypeSucceeded(G, functionTypeRef(G), typeRef))) { + return new Callable(typeRef, Optional.absent(), typeRef.isDynamic()); + } + return null; + } + + public Newable getNewableTypeRef(RuleEnvironment G, NewExpression newExpr, boolean ignoreConstructSignatures) { + TypeRef calleeTypeRef = ts.type(G, newExpr.getCallee()); + return getNewableTypeRef(G, calleeTypeRef, newExpr, ignoreConstructSignatures); + } + + /** + * Checks if a value of the given type is "newable" (i.e. can be instantiated with keyword "new"). If so, returns an + * instance of class {@link Newable} with further information; if not, returns null. + */ + public Newable getNewableTypeRef(RuleEnvironment G, TypeRef typeRef, NewExpression newExpr, + boolean ignoreConstructSignatures) { + List result = getNewableTypeRefs(G, typeRef, newExpr, ignoreConstructSignatures); + if (result.size() == 1) { + return result.get(0); + } + return null; + } + + public List getNewableTypeRefs(RuleEnvironment G, TypeRef typeRef, NewExpression newExpr, + boolean ignoreConstructSignatures) { + + if (typeRef instanceof UnionTypeExpression) { + List newables = new ArrayList<>(); + for (TypeRef currTypeRef : ((UnionTypeExpression) typeRef).getTypeRefs()) { + Newable curr = internalGetNewableTypeRef(G, currTypeRef, newExpr, ignoreConstructSignatures); + if (curr != null) { + newables.add(curr); + } + } + List constructSigsReturn = new ArrayList<>(); + List resTypeRefs = new ArrayList<>(); + for (Newable newable : newables) { + resTypeRefs.add(newable.getInstanceTypeRef()); + if (newable.ctorOrConstructSig != null) { + constructSigsReturn.add(newable.ctorOrConstructSig.getReturnTypeRef()); + } + } + + // use non-simplified because union with any+ will remove other types that would give additional info to the + // user + TypeRef resTypeRef = TypeUtils.createNonSimplifiedUnionType(resTypeRefs); + TMethod constructSig = TypesFactory.eINSTANCE.createTMethod(); + constructSig.setReturnTypeRef(TypeUtils.createNonSimplifiedUnionType(constructSigsReturn)); + TFormalParameter vArgs = TypesFactory.eINSTANCE.createTFormalParameter(); + constructSig.getFpars().add(vArgs); + vArgs.setVariadic(true); + vArgs.setTypeRef(anyTypeRefDynamic(G)); + // TODO improve merging of construct signatures + + return Collections.singletonList(new Newable(typeRef, constructSig, resTypeRef)); + + } else if (typeRef instanceof IntersectionTypeExpression) { + // TODO improve special handling for intersections + TypeRef typeRef2 = simplifyComputer.simplify(G, (IntersectionTypeExpression) typeRef, true); + if (typeRef2 instanceof IntersectionTypeExpression) { + List result = new ArrayList<>(); + for (TypeRef currTypeRef : ((IntersectionTypeExpression) typeRef2).getTypeRefs()) { + Newable curr = internalGetNewableTypeRef(G, currTypeRef, newExpr, ignoreConstructSignatures); + if (curr != null) { + result.add(curr); + } + } + return result; + } else { + return getNewableTypeRefs(G, typeRef2, newExpr, ignoreConstructSignatures); + } + } + Newable result = internalGetNewableTypeRef(G, typeRef, newExpr, ignoreConstructSignatures); + if (result != null) { + return Collections.singletonList(result); + } + return Collections.emptyList(); + } + + private Newable internalGetNewableTypeRef(RuleEnvironment G, TypeRef calleeTypeRef, NewExpression newExpr, + boolean ignoreConstructSignatures) { + if (calleeTypeRef instanceof TypeTypeRef) { + TMethod ctor = null; + Type staticType = getStaticType(G, (TypeTypeRef) calleeTypeRef, true); + if (staticType instanceof ContainerType) { + ctor = containerTypesHelper.fromContext(getContextResource(G)) + .findConstructor((ContainerType) staticType); + } + TypeRef instanceTypeRef = createTypeRefFromStaticType(G, (TypeTypeRef) calleeTypeRef, newExpr); + return new Newable(calleeTypeRef, ctor, instanceTypeRef); + } + if (isAnyDynamic(G, calleeTypeRef)) { + TMethod constructSig = TypesFactory.eINSTANCE.createTMethod(); + constructSig.setReturnTypeRef(anyTypeRefDynamic(G)); + TFormalParameter vArgs = TypesFactory.eINSTANCE.createTFormalParameter(); + constructSig.getFpars().add(vArgs); + vArgs.setVariadic(true); + vArgs.setTypeRef(anyTypeRefDynamic(G)); + + return new Newable(calleeTypeRef, constructSig, anyTypeRefDynamic(G)); + } + if (!ignoreConstructSignatures) { + TMethod constructSig = getConstructSignature(G, calleeTypeRef); + if (constructSig != null) { + TypeRef returnTypeRef = constructSig.getReturnTypeRef(); + if (returnTypeRef != null && !TypeUtils.isVoid(returnTypeRef)) { + RuleEnvironment G2 = wrap(G); + addSubstitutions(G2, newExpr, constructSig); + TypeRef returnTypeRefSubst = ts.substTypeVariablesWithFullCapture(G2, returnTypeRef); + return new Newable(calleeTypeRef, constructSig, returnTypeRefSubst); + } + } + } + return null; + } + + /** + * Checks if a value of type typeRef is a class constructor function. + */ + public boolean isClassConstructorFunction(RuleEnvironment G, TypeRef typeRef) { + Type declaredType = typeRef.getDeclaredType(); + if (declaredType instanceof TMethod) { + if (((TMethod) declaredType).isConstructor()) { + return true; + } + } + if (typeRef instanceof FunctionTypeExprOrRef) { + TFunction ft = ((FunctionTypeExprOrRef) typeRef).getFunctionType(); + if (ft instanceof TMethod) { + if (((TMethod) ft).isConstructor()) { + return true; + } + } + } + if (typeRef instanceof TypeTypeRef) { + Type cls = getStaticType(G, (TypeTypeRef) typeRef); + if (cls instanceof TClass) { + return true; + } + } + return false; + } + + public TMethod getCallableClassConstructorFunction(RuleEnvironment G, TypeRef typeRef) { + Type type = null; + Type declaredType = typeRef.getDeclaredType(); + if (declaredType instanceof TMethod) { + if (((TMethod) declaredType).isConstructor()) { + type = ((TMethod) declaredType).getContainingType(); + } + } + if (typeRef instanceof FunctionTypeExprOrRef) { + TFunction ft = ((FunctionTypeExprOrRef) typeRef).getFunctionType(); + if (ft instanceof TMethod) { + if (((TMethod) ft).isConstructor()) { + type = ((TMethod) ft).getContainingType(); + } + } + } + if (typeRef instanceof TypeTypeRef) { + Type cls = getStaticType(G, (TypeTypeRef) typeRef); + if (cls instanceof TClass) { + type = cls; + } + } + if (type instanceof TClass) { + // note: "callable constructors" (i.e. call signatures in classes) are not inherited + // and cannot appear in StructuralTypeRefs, so no need for ContainerTypesHelper or + // checking for TStructuralType here: + return ((TClass) type).getCallSignature(); + } + return null; + } + + public TMethod getCallSignature(RuleEnvironment G, TypeRef calleeTypeRef) { + return getCallSignature(getContextResource(G), calleeTypeRef); + } + + public TMethod getCallSignature(Resource context, TypeRef calleeTypeRef) { + return getCallConstructSignature(context, calleeTypeRef, false); + } + + public TMethod getConstructSignature(RuleEnvironment G, TypeRef calleeTypeRef) { + return getConstructSignature(getContextResource(G), calleeTypeRef); + } + + public TMethod getConstructSignature(Resource context, TypeRef calleeTypeRef) { + return getCallConstructSignature(context, calleeTypeRef, true); + } + + /** + * NOTE: does not cover "callable constructors" (i.e. call signatures in classes); use method + * {@link #getCallableClassConstructorFunction(RuleEnvironment,TypeRef)} for this purpose. + */ + private TMethod getCallConstructSignature(Resource context, TypeRef calleeTypeRef, boolean searchConstructSig) { + Type declType = calleeTypeRef.getDeclaredType(); + if (declType instanceof TInterface) { + if (searchConstructSig) { + return containerTypesHelper.fromContext(context).findConstructSignature((TInterface) declType); + } else { + return containerTypesHelper.fromContext(context).findCallSignature((TInterface) declType); + } + } + if (calleeTypeRef instanceof StructuralTypeRef) { + TStructuralType structType = ((StructuralTypeRef) calleeTypeRef).getStructuralType(); + if (structType != null) { + if (searchConstructSig) { + return structType.getConstructSignature(); + } else { + return structType.getCallSignature(); + } + } + } + return null; + } + + public FunctionTypeExprOrRef getFunctionTypeExprOrRef(RuleEnvironment G, TypeRef typeRef) { + if (typeRef instanceof FunctionTypeExprOrRef) { + return (FunctionTypeExprOrRef) typeRef; + } + Callable callable = getCallableTypeRef(G, typeRef); + if (callable != null) { + return callable.signatureTypeRef.orNull(); + } + return null; + } + + /** Same as {@link #getStaticType(RuleEnvironment, TypeTypeRef, boolean)} without resolving type variables. */ + public Type getStaticType(RuleEnvironment G, TypeTypeRef typeTypeRef) { + return getStaticType(G, typeTypeRef, false); + } + + /** + * Returns the so-called "static type" of the given {@link TypeTypeRef} or null if not available. Iff + * {@code resolveTypeVariables} is true, then type variables will be resolved (i.e. replaced by their + * explicit or implicit upper bound). + *

+ * Formerly, this was a utility operation in {@code TypeRefs.xcore} but since the introduction of wildcards in + * {@code TypeTypeRef}s the 'upperBound' judgment (and thus a RuleEnvironment) is required to compute this and hence + * it was moved here. + */ + public Type getStaticType(RuleEnvironment G, TypeTypeRef typeTypeRef, boolean resolveTypeVariables) { + TypeRef staticTypeRef = getStaticTypeRef(G, typeTypeRef, resolveTypeVariables); + if (staticTypeRef == null) { + return null; + } + return staticTypeRef.getDeclaredType(); // will return null if #getStaticTypeRef() is not of type + // ParameterizedTypeRef + } + + public TypeRef getStaticTypeRef(RuleEnvironment G, TypeTypeRef typeTypeRef) { + return getStaticTypeRef(G, typeTypeRef, false); + } + + public TypeRef getStaticTypeRef(RuleEnvironment G, TypeTypeRef typeTypeRef, boolean resolveTypeVariables) { + TypeArgument typeArg = typeTypeRef.getTypeArg(); + TypeRef typeArgUB = resolveTypeVariables + ? ts.upperBoundWithReopenAndResolveTypeVars(G, typeArg) + : ts.upperBoundWithReopen(G, typeArg); + return typeArgUB; + } + + public TypeRef createTypeRefFromStaticType(RuleEnvironment G, TypeTypeRef ctr, ParameterizedAccess paramAccess) { + + return createTypeRefFromStaticType(G, ctr, + toList(map(paramAccess.getTypeArgs(), ta -> ta.getTypeRef())).toArray(new TypeArgument[0])); + } + + /** + * Creates a parameterized type ref to the wrapped static type of a TypeTypeRef, configured with the given + * TypeArguments. Returns UnknownTypeRef if the static type could not be retrieved (e.g. unbound This-Type). + */ + public TypeRef createTypeRefFromStaticType(RuleEnvironment G, TypeTypeRef ctr, TypeArgument... typeArgs) { + TypeRef typeRef = getStaticTypeRef(G, ctr); + Type type = typeRef == null ? null : typeRef.getDeclaredType(); + if (type != null) { + return TypeExtensions.ref(type, typeArgs); + } + return TypeRefsFactory.eINSTANCE.createUnknownTypeRef(); + } + + /** + * This method computes the set of all subtypes in the set of TypeRefs. It does not copy the TypeRefs! + */ + public List getSubtypesOnly(RuleEnvironment G, TypeRef... typeRefs) { + List intersectTRs = new LinkedList<>(); + + for (TypeRef s : typeRefs) { + if (!exists(intersectTRs, it -> ts.subtypeSucceeded(G, it, s))) { + Iterables.removeIf(intersectTRs, it -> ts.subtypeSucceeded(G, s, it)); + intersectTRs.add(s); + } + } + + return intersectTRs; + } + + /** + * This method computes the set of all super types in the set of TypeRefs. It does not copy the TypeRefs! + */ + public List getSuperTypesOnly(RuleEnvironment G, TypeRef... typeRefs) { + List unionTRs = new LinkedList<>(); + + for (TypeRef s : typeRefs) { + if (!exists(unionTRs, it -> ts.subtypeSucceeded(G, s, it))) { + Iterables.removeIf(unionTRs, it -> ts.subtypeSucceeded(G, s, it)); + unionTRs.add(s); + } + } + + return unionTRs; + } + + /** + * From any expression within a generator function or method, the type TNext is returned (referring to the actual + * (outer) return type, which is {@code [Async]Generator}). + */ + public TypeRef getActualGeneratorReturnType(RuleEnvironment G, Expression expr) { + if (expr == null) { + return null; + } + FunctionDefinition funDef = EcoreUtil2.getContainerOfType(expr.eContainer(), FunctionDefinition.class); + RuleEnvironment G2 = wrap(G); + TypeRef myThisTypeRef = getThisTypeAtLocation(G, expr); + setThisBinding(G2, myThisTypeRef); // takes the real-this type even if it is a type{this} reference. + + if (funDef == null || !funDef.isGenerator()) { + return null; // yield only occurs in generator functions + } + + Type tFun = funDef.getDefinedType(); + if (tFun instanceof TFunction) { + TypeRef actualReturnTypeRef = ((TFunction) tFun).getReturnTypeRef(); + BuiltInTypeScope scope = getPredefinedTypes(G).builtInTypeScope; + if (TypeUtils.isGeneratorOrAsyncGenerator(actualReturnTypeRef, scope)) { + return actualReturnTypeRef; + } + } + return TypeRefsFactory.eINSTANCE.createUnknownTypeRef(); + } + + /** + * Given a {@link TypeRef} to a {@code [Async]Generator} class, this method returns TYield, if + * existent. + */ + public TypeRef getGeneratorTYield(RuleEnvironment G, TypeRef generatorTypeRef) { + TypeRef yieldTypeRef = null; + if (generatorTypeRef.getDeclaredTypeArgs().size() >= 1) { + TypeArgument yieldTypeArg = generatorTypeRef.getDeclaredTypeArgs().get(0); + if (yieldTypeArg != null) + yieldTypeRef = ts.upperBound(G, yieldTypeArg); // take upper bound to get rid of Wildcard, etc. + } else { + yieldTypeRef = generatorType(G).getTypeVars().get(0).getDefaultArgument(); + } + return yieldTypeRef; + } + + /** + * Given a {@link TypeRef} to a {@code [Async]Generator} class, this method returns TReturn, + * if existent. + */ + public TypeRef getGeneratorTReturn(RuleEnvironment G, TypeRef generatorTypeRef) { + TypeRef returnTypeRef = null; + if (generatorTypeRef.getDeclaredTypeArgs().size() >= 2) { + TypeArgument returnTypeArg = generatorTypeRef.getDeclaredTypeArgs().get(1); + if (returnTypeArg != null) + returnTypeRef = ts.upperBound(G, returnTypeArg); // take upper bound to get rid of Wildcard, etc. + } else { + returnTypeRef = generatorType(G).getTypeVars().get(1).getDefaultArgument(); + } + return returnTypeRef; + } + + /** + * Given a {@link TypeRef} to a {@code [Async]Generator} class, this method returns TNext, if + * existent. + */ + public TypeRef getGeneratorTNext(RuleEnvironment G, TypeRef generatorTypeRef) { + TypeRef nextTypeRef = null; + if (generatorTypeRef.getDeclaredTypeArgs().size() >= 3) { + TypeArgument nextTypeArg = generatorTypeRef.getDeclaredTypeArgs().get(2); + if (nextTypeArg != null) + nextTypeRef = ts.upperBound(G, nextTypeArg); // take upper bound to get rid of Wildcard, etc. + } else { + nextTypeRef = generatorType(G).getTypeVars().get(2).getDefaultArgument(); + } + return nextTypeRef; + } +} diff --git a/plugins/org.eclipse.n4js/src/org/eclipse/n4js/typesystem/utils/TypeSystemHelper.xtend b/plugins/org.eclipse.n4js/src/org/eclipse/n4js/typesystem/utils/TypeSystemHelper.xtend deleted file mode 100644 index 77aaeab4ae..0000000000 --- a/plugins/org.eclipse.n4js/src/org/eclipse/n4js/typesystem/utils/TypeSystemHelper.xtend +++ /dev/null @@ -1,820 +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.typesystem.utils - -import com.google.common.base.Optional -import com.google.common.collect.Iterables -import com.google.inject.Inject -import com.google.inject.Singleton -import java.util.ArrayList -import java.util.Arrays -import java.util.Collections -import java.util.LinkedList -import java.util.List -import org.eclipse.emf.ecore.EObject -import org.eclipse.emf.ecore.resource.Resource -import org.eclipse.n4js.n4JS.Expression -import org.eclipse.n4js.n4JS.FunctionDefinition -import org.eclipse.n4js.n4JS.FunctionOrFieldAccessor -import org.eclipse.n4js.n4JS.NewExpression -import org.eclipse.n4js.n4JS.ParameterizedAccess -import org.eclipse.n4js.n4JS.ParameterizedCallExpression -import org.eclipse.n4js.n4JS.ParameterizedPropertyAccessExpression -import org.eclipse.n4js.n4JS.ReturnStatement -import org.eclipse.n4js.n4JS.YieldExpression -import org.eclipse.n4js.ts.typeRefs.ComposedTypeRef -import org.eclipse.n4js.ts.typeRefs.FunctionTypeExprOrRef -import org.eclipse.n4js.ts.typeRefs.FunctionTypeRef -import org.eclipse.n4js.ts.typeRefs.IntersectionTypeExpression -import org.eclipse.n4js.ts.typeRefs.ParameterizedTypeRef -import org.eclipse.n4js.ts.typeRefs.StructuralTypeRef -import org.eclipse.n4js.ts.typeRefs.ThisTypeRef -import org.eclipse.n4js.ts.typeRefs.TypeArgument -import org.eclipse.n4js.ts.typeRefs.TypeRef -import org.eclipse.n4js.ts.typeRefs.TypeRefsFactory -import org.eclipse.n4js.ts.typeRefs.TypeTypeRef -import org.eclipse.n4js.ts.typeRefs.UnionTypeExpression -import org.eclipse.n4js.ts.typeRefs.UnknownTypeRef -import org.eclipse.n4js.ts.types.ContainerType -import org.eclipse.n4js.ts.types.IdentifiableElement -import org.eclipse.n4js.ts.types.TClass -import org.eclipse.n4js.ts.types.TFunction -import org.eclipse.n4js.ts.types.TGetter -import org.eclipse.n4js.ts.types.TInterface -import org.eclipse.n4js.ts.types.TMember -import org.eclipse.n4js.ts.types.TMethod -import org.eclipse.n4js.ts.types.TSetter -import org.eclipse.n4js.ts.types.Type -import org.eclipse.n4js.ts.types.TypesFactory -import org.eclipse.n4js.ts.types.util.TypeExtensions -import org.eclipse.n4js.ts.types.util.Variance -import org.eclipse.n4js.types.utils.TypeUtils -import org.eclipse.n4js.typesystem.N4JSTypeSystem -import org.eclipse.n4js.typesystem.constraints.TypeConstraint -import org.eclipse.n4js.typesystem.utils.StructuralTypingComputer.StructTypingInfo -import org.eclipse.n4js.utils.ContainerTypesHelper -import org.eclipse.n4js.utils.EcoreUtilN4 -import org.eclipse.n4js.utils.Log -import org.eclipse.n4js.utils.StructuralTypesHelper -import org.eclipse.xtend.lib.annotations.Data -import org.eclipse.xtext.EcoreUtil2 - -import static extension org.eclipse.n4js.typesystem.utils.RuleEnvironmentExtensions.* - -/** - * Utility methods used in the XSemantics type system. Must be injected. - * - *

Simple implementations are directly contained here. Complex operations such as join or meet are to - * be implemented in strategy classes. For those operations, this class acts as a facade.

- * - *

EObject Reference Note: All methods prefer using {@link TypeUtils.copyIfContained(EObject)} instead - * of {@link TypeUtils.copy(EObject)}. So, clients should follow this pattern as well.

- * - * Bibliography: - * [Pierce02a] B. C. Pierce: Types and Programming Languages. The MIT Press, 1, 2002. - */ -@Log -@Singleton -class TypeSystemHelper { - - @Inject private N4JSTypeSystem ts; - - // ***************************************************************************************************** - // forwarding of utility methods implemented in strategy classes - // ***************************************************************************************************** - - @Inject private GenericsComputer genericsComputer; - - @Inject private SimplifyComputer simplifyComputer; - @Inject private JoinComputer joinComputer; - @Inject private MeetComputer meetComputer; - - @Inject private SubtypeComputer subtypeComputer; - @Inject private ExpectedTypeComputer expectedTypeCompuer; - @Inject private StructuralTypingComputer structuralTypingComputer; - @Inject private ThisTypeComputer thisTypeComputer; - @Inject private IterableComputer iterableComputer; - @Inject private TypeAliasComputer typeAliasComputer; - - @Inject private ContainerTypesHelper containerTypesHelper; - - -@Inject private StructuralTypesHelper structuralTypesHelper; -def StructuralTypesHelper getStructuralTypesHelper() { - return structuralTypesHelper; -} - - - def void addSubstitutions(RuleEnvironment G, TypeRef typeRef) { - genericsComputer.addSubstitutions(G, typeRef) - } - def void addSubstitutions(RuleEnvironment G, ParameterizedCallExpression callExpr, FunctionTypeExprOrRef targetTypeRef, boolean defaultsTypeArgsToAny) { - genericsComputer.addSubstitutions(G, callExpr, targetTypeRef, defaultsTypeArgsToAny) - } - def void addSubstitutions(RuleEnvironment G, NewExpression newExpr, TMethod constructSignature) { - genericsComputer.addSubstitutions(G, newExpr, constructSignature); - } - def void addSubstitutions(RuleEnvironment G, ParameterizedPropertyAccessExpression accessExpr) { - genericsComputer.addSubstitutions(G,accessExpr) - } - def TypeRef substTypeVariablesInStructuralMembers(RuleEnvironment G, StructuralTypeRef typeRef) { - genericsComputer.substTypeVariablesInStructuralMembers(G, typeRef) - } - def void storePostponedSubstitutionsIn(RuleEnvironment G, StructuralTypeRef typeRef) { - genericsComputer.storePostponedSubstitutionsIn(G, typeRef); - } - def void restorePostponedSubstitutionsFrom(RuleEnvironment G, StructuralTypeRef typeRef) { - genericsComputer.restorePostponedSubstitutionsFrom(G, typeRef); - } - /** See {@link GenericsComputer#checkTypeArgumentCompatibility(RuleEnvironment, TypeArgument, TypeArgument, Optional, boolean)}. */ - def Result checkTypeArgumentCompatibility(RuleEnvironment G, TypeArgument leftArg, TypeArgument rightArg, - Optional varianceOpt, boolean useFancyErrMsg) { - - return genericsComputer.checkTypeArgumentCompatibility(G, leftArg, rightArg, varianceOpt, useFancyErrMsg); - } - /** See {@link GenericsComputer#reduceTypeArgumentCompatibilityCheck(RuleEnvironment, TypeArgument, TypeArgument, Optional, boolean)}. */ - def List reduceTypeArgumentCompatibilityCheck(RuleEnvironment G, TypeArgument leftArg, TypeArgument rightArg, - Optional varianceOpt, boolean useFancyConstraints) { - - return genericsComputer.reduceTypeArgumentCompatibilityCheck(G, leftArg, rightArg, varianceOpt, useFancyConstraints); - } - - def TypeRef createUnionType(RuleEnvironment G, TypeRef... elements) { - simplifyComputer.createUnionType(G,elements) - } - - def TypeRef createIntersectionType(RuleEnvironment G, TypeRef... elements) { - simplifyComputer.createIntersectionType(G,elements) - } - def TypeRef simplify(RuleEnvironment G, T composedType) { - simplify(G,composedType, true) - } - def TypeRef simplify(RuleEnvironment G, T composedType, boolean checkSubtypes) { - simplifyComputer.simplify(G,composedType,checkSubtypes) - } - - /** - * Convenience method calling {@link join(RuleEnvironment, Iterable)} with - * type references inside an array. - */ - def TypeRef join(RuleEnvironment G, TypeRef... typeRefs) { - joinComputer.join(G, Arrays.asList(typeRefs)) - } - - /** - * Returns the join, sometimes called least common super type (LCST), - * of the given types. - * @see JoinComputer#join(RuleEnvironment, Iterable) - */ - def TypeRef join(RuleEnvironment G, Iterable typeRefsToJoin) { - joinComputer.join(G, typeRefsToJoin) - } - - /** - * Convenience method calling {@link meet(RuleEnvironment, Iterable)} with - * type references inside an array. - */ - def TypeRef meet(RuleEnvironment G, TypeRef... typeRefs) { - meetComputer.meet(G, Arrays.asList(typeRefs)) - } - - /** - * Returns the meet (first common sub type) of the given types - * @see MeetComputer#meet(RuleEnvironment, Iterable) - */ - def TypeRef meet(RuleEnvironment G, Iterable typeRefs) { - meetComputer.meet(G, typeRefs) - } - - def boolean isSubtypeFunction(RuleEnvironment G, FunctionTypeExprOrRef left, FunctionTypeExprOrRef right) { - return subtypeComputer.isSubtypeFunction(G, left, right) - } - - def StructuralTypingResult isStructuralSubtype(RuleEnvironment G,TypeRef left, TypeRef right) { - return structuralTypingComputer.isStructuralSubtype(G, left, right); - } - def public List reduceMembers(RuleEnvironment G, TypeRef leftTypeRef, TMember left, TMember right, StructTypingInfo info) { - return structuralTypingComputer.reduceMembers(G, leftTypeRef, left, right, info); - } - - /** @see ExpectedTypeComputer#getExpectedTypeOfReturnValueExpression(RuleEnvironment,Expression) */ - def TypeRef getExpectedTypeOfReturnValueExpression(RuleEnvironment G, Expression returnValueExpr) { - return expectedTypeCompuer.getExpectedTypeOfReturnValueExpression(G, returnValueExpr); - } - - /** @see ExpectedTypeComputer#getExpectedTypeOfYieldValueExpression(RuleEnvironment,YieldExpression,Expression) */ - def TypeRef getExpectedTypeOfYieldValueExpression(RuleEnvironment G, YieldExpression yieldExpr, TypeRef exprTypeRef) { - return expectedTypeCompuer.getExpectedTypeOfYieldValueExpression(G, yieldExpr, exprTypeRef); - } - - /** @see ExpectedTypeComputer#getExpectedTypeOfYieldValueExpression(RuleEnvironment,YieldExpression,Expression) */ - def TypeRef getExpectedTypeOfFunctionOrFieldAccessor(RuleEnvironment G, FunctionOrFieldAccessor fofa) { - return expectedTypeCompuer.getExpectedTypeOfFunctionOrFieldAccessor(G, fofa); - } - - /** @see ThisTypeComputer#getThisTypeAtLocation(RuleEnvironment,EObject) */ - def TypeRef getThisTypeAtLocation(RuleEnvironment G, EObject location) { - return thisTypeComputer.getThisTypeAtLocation(G, location); - } - - /** @see IterableComputer#extractIterableElementTypes(RuleEnvironment, TypeRef) */ - public def List extractIterableElementTypes(RuleEnvironment G, TypeRef typeRef) { - return iterableComputer.extractIterableElementTypes(G, typeRef); - } - - /** @see IterableComputer#extractIterableElementType(RuleEnvironment, TypeRef, boolean) */ - public def TypeRef extractIterableElementType(RuleEnvironment G, TypeRef typeRef, boolean includeAsyncIterable) { - return iterableComputer.extractIterableElementType(G, typeRef, includeAsyncIterable); - } - - /** @see TypeAliasComputer#resolveTypeAliasFlat(RuleEnvironment, TypeRef) */ - public def TypeRef resolveTypeAliasFlat(RuleEnvironment G, TypeRef typeRef) { - return typeAliasComputer.resolveTypeAliasFlat(G, typeRef); - } - - /** @see TypeAliasComputer#resolveTypeAliases(RuleEnvironment, TypeRef) */ - public def TypeRef resolveTypeAliases(RuleEnvironment G, TypeRef typeRef) { - return typeAliasComputer.resolveTypeAliases(G, typeRef); - } - - /** @see TypeAliasComputer#resolveTypeAliases(RuleEnvironment, TypeArgument) */ - public def TypeArgument resolveTypeAliases(RuleEnvironment G, TypeArgument typeArg) { - return typeAliasComputer.resolveTypeAliases(G, typeArg); - } - - - - - // ***************************************************************************************************** - // small utility methods that do not have their own strategy class - // ***************************************************************************************************** - - public def boolean allEqualType(RuleEnvironment G, TypeRef... typeRefs) { - val len = typeRefs.size; - if(len>=2) { - val firstRef = typeRefs.head; - for(var i=1;inull. - * @param type either subtype of TFunction, of FieldAccessor, or of FunctionTypeExprOrRef can have a declared this - * type ("@This") - * @return declaredThisType if any, null in other cases. - */ - public static def TypeRef getDeclaredThisType(IdentifiableElement type) { - return switch ( type ) { - TFunction: { - type.declaredThisType - } - TGetter: { - type.declaredThisType - } - TSetter: { - type.declaredThisType - } - FunctionTypeExprOrRef: { - type.declaredThisType - } - default: - null - } - } - - /** - * Binds and substitutes the given {@link ThisTypeRef this type reference} after wrapping the - * given rule environment. - * - *

- * For instance after passing a {@code ~~this} type reference into a method in the context of container - * {@code class A}, the type reference argument will be bound to {@code this[A]} and finally will be substituted - * with {@code ~~this[A]} type reference. That will be the return value of the method. - * - * @param G - * the rule environment that will be wrapped for the operation. - * @param location - * location within the AST for which to create a BoundThisTypeRef. Same as the argument 'location' of - * judgment 'thisTypeRef' in Xsemantics. - * @param typeRef - * type reference to substitute; this can either be an unbound ThisTypeRef or any other kind of TypeRef that - * contains one or more unbound ThisTypeRefs. Need not be contained in the AST (as usual for type references). - */ - public def bindAndSubstituteThisTypeRef(RuleEnvironment G, EObject location, TypeRef typeRef) { - // create a BoundThisTypeRef for given location - val boundThisTypeRef = getThisTypeAtLocation(G, location); - val localG = G.wrap; - localG.setThisBinding(boundThisTypeRef); - // substitute all unbound ThisTypeRefs with the newly created BoundThisTypeRef - return ts.substTypeVariables(localG, typeRef); - } - - @Data - public static class Callable { - /** The actual type reference that contributed function/method. Used for error reporting. */ - TypeRef callableTypeRef - /** - * The signature of the function/method being invoked. Used for argument checking and to obtain - * the type of the return value. If absent, the invocation is possible, but no information about - * the parameters or the return value is available (e.g. when invoking values of built-in type - * {@code Function}). - */ - Optional signatureTypeRef - /** - * Tells whether the function/method being invoked is {@link TypeRef#isDynamic() dynamic}. - */ - boolean dynamic - } - - /** - * Checks if a value of the given type is "callable" (i.e. can be invoked with a call expression). - * If so, returns an instance of class {@link Callable} with further information; if not, returns - * null. - */ - def public Callable getCallableTypeRef(RuleEnvironment G, TypeRef typeRef) { - val result = getCallableTypeRefs(G, typeRef); - return if (result.size === 1) result.get(0); - } - - def public List getCallableTypeRefs(RuleEnvironment G, TypeRef typeRef) { - if (typeRef instanceof UnionTypeExpression) { - // TODO implement special handling for unions - } else if (typeRef instanceof IntersectionTypeExpression) { - // TODO improve special handling for intersections - val result = newArrayList; - var foundWithoutSignature = false; - var foundWithoutSignatureDynamic = false; - for (currTypeRef : typeRef.typeRefs) { - val currCallable = internalGetCallableTypeRef(G, currTypeRef); - if (currCallable !== null) { - if (!currCallable.signatureTypeRef.isPresent()) { - foundWithoutSignature = true; - foundWithoutSignatureDynamic = foundWithoutSignatureDynamic || currCallable.dynamic; - } else { - result += currCallable; - } - } - } - if (result.empty && foundWithoutSignature) { - return Collections.singletonList(new Callable(typeRef, Optional.absent(), foundWithoutSignatureDynamic)); - } - return result; - } - val result = internalGetCallableTypeRef(G, typeRef); - if (result !== null) { - return Collections.singletonList(result); - } - return Collections.emptyList(); - } - - def private Callable internalGetCallableTypeRef(RuleEnvironment G, TypeRef typeRef) { - if (typeRef instanceof UnknownTypeRef) { - return null; - } - if (typeRef instanceof FunctionTypeExprOrRef) { - return new Callable(typeRef, Optional.of(typeRef), typeRef.dynamic); - } - if (isClassConstructorFunction(G, typeRef)) { - // don't allow direct invocation of class constructors - val callableCtor = getCallableClassConstructorFunction(G, typeRef); - if (callableCtor !== null) { - // exception: this is a class that provides a call signature - return new Callable(typeRef, Optional.of(TypeUtils.createTypeRef(callableCtor) as FunctionTypeRef), typeRef.dynamic); - } - return null; - } - val callSig = getCallSignature(G, typeRef); - if (callSig !== null) { - return new Callable(typeRef, Optional.of(TypeUtils.createTypeRef(callSig) as FunctionTypeRef), typeRef.dynamic); - } - if (ts.subtypeSucceeded(G, typeRef, G.functionTypeRef) - || ts.subtypeSucceeded(G, typeRef, G.structuralFunctionTypeRef) - || (typeRef.dynamic && ts.subtypeSucceeded(G, G.functionTypeRef, typeRef))) { - return new Callable(typeRef, Optional.absent(), typeRef.dynamic); - } - return null; - } - - @Data - public static class Newable { - /** The actual type reference that contributed constructor or construct signature. Used for error reporting. */ - TypeRef newableTypeRef; - /** The constructor or construct signature. Used for argument checking. Can be null. */ - TMethod ctorOrConstructSig; - /** The type of the newly created instance. */ - TypeRef instanceTypeRef; - } - - def public Newable getNewableTypeRef(RuleEnvironment G, NewExpression newExpr, boolean ignoreConstructSignatures) { - val calleeTypeRef = ts.type(G, newExpr.callee); - return getNewableTypeRef(G, calleeTypeRef, newExpr, ignoreConstructSignatures); - } - - /** - * Checks if a value of the given type is "newable" (i.e. can be instantiated with keyword "new"). - * If so, returns an instance of class {@link Newable) with further information; if not, returns - * null. - */ - def public Newable getNewableTypeRef(RuleEnvironment G, TypeRef typeRef, NewExpression newExpr, boolean ignoreConstructSignatures) { - val result = getNewableTypeRefs(G, typeRef, newExpr, ignoreConstructSignatures); - return if (result.size === 1) result.get(0); - } - - def public List getNewableTypeRefs(RuleEnvironment G, TypeRef typeRef, NewExpression newExpr, boolean ignoreConstructSignatures) { - - if (typeRef instanceof UnionTypeExpression) { - val newables = newArrayList; - for (currTypeRef : typeRef.typeRefs) { - val curr = internalGetNewableTypeRef(G, currTypeRef, newExpr, ignoreConstructSignatures); - if (curr !== null) { - newables += curr; - } - } - val List constructSigsReturn = new ArrayList(); - val List resTypeRefs = new ArrayList(); - for (newable : newables) { - resTypeRefs += newable.instanceTypeRef; - if (newable.ctorOrConstructSig !== null) { - constructSigsReturn += newable.ctorOrConstructSig.returnTypeRef - } - } - - // use non-simplified because union with any+ will remove other types that would give additional info to the user - val resTypeRef = TypeUtils.createNonSimplifiedUnionType(resTypeRefs); - val constructSig = TypesFactory.eINSTANCE.createTMethod(); - constructSig.returnTypeRef = TypeUtils.createNonSimplifiedUnionType(constructSigsReturn); - val vArgs = TypesFactory.eINSTANCE.createTFormalParameter(); - constructSig.fpars += vArgs; - vArgs.variadic = true; - vArgs.typeRef = G.anyTypeRefDynamic; - // TODO improve merging of construct signatures - - return Collections.singletonList(new Newable(typeRef, constructSig, resTypeRef)); - - } else if (typeRef instanceof IntersectionTypeExpression) { - // TODO improve special handling for intersections - val typeRef2 = simplifyComputer.simplify(G, typeRef, true); - if (typeRef2 instanceof IntersectionTypeExpression) { - val result = newArrayList; - for (currTypeRef : typeRef2.typeRefs) { - val curr = internalGetNewableTypeRef(G, currTypeRef, newExpr, ignoreConstructSignatures); - if (curr !== null) { - result += curr; - } - } - return result; - } else { - return getNewableTypeRefs(G, typeRef2, newExpr, ignoreConstructSignatures); - } - } - val result = internalGetNewableTypeRef(G, typeRef, newExpr, ignoreConstructSignatures); - if (result !== null) { - return Collections.singletonList(result); - } - return Collections.emptyList(); - } - - def private Newable internalGetNewableTypeRef(RuleEnvironment G, TypeRef calleeTypeRef, NewExpression newExpr, boolean ignoreConstructSignatures) { - if (calleeTypeRef instanceof TypeTypeRef) { - var ctor = null as TMethod; - val staticType = getStaticType(G, calleeTypeRef, true); - if (staticType instanceof ContainerType) { - ctor = containerTypesHelper.fromContext(G.contextResource).findConstructor(staticType); - } - val instanceTypeRef = createTypeRefFromStaticType(G, calleeTypeRef, newExpr); - return new Newable(calleeTypeRef, ctor, instanceTypeRef) - } - if (G.isAnyDynamic(calleeTypeRef)) { - val constructSig = TypesFactory.eINSTANCE.createTMethod(); - constructSig.returnTypeRef = G.anyTypeRefDynamic; - val vArgs = TypesFactory.eINSTANCE.createTFormalParameter(); - constructSig.fpars += vArgs; - vArgs.variadic = true; - vArgs.typeRef = G.anyTypeRefDynamic; - - return new Newable(calleeTypeRef, constructSig, G.anyTypeRefDynamic); - } - if (!ignoreConstructSignatures) { - val constructSig = getConstructSignature(G, calleeTypeRef); - if (constructSig !== null) { - val returnTypeRef = constructSig.getReturnTypeRef(); - if (returnTypeRef !== null && !TypeUtils.isVoid(returnTypeRef)) { - val G2 = wrap(G); - addSubstitutions(G2, newExpr, constructSig); - val returnTypeRefSubst = ts.substTypeVariablesWithFullCapture(G2, returnTypeRef); - return new Newable(calleeTypeRef, constructSig, returnTypeRefSubst); - } - } - } - return null; - } - - /** - * Checks if a value of type typeRef is a class constructor function. - */ - def public boolean isClassConstructorFunction(RuleEnvironment G, TypeRef typeRef) { - val declaredType = typeRef.declaredType; - if(declaredType instanceof TMethod) { - if(declaredType.isConstructor) - return true; - } - if(typeRef instanceof FunctionTypeExprOrRef) { - val ft = typeRef.functionType; - if(ft instanceof TMethod) { - if(ft.isConstructor) - return true; - } - } - if(typeRef instanceof TypeTypeRef) { - val cls = getStaticType(G, typeRef); - if(cls instanceof TClass) - return true; - } - return false; - } - def public TMethod getCallableClassConstructorFunction(RuleEnvironment G, TypeRef typeRef) { - var Type type = null; - val declaredType = typeRef.declaredType; - if(declaredType instanceof TMethod) { - if(declaredType.isConstructor) - type = declaredType.containingType; - } - if(typeRef instanceof FunctionTypeExprOrRef) { - val ft = typeRef.functionType; - if(ft instanceof TMethod) { - if(ft.isConstructor) - type = ft.containingType; - } - } - if(typeRef instanceof TypeTypeRef) { - val cls = getStaticType(G, typeRef); - if(cls instanceof TClass) - type = cls; - } - if(type instanceof TClass) { - // note: "callable constructors" (i.e. call signatures in classes) are not inherited - // and cannot appear in StructuralTypeRefs, so no need for ContainerTypesHelper or - // checking for TStructuralType here: - return type.callSignature; - } - return null; - } - - def public TMethod getCallSignature(RuleEnvironment G, TypeRef calleeTypeRef) { - return getCallSignature(G.contextResource, calleeTypeRef); - } - - def public TMethod getCallSignature(Resource context, TypeRef calleeTypeRef) { - return getCallConstructSignature(context, calleeTypeRef, false); - } - - def public TMethod getConstructSignature(RuleEnvironment G, TypeRef calleeTypeRef) { - return getConstructSignature(G.contextResource, calleeTypeRef); - } - - def public TMethod getConstructSignature(Resource context, TypeRef calleeTypeRef) { - return getCallConstructSignature(context, calleeTypeRef, true); - } - - /** - * NOTE: does not cover "callable constructors" (i.e. call signatures in classes); use method - * {@link #getCallableClassConstructorFunction(RuleEnvironment,TypeRef)} for this purpose. - */ - def private TMethod getCallConstructSignature(Resource context, TypeRef calleeTypeRef, boolean searchConstructSig) { - val declType = calleeTypeRef.declaredType; - if (declType instanceof TInterface) { - return if (searchConstructSig) { - containerTypesHelper.fromContext(context).findConstructSignature(declType); - } else { - containerTypesHelper.fromContext(context).findCallSignature(declType); - }; - } - if (calleeTypeRef instanceof StructuralTypeRef) { - val structType = calleeTypeRef.structuralType; - if (structType !== null) { - return if (searchConstructSig) { - structType.constructSignature - } else { - structType.callSignature - }; - } - } - return null; - } - - def public FunctionTypeExprOrRef getFunctionTypeExprOrRef(RuleEnvironment G, TypeRef typeRef) { - if (typeRef instanceof FunctionTypeExprOrRef) { - return typeRef; - } - val callable = getCallableTypeRef(G, typeRef); - if (callable !== null) { - return callable.signatureTypeRef.orNull; - } - return null; - } - - /** Same as {@link #getStaticType(RuleEnvironment, TypeTypeRef, boolean)} without resolving type variables. */ - def public Type getStaticType(RuleEnvironment G, TypeTypeRef typeTypeRef) { - return getStaticType(G, typeTypeRef, false); - } - - /** - * Returns the so-called "static type" of the given {@link TypeTypeRef} or null if not - * available. Iff {@code resolveTypeVariables} is true, then type variables will be resolved - * (i.e. replaced by their explicit or implicit upper bound). - *

- * Formerly, this was a utility operation in {@code TypeRefs.xcore} but since the introduction of wildcards in - * {@code TypeTypeRef}s the 'upperBound' judgment (and thus a RuleEnvironment) is required to compute this - * and hence it was moved here. - */ - def public Type getStaticType(RuleEnvironment G, TypeTypeRef typeTypeRef, boolean resolveTypeVariables) { - return getStaticTypeRef(G, typeTypeRef, resolveTypeVariables)?.declaredType; // will return null if #getStaticTypeRef() is not of type ParameterizedTypeRef - } - - def public TypeRef getStaticTypeRef(RuleEnvironment G, TypeTypeRef typeTypeRef) { - return getStaticTypeRef(G, typeTypeRef, false); - } - - def public TypeRef getStaticTypeRef(RuleEnvironment G, TypeTypeRef typeTypeRef, boolean resolveTypeVariables) { - val typeArg = typeTypeRef.typeArg; - val typeArgUB = if (resolveTypeVariables) { - ts.upperBoundWithReopenAndResolveTypeVars(G, typeArg) - } else { - ts.upperBoundWithReopen(G, typeArg) - }; - return typeArgUB; - } - - def public TypeRef createTypeRefFromStaticType(RuleEnvironment G, TypeTypeRef ctr, ParameterizedAccess paramAccess) { - return createTypeRefFromStaticType(G, ctr, paramAccess.typeArgs.map[typeRef]); - } - - /** - * Creates a parameterized type ref to the wrapped static type of a TypeTypeRef, configured with the given - * TypeArguments. Returns UnknownTypeRef if the static type could not be retrieved (e.g. unbound This-Type). - */ - def public TypeRef createTypeRefFromStaticType(RuleEnvironment G, TypeTypeRef ctr, TypeArgument... typeArgs) { - val typeRef = getStaticTypeRef(G, ctr); - val type = typeRef?.declaredType; - if (type !== null) { - return TypeExtensions.ref(type, typeArgs); - } - return TypeRefsFactory.eINSTANCE.createUnknownTypeRef; - } - - /** - * This method computes the set of all subtypes in the set of TypeRefs. - * It does not copy the TypeRefs! - */ - def List getSubtypesOnly(RuleEnvironment G, TypeRef... typeRefs) { - val intersectTRs = new LinkedList(); - - for (s : typeRefs) { - if (! intersectTRs.exists[ts.subtypeSucceeded(G, it, s)]) { - Iterables.removeIf(intersectTRs, [ts.subtypeSucceeded(G, s, it)]); - intersectTRs.add(s) - } - } - - return intersectTRs - } - - /** - * This method computes the set of all super types in the set of TypeRefs. - * It does not copy the TypeRefs! - */ - def List getSuperTypesOnly(RuleEnvironment G, TypeRef... typeRefs) { - val unionTRs = new LinkedList(); - - for (s : typeRefs) { - if (! unionTRs.exists[ts.subtypeSucceeded(G, s, it)]) { - Iterables.removeIf(unionTRs, [ts.subtypeSucceeded(G, s, it)]); - unionTRs.add(s) - } - } - - return unionTRs - } - - - /** - * From any expression within a generator function or method, the type TNext is returned (referring to the - * actual (outer) return type, which is {@code [Async]Generator}). - */ - def TypeRef getActualGeneratorReturnType(RuleEnvironment G, Expression expr) { - val funDef = EcoreUtil2.getContainerOfType(expr?.eContainer, FunctionDefinition); - val G2 = G.wrap; - val myThisTypeRef = getThisTypeAtLocation(G, expr); - G2.setThisBinding(myThisTypeRef); // takes the real-this type even if it is a type{this} reference. - - if (funDef === null || !funDef.isGenerator) - return null; // yield only occurs in generator functions - - val tFun = funDef.definedType; - if (tFun instanceof TFunction) { - val actualReturnTypeRef = tFun.returnTypeRef; - val scope = G.getPredefinedTypes().builtInTypeScope; - if (TypeUtils.isGeneratorOrAsyncGenerator(actualReturnTypeRef, scope)) { - return actualReturnTypeRef; - } - } - return TypeRefsFactory.eINSTANCE.createUnknownTypeRef; - } - - /** - * Given a {@link TypeRef} to a {@code [Async]Generator} class, this method returns TYield, if existent. - */ - def TypeRef getGeneratorTYield(RuleEnvironment G, TypeRef generatorTypeRef) { - var TypeRef yieldTypeRef = null; - if (generatorTypeRef.declaredTypeArgs.size >= 1) { - val yieldTypeArg = generatorTypeRef.declaredTypeArgs.get(0); - if (yieldTypeArg !== null) - yieldTypeRef = ts.upperBound(G, yieldTypeArg); // take upper bound to get rid of Wildcard, etc. - } else { - yieldTypeRef = G.generatorType.typeVars.get(0).defaultArgument; - } - return yieldTypeRef; - } - - /** - * Given a {@link TypeRef} to a {@code [Async]Generator} class, this method returns TReturn, if existent. - */ - def TypeRef getGeneratorTReturn(RuleEnvironment G, TypeRef generatorTypeRef) { - var TypeRef returnTypeRef = null; - if (generatorTypeRef.declaredTypeArgs.size >= 2) { - val returnTypeArg = generatorTypeRef.declaredTypeArgs.get(1); - if (returnTypeArg !== null) - returnTypeRef = ts.upperBound(G, returnTypeArg); // take upper bound to get rid of Wildcard, etc. - } else { - returnTypeRef = G.generatorType.typeVars.get(1).defaultArgument; - } - return returnTypeRef; - } - - /** - * Given a {@link TypeRef} to a {@code [Async]Generator} class, this method returns TNext, if existent. - */ - def TypeRef getGeneratorTNext(RuleEnvironment G, TypeRef generatorTypeRef) { - var TypeRef nextTypeRef = null; - if (generatorTypeRef.declaredTypeArgs.size >= 3) { - val nextTypeArg = generatorTypeRef.declaredTypeArgs.get(2); - if (nextTypeArg !== null) - nextTypeRef = ts.upperBound(G, nextTypeArg); // take upper bound to get rid of Wildcard, etc. - } else { - nextTypeRef = G.generatorType.typeVars.get(2).defaultArgument; - } - return nextTypeRef; - } -}