@Nullable
  public static PyType getType(@NotNull PsiElement resolved, @NotNull List<PyType> elementTypes) {
    final String qualifiedName = getQualifiedName(resolved);

    final List<Integer> paramListTypePositions = new ArrayList<>();
    final List<Integer> ellipsisTypePositions = new ArrayList<>();
    for (int i = 0; i < elementTypes.size(); i++) {
      final PyType type = elementTypes.get(i);
      if (type instanceof PyTypeParser.ParameterListType) {
        paramListTypePositions.add(i);
      } else if (type instanceof PyTypeParser.EllipsisType) {
        ellipsisTypePositions.add(i);
      }
    }

    if (!paramListTypePositions.isEmpty()) {
      if (!("typing.Callable".equals(qualifiedName) && paramListTypePositions.equals(list(0)))) {
        return null;
      }
    }
    if (!ellipsisTypePositions.isEmpty()) {
      if (!("typing.Callable".equals(qualifiedName) && ellipsisTypePositions.equals(list(0))
          || "typing.Tuple".equals(qualifiedName)
              && ellipsisTypePositions.equals(list(1))
              && elementTypes.size() == 2)) {
        return null;
      }
    }

    if ("typing.Union".equals(qualifiedName)) {
      return PyUnionType.union(elementTypes);
    }
    if ("typing.Optional".equals(qualifiedName) && elementTypes.size() == 1) {
      return PyUnionType.union(elementTypes.get(0), PyNoneType.INSTANCE);
    }
    if ("typing.Callable".equals(qualifiedName) && elementTypes.size() == 2) {
      final PyTypeParser.ParameterListType paramList =
          as(elementTypes.get(0), PyTypeParser.ParameterListType.class);
      if (paramList != null) {
        return new PyCallableTypeImpl(paramList.getCallableParameters(), elementTypes.get(1));
      }
      if (elementTypes.get(0) instanceof PyTypeParser.EllipsisType) {
        return new PyCallableTypeImpl(null, elementTypes.get(1));
      }
    }
    if ("typing.Tuple".equals(qualifiedName)) {
      if (elementTypes.size() > 1 && elementTypes.get(1) instanceof PyTypeParser.EllipsisType) {
        return PyTupleType.createHomogeneous(resolved, elementTypes.get(0));
      }
      return PyTupleType.create(resolved, elementTypes);
    }
    final PyType builtinCollection = getBuiltinCollection(resolved);
    if (builtinCollection instanceof PyClassType) {
      final PyClassType classType = (PyClassType) builtinCollection;
      return new PyCollectionTypeImpl(classType.getPyClass(), false, elementTypes);
    }
    return null;
  }
 @Nullable
 private PyType resolveQualifierType(
     @NotNull List<Token<PyElementType>> tokens,
     @NotNull PyFile file,
     @NotNull TypeEvalContext context,
     @NotNull Map<TextRange, PyType> types,
     @NotNull Map<PyType, TextRange> fullRanges,
     @NotNull Map<PyType, PyImportElement> imports) {
   if (tokens.isEmpty()) {
     return null;
   }
   final Token<PyElementType> firstToken = tokens.get(0);
   final String firstText = firstToken.getText().toString();
   final TextRange firstRange = firstToken.getRange();
   final List<RatedResolveResult> resolveResults = file.multiResolveName(firstText);
   if (resolveResults.isEmpty()) {
     return getImplicitlyResolvedType(tokens, context, types, fullRanges, firstRange);
   }
   final List<PyType> members = Lists.newArrayList();
   for (RatedResolveResult result : resolveResults) {
     final PsiElement resolved = result.getElement();
     PyType type = null;
     if (resolved instanceof PyTargetExpression) {
       type =
           PyTypingTypeProvider.getTypeFromTargetExpression(
               (PyTargetExpression) resolved, context);
     }
     if (type == null && resolved instanceof PyTypedElement) {
       type = context.getType((PyTypedElement) resolved);
     }
     if (type != null) {
       if (!allowResolveToType(type)) {
         continue;
       }
       if (type instanceof PyClassLikeType) {
         type = ((PyClassLikeType) type).toInstance();
       }
       types.put(firstRange, type);
       fullRanges.put(type, firstRange);
       for (PyFromImportStatement fromImportStatement : file.getFromImports()) {
         for (PyImportElement importElement : fromImportStatement.getImportElements()) {
           if (firstText.equals(importElement.getVisibleName())) {
             imports.put(type, importElement);
           }
         }
       }
       for (PyImportElement importElement : file.getImportTargets()) {
         if (firstText.equals(importElement.getVisibleName())) {
           imports.put(type, importElement);
         }
       }
     }
     members.add(type);
   }
   if (!members.isEmpty()) {
     tokens.remove(0);
   }
   return PyUnionType.union(members);
 }
 @Nullable
 private static PyType getType(@NotNull PyExpression expression, @NotNull Context context) {
   final List<PyType> members = Lists.newArrayList();
   for (PsiElement resolved : tryResolving(expression, context.getTypeContext())) {
     members.add(getTypeForResolvedElement(resolved, context));
   }
   return PyUnionType.union(members);
 }
 @Nullable
 private static PyType getGenericTypeBound(
     @NotNull PyExpression[] typeVarArguments, @NotNull Context context) {
   final List<PyType> types = new ArrayList<>();
   for (int i = 1; i < typeVarArguments.length; i++) {
     types.add(getType(typeVarArguments[i], context));
   }
   return PyUnionType.union(types);
 }
  public PyType getType(@NotNull TypeEvalContext context, @NotNull TypeEvalContext.Key key) {
    if (!TypeEvalStack.mayEvaluate(this)) {
      return null;
    }
    try {
      final boolean qualified = isQualified();
      if (!qualified) {
        String name = getReferencedName();
        if (PyNames.NONE.equals(name)) {
          return PyNoneType.INSTANCE;
        }
      }
      PyType type = getTypeFromProviders(context);
      if (type != null) {
        return type;
      }
      if (qualified) {
        PyType maybe_type = PyUtil.getSpecialAttributeType(this, context);
        if (maybe_type != null) return maybe_type;
        Ref<PyType> typeOfProperty = getTypeOfProperty(context);
        if (typeOfProperty != null) {
          return typeOfProperty.get();
        }
      }
      final PsiPolyVariantReference reference =
          getReference(PyResolveContext.noImplicits().withTypeEvalContext(context));
      final List<PsiElement> targets = PyUtil.multiResolveTopPriority(reference);
      if (targets.isEmpty()) {
        return getQualifiedReferenceTypeByControlFlow(context);
      }

      final List<PyType> members = new ArrayList<PyType>();
      for (PsiElement target : targets) {
        if (target == this || target == null) {
          continue;
        }
        if (!target.isValid()) {
          LOG.error(
              "Reference "
                  + this
                  + " resolved to invalid element "
                  + target
                  + " (text="
                  + target.getText()
                  + ")");
          continue;
        }
        members.add(getTypeFromTarget(target, context, this));
      }

      return PyUnionType.union(members);
    } finally {
      TypeEvalStack.evaluated(this);
    }
  }
 @Nullable
 private static PyType getOptionalTypeFromDefaultNone(
     @NotNull PyNamedParameter param, @NotNull PyType type, @NotNull TypeEvalContext context) {
   final PyExpression defaultValue = param.getDefaultValue();
   if (defaultValue != null) {
     final PyType defaultType = context.getType(defaultValue);
     if (defaultType instanceof PyNoneType) {
       return PyUnionType.union(type, defaultType);
     }
   }
   return null;
 }
 @Nullable
 private static PyType getUnionType(@NotNull PsiElement element, @NotNull Context context) {
   if (element instanceof PySubscriptionExpression) {
     final PySubscriptionExpression subscriptionExpr = (PySubscriptionExpression) element;
     final PyExpression operand = subscriptionExpr.getOperand();
     final Collection<String> operandNames =
         resolveToQualifiedNames(operand, context.getTypeContext());
     if (operandNames.contains("typing.Union")) {
       return PyUnionType.union(getIndexTypes(subscriptionExpr, context));
     }
   }
   return null;
 }
 @Override
 public void visitPyReturnStatement(PyReturnStatement node) {
   if (PsiTreeUtil.getParentOfType(node, ScopeOwner.class, true) == myFunction) {
     final PyExpression expr = node.getExpression();
     PyType returnType;
     returnType = expr == null ? PyNoneType.INSTANCE : myContext.getType(expr);
     if (!myHasReturns) {
       myResult = returnType;
       myHasReturns = true;
     } else {
       myResult = PyUnionType.union(myResult, returnType);
     }
   }
 }
  @Nullable
  private Ref<? extends PyType> getYieldStatementType(@NotNull final TypeEvalContext context) {
    Ref<PyType> elementType = null;
    final PyBuiltinCache cache = PyBuiltinCache.getInstance(this);
    final PyStatementList statements = getStatementList();
    final Set<PyType> types = new LinkedHashSet<>();
    statements.accept(
        new PyRecursiveElementVisitor() {
          @Override
          public void visitPyYieldExpression(PyYieldExpression node) {
            final PyExpression expr = node.getExpression();
            final PyType type = expr != null ? context.getType(expr) : null;
            if (node.isDelegating() && type instanceof PyCollectionType) {
              final PyCollectionType collectionType = (PyCollectionType) type;
              // TODO: Select the parameter types that matches T in Iterable[T]
              final List<PyType> elementTypes = collectionType.getElementTypes(context);
              types.add(elementTypes.isEmpty() ? null : elementTypes.get(0));
            } else {
              types.add(type);
            }
          }

          @Override
          public void visitPyFunction(PyFunction node) {
            // Ignore nested functions
          }
        });
    final int n = types.size();
    if (n == 1) {
      elementType = Ref.create(types.iterator().next());
    } else if (n > 0) {
      elementType = Ref.create(PyUnionType.union(types));
    }
    if (elementType != null) {
      final PyClass generator = cache.getClass(PyNames.FAKE_GENERATOR);
      if (generator != null) {
        final List<PyType> parameters =
            Arrays.asList(elementType.get(), null, getReturnStatementType(context));
        return Ref.create(new PyCollectionTypeImpl(generator, false, parameters));
      }
    }
    if (!types.isEmpty()) {
      return Ref.create(null);
    }
    return null;
  }
예제 #10
0
  @Nullable
  private Ref<? extends PyType> getYieldStatementType(@NotNull final TypeEvalContext context) {
    Ref<PyType> elementType = null;
    final PyBuiltinCache cache = PyBuiltinCache.getInstance(this);
    final PyStatementList statements = getStatementList();
    final Set<PyType> types = new LinkedHashSet<PyType>();
    if (statements != null) {
      statements.accept(
          new PyRecursiveElementVisitor() {
            @Override
            public void visitPyYieldExpression(PyYieldExpression node) {
              final PyType type = context.getType(node);
              if (node.isDelegating() && type instanceof PyCollectionType) {
                final PyCollectionType collectionType = (PyCollectionType) type;
                types.add(collectionType.getElementType(context));
              } else {
                types.add(type);
              }
            }

            @Override
            public void visitPyFunction(PyFunction node) {
              // Ignore nested functions
            }
          });
      final int n = types.size();
      if (n == 1) {
        elementType = Ref.create(types.iterator().next());
      } else if (n > 0) {
        elementType = Ref.create(PyUnionType.union(types));
      }
    }
    if (elementType != null) {
      final PyClass generator = cache.getClass(PyNames.FAKE_GENERATOR);
      if (generator != null) {
        return Ref.create(new PyCollectionTypeImpl(generator, false, elementType.get()));
      }
    }
    if (!types.isEmpty()) {
      return Ref.create(null);
    }
    return null;
  }
 @Nullable
 private static Ref<PyType> getOptionalType(
     @NotNull PsiElement element, @NotNull Context context) {
   if (element instanceof PySubscriptionExpression) {
     final PySubscriptionExpression subscriptionExpr = (PySubscriptionExpression) element;
     final PyExpression operand = subscriptionExpr.getOperand();
     final Collection<String> operandNames =
         resolveToQualifiedNames(operand, context.getTypeContext());
     if (operandNames.contains("typing.Optional")) {
       final PyExpression indexExpr = subscriptionExpr.getIndexExpression();
       if (indexExpr != null) {
         final PyType type = getType(indexExpr, context);
         if (type != null) {
           return Ref.create(PyUnionType.union(type, PyNoneType.INSTANCE));
         }
       }
       return Ref.create();
     }
   }
   return null;
 }
 private static PyType getTypeByControlFlow(
     @NotNull String name,
     @NotNull TypeEvalContext context,
     @NotNull PyExpression anchor,
     @NotNull ScopeOwner scopeOwner) {
   PyAugAssignmentStatement augAssignment =
       PsiTreeUtil.getParentOfType(anchor, PyAugAssignmentStatement.class);
   try {
     final PyElement element = augAssignment != null ? augAssignment : anchor;
     final List<ReadWriteInstruction> defs =
         PyDefUseUtil.getLatestDefs(scopeOwner, name, element, true);
     if (!defs.isEmpty()) {
       PyType type = defs.get(0).getType(context, anchor);
       for (int i = 1; i < defs.size(); i++) {
         type = PyUnionType.union(type, defs.get(i).getType(context, anchor));
       }
       return type;
     }
   } catch (PyDefUseUtil.InstructionNotFoundException ignored) {
   }
   return null;
 }
예제 #13
0
  /** @param anchor should never be null or null will be returned */
  @NotNull
  public static ParseResult parse(@Nullable final PsiElement anchor, @NotNull String type) {
    PyPsiUtils.assertValid(anchor);
    if (anchor == null) {
      return EMPTY_RESULT;
    }

    final ForwardDeclaration<ParseResult, PyElementType> typeExpr = ForwardDeclaration.create();

    final FunctionalParser<ParseResult, PyElementType> classType =
        token(IDENTIFIER)
            .then(many(op(".").skipThen(token(IDENTIFIER))))
            .map(new MakeSimpleType(anchor))
            .cached()
            .named("class-type");

    final FunctionalParser<ParseResult, PyElementType> tupleType =
        op("(")
            .skipThen(typeExpr)
            .then(many(op(",").skipThen(typeExpr)))
            .thenSkip(op(")"))
            .map(
                value -> {
                  ParseResult result = value.getFirst();
                  final List<ParseResult> rest = value.getSecond();
                  if (rest.isEmpty()) {
                    return result;
                  }
                  final List<PyType> types = new ArrayList<>();
                  types.add(result.getType());
                  for (ParseResult r : rest) {
                    result = result.merge(r);
                    types.add(r.getType());
                  }
                  return result.withType(PyTupleType.create(anchor, types));
                })
            .named("tuple-type");

    final FunctionalParser<ParseResult, PyElementType> typeParameter =
        token(PARAMETER)
            .then(maybe(op("<=").skipThen(typeExpr)))
            .map(
                value -> {
                  final Token<PyElementType> token = value.getFirst();
                  final String name = token.getText().toString();
                  final TextRange range = token.getRange();
                  final ParseResult boundResult = value.getSecond();
                  if (boundResult != null) {
                    final PyGenericType type1 = new PyGenericType(name, boundResult.getType());
                    final ParseResult result = new ParseResult(null, type1, range);
                    return result.merge(boundResult).withType(type1);
                  }
                  return new ParseResult(null, new PyGenericType(name, null), range);
                })
            .named("type-parameter");

    final FunctionalParser<ParseResult, PyElementType> simpleExpr =
        classType.or(tupleType).or(typeParameter).named("simple-expr");

    final FunctionalParser<ParseResult, PyElementType> paramExpr =
        classType
            .thenSkip(op("["))
            .then(typeExpr)
            .then(many(op(",").skipThen(typeExpr)))
            .thenSkip(op("]"))
            .map(
                value -> {
                  final Pair<ParseResult, ParseResult> firstPair = value.getFirst();
                  final ParseResult first = firstPair.getFirst();
                  final ParseResult second = firstPair.getSecond();
                  final List<ParseResult> third = value.getSecond();
                  final PyType firstType = first.getType();
                  final List<PyType> typesInBrackets = new ArrayList<>();
                  typesInBrackets.add(second.getType());
                  ParseResult result = first;
                  result = result.merge(second);
                  for (ParseResult r : third) {
                    typesInBrackets.add(r.getType());
                    result = result.merge(r);
                  }
                  final List<PyType> elementTypes =
                      third.isEmpty()
                          ? Collections.singletonList(second.getType())
                          : typesInBrackets;
                  final PsiElement resolved = first.getElement();
                  if (resolved != null) {
                    final PyType typingType = PyTypingTypeProvider.getType(resolved, elementTypes);
                    if (typingType != null) {
                      return result.withType(typingType);
                    }
                  }
                  if (firstType instanceof PyClassType) {
                    final PyType type1 =
                        new PyCollectionTypeImpl(
                            ((PyClassType) firstType).getPyClass(), false, elementTypes);
                    return result.withType(type1);
                  }
                  return EMPTY_RESULT;
                })
            .or(
                classType
                    .thenSkip(op("of"))
                    .then(simpleExpr)
                    .map(
                        value -> {
                          final ParseResult firstResult = value.getFirst();
                          final ParseResult secondResult = value.getSecond();
                          final ParseResult result = firstResult.merge(secondResult);
                          final PyType firstType = firstResult.getType();
                          final PyType secondType = secondResult.getType();
                          if (firstType != null) {
                            if (firstType instanceof PyClassType && secondType != null) {
                              return result.withType(
                                  new PyCollectionTypeImpl(
                                      ((PyClassType) firstType).getPyClass(),
                                      false,
                                      Collections.singletonList(secondType)));
                            }
                            return result.withType(firstType);
                          }
                          return EMPTY_RESULT;
                        }))
            .or(
                classType
                    .thenSkip(op("from"))
                    .then(simpleExpr)
                    .thenSkip(op("to"))
                    .then(simpleExpr)
                    .map(
                        value -> {
                          final Pair<ParseResult, ParseResult> firstPair = value.getFirst();
                          final ParseResult first = firstPair.getFirst();
                          final ParseResult second = firstPair.getSecond();
                          final ParseResult third = value.getSecond();
                          final PyType firstType = first.getType();
                          if (firstType instanceof PyClassType) {
                            final List<PyType> elementTypes =
                                Arrays.asList(second.getType(), third.getType());
                            final PyCollectionTypeImpl type1 =
                                new PyCollectionTypeImpl(
                                    ((PyClassType) firstType).getPyClass(), false, elementTypes);
                            return first.merge(second).merge(third).withType(type1);
                          }
                          return EMPTY_RESULT;
                        }))
            .named("param-expr");

    final FunctionalParser<ParseResult, PyElementType> callableExpr =
        op("(")
            .skipThen(maybe(typeExpr.then(many(op(",").skipThen(typeExpr)))))
            .thenSkip(op(")"))
            .thenSkip(op("->"))
            .then(typeExpr)
            .map(
                value -> {
                  final List<PyCallableParameter> parameters = new ArrayList<>();
                  final ParseResult returnResult = value.getSecond();
                  ParseResult result;
                  final Pair<ParseResult, List<ParseResult>> firstPair = value.getFirst();
                  if (firstPair != null) {
                    final ParseResult first = firstPair.getFirst();
                    final List<ParseResult> second = firstPair.getSecond();
                    result = first;
                    parameters.add(new PyCallableParameterImpl(null, first.getType()));
                    for (ParseResult r : second) {
                      result = result.merge(r);
                      parameters.add(new PyCallableParameterImpl(null, r.getType()));
                    }
                    result = result.merge(returnResult);
                  } else {
                    result = returnResult;
                  }
                  return result.withType(
                      new PyCallableTypeImpl(parameters, returnResult.getType()));
                })
            .named("callable-expr");

    final FunctionalParser<ParseResult, PyElementType> singleExpr =
        paramExpr.or(callableExpr).or(simpleExpr).named("single-expr");

    final FunctionalParser<ParseResult, PyElementType> unionExpr =
        singleExpr
            .then(many(op("or").or(op("|")).skipThen(singleExpr)))
            .map(
                value -> {
                  final ParseResult first = value.getFirst();
                  final List<ParseResult> rest = value.getSecond();
                  if (rest.isEmpty()) {
                    return first;
                  }
                  final List<PyType> types = new ArrayList<>();
                  types.add(first.getType());
                  ParseResult result = first;
                  for (ParseResult r : rest) {
                    types.add(r.getType());
                    result = result.merge(r);
                  }
                  return result.withType(PyUnionType.union(types));
                })
            .named("union-expr");

    typeExpr.define(unionExpr).named("type-expr");

    final FunctionalParser<ParseResult, PyElementType> typeFile =
        typeExpr.endOfInput().named("type-file");

    try {
      return typeFile.parse(tokenize(type));
    } catch (ParserException e) {
      return EMPTY_RESULT;
    }
  }