Ref<PyType> (@NotNull PyExpression typeHint, @Nullable PyQualifiedNameOwner alias, @NotNull PsiElement resolved, @NotNull Context context) { if (alias != null) { if (context.getTypeAliasStack().contains(alias)) { // Recursive types are not yet supported return null; } context.getTypeAliasStack().add(alias); } try { final Ref<PyType> typeFromParenthesizedExpression = getTypeFromParenthesizedExpression(resolved, context); if (typeFromParenthesizedExpression != null) { return typeFromParenthesizedExpression; } final PyType unionType = getUnionType(resolved, context); if (unionType != null) { return Ref.create(unionType); } final PyType concatenateType = getConcatenateType(resolved, context); if (concatenateType != null) { return Ref.create(concatenateType); } final Ref<PyType> optionalType = getOptionalType(resolved, context); if (optionalType != null) { return optionalType; } final PyType callableType = getCallableType(resolved, context); if (callableType != null) { return Ref.create(callableType); } final Ref<PyType> classVarType = unwrapTypeModifier(resolved, context, CLASS_VAR); if (classVarType != null) { return classVarType; } final Ref<PyType> classObjType = getClassObjectType(resolved, context); if (classObjType != null) { return classObjType; } final Ref<PyType> finalType = unwrapTypeModifier(resolved, context, FINAL, FINAL_EXT); if (finalType != null) { return finalType; } final Ref<PyType> annotatedType = getAnnotatedType(resolved, context); if (annotatedType != null) { return annotatedType; } final Ref<PyType> requiredOrNotRequiredType = getRequiredOrNotRequiredType(resolved, context); if (requiredOrNotRequiredType != null) { return requiredOrNotRequiredType; } final Ref<PyType> literalStringType = getLiteralStringType(resolved, context); if (literalStringType != null) { return literalStringType; } final Ref<PyType> literalType = getLiteralType(resolved, context); if (literalType != null) { return literalType; } final Ref<PyType> typeAliasType = getExplicitTypeAliasType(resolved); if (typeAliasType != null) { return typeAliasType; } final PyType parameterizedType = getParameterizedType(resolved, context); if (parameterizedType != null) { return Ref.create(parameterizedType); } final PyType collection = getCollection(resolved, context.getTypeContext()); if (collection != null) { return Ref.create(collection); } final PyType typeParameter = getTypeParameterTypeFromDeclaration(resolved, context); if (typeParameter != null) { return Ref.create(anchorTypeParameter(typeHint, typeParameter, context)); } final PyType unpackedType = getUnpackedType(resolved, context.getTypeContext()); if (unpackedType != null) { return Ref.create(unpackedType); } final PyType typeParameterType = getTypeParameterTypeFromTypeParameter(resolved, context); if (typeParameterType != null) { return Ref.create(typeParameterType); } final PyType paramSpecType = getParamSpecType(resolved, context); if (paramSpecType != null) { return Ref.create(anchorTypeParameter(typeHint, paramSpecType, context)); } final PyType stringBasedType = getStringLiteralType(resolved, context); if (stringBasedType != null) { return Ref.create(stringBasedType); } final Ref<PyType> anyType = getAnyType(resolved); if (anyType != null) { return anyType; } // We perform chained resolve only for actual aliases as tryResolvingWithAliases() returns the passed-in // expression both when it's not a reference expression and when it's failed to resolve it, hence we might // hit SOE for mere unresolved references in the latter case. if (alias != null) { final Ref<PyType> aliasedType = getAliasedType(resolved, context); if (aliasedType != null) { return aliasedType; } } final PyType typedDictType = PyTypedDictTypeProvider.Companion.getTypedDictTypeForResolvedElement(resolved, context.getTypeContext()); if (typedDictType != null) { return Ref.create(typedDictType); } final Ref<PyType> classType = getClassType(resolved, context.getTypeContext()); if (classType != null) { return classType; } final Ref<PyType> unionTypeFromBinaryOr = getTypeFromBinaryExpression(resolved, context); if (unionTypeFromBinaryOr != null) { return unionTypeFromBinaryOr; } final Ref<PyType> selfType = getSelfType(resolved, typeHint, context); if (selfType != null) { return selfType; } return null; } finally { if (alias != null) { context.getTypeAliasStack().remove(alias); } } }