@NotNull
  private JetType modifyTypeAccordingToSuperMethods(
      @NotNull JetType autoType,
      @NotNull List<TypeAndVariance> typesFromSuper,
      @NotNull TypeUsage howThisTypeIsUsed) {
    if (ErrorUtils.isErrorType(autoType)) {
      return autoType;
    }

    boolean resultNullable = typeMustBeNullable(autoType, typesFromSuper, howThisTypeIsUsed);
    ClassifierDescriptor resultClassifier = modifyTypeClassifier(autoType, typesFromSuper);
    List<TypeProjection> resultArguments =
        getTypeArgsOfType(autoType, resultClassifier, typesFromSuper);
    JetScope resultScope;
    if (resultClassifier instanceof ClassDescriptor) {
      resultScope = ((ClassDescriptor) resultClassifier).getMemberScope(resultArguments);
    } else {
      resultScope = autoType.getMemberScope();
    }

    JetTypeImpl type =
        new JetTypeImpl(
            autoType.getAnnotations(),
            resultClassifier.getTypeConstructor(),
            resultNullable,
            resultArguments,
            resultScope);

    PropagationHeuristics.checkArrayInReturnType(this, type, typesFromSuper);
    return type;
  }
  @Nullable
  private JetType lookupNamespaceOrClassObject(
      @NotNull JetSimpleNameExpression expression, @NotNull ResolutionContext context) {
    Name referencedName = expression.getReferencedNameAsName();
    final ClassifierDescriptor classifier = context.scope.getClassifier(referencedName);
    if (classifier != null) {
      JetType classObjectType = classifier.getClassObjectType();
      if (classObjectType != null) {
        context.trace.record(REFERENCE_TARGET, expression, classifier);
        JetType result =
            getExtendedClassObjectType(classObjectType, referencedName, classifier, context);
        if (result == null) {
          context.trace.report(NO_CLASS_OBJECT.on(expression, classifier));
        }
        return DataFlowUtils.checkType(result, expression, context);
      }
    }
    JetType[] result = new JetType[1];
    TemporaryBindingTrace temporaryTrace =
        TemporaryBindingTrace.create(
            context.trace, "trace for namespace/class object lookup of name", referencedName);
    if (furtherNameLookup(expression, result, context.replaceBindingTrace(temporaryTrace))) {
      temporaryTrace.commit();
      return DataFlowUtils.checkType(result[0], expression, context);
    }
    // To report NO_CLASS_OBJECT when no namespace found
    if (classifier != null) {
      if (classifier instanceof TypeParameterDescriptor) {
        if (context.expressionPosition == ExpressionPosition.FREE) {
          context.trace.report(
              TYPE_PARAMETER_IS_NOT_AN_EXPRESSION.on(
                  expression, (TypeParameterDescriptor) classifier));
        } else {
          context.trace.report(
              TYPE_PARAMETER_ON_LHS_OF_DOT.on(expression, (TypeParameterDescriptor) classifier));
        }
      } else if (context.expressionPosition == ExpressionPosition.FREE) {
        context.trace.report(NO_CLASS_OBJECT.on(expression, classifier));
      }
      context.trace.record(REFERENCE_TARGET, expression, classifier);
      JetScope scopeForStaticMembersResolution =
          classifier instanceof ClassDescriptor
              ? getStaticNestedClassesScope((ClassDescriptor) classifier)
              : new JetScopeImpl() {
                @NotNull
                @Override
                public DeclarationDescriptor getContainingDeclaration() {
                  return classifier;
                }

                @Override
                public String toString() {
                  return "Scope for the type parameter on the left hand side of dot";
                }
              };
      return new NamespaceType(referencedName, scopeForStaticMembersResolution);
    }
    temporaryTrace.commit();
    return result[0];
  }
  @NotNull
  private static Multimap<FqName, Pair<FunctionDescriptor, PsiMethod>>
      getSuperclassToFunctionsMultimap(
          @NotNull PsiMethodWrapper method,
          @NotNull BindingContext bindingContext,
          @NotNull ClassDescriptor containingClass) {
    Multimap<FqName, Pair<FunctionDescriptor, PsiMethod>> result = HashMultimap.create();

    Name functionName = Name.identifier(method.getName());
    int parameterCount = method.getParameters().size();

    for (JetType supertype : TypeUtils.getAllSupertypes(containingClass.getDefaultType())) {
      ClassifierDescriptor klass = supertype.getConstructor().getDeclarationDescriptor();
      assert klass != null;
      FqName fqName = DescriptorUtils.getFQName(klass).toSafe();

      for (FunctionDescriptor fun :
          klass.getDefaultType().getMemberScope().getFunctions(functionName)) {
        if (fun.getKind().isReal() && fun.getValueParameters().size() == parameterCount) {
          PsiElement declaration = BindingContextUtils.descriptorToDeclaration(bindingContext, fun);
          if (declaration instanceof PsiMethod) {
            result.put(fqName, Pair.create(fun, (PsiMethod) declaration));
          } // else declaration is null or JetNamedFunction: both cases are processed later
        }
      }
    }
    return result;
  }
Example #4
0
  private String renderDefaultType(JetType type, boolean shortNamesOnly) {
    StringBuilder sb = new StringBuilder();
    ClassifierDescriptor cd = type.getConstructor().getDeclarationDescriptor();

    Object typeNameObject;

    if (cd == null || cd instanceof TypeParameterDescriptor) {
      typeNameObject = type.getConstructor();
    } else {
      if (shortNamesOnly) {
        // for nested classes qualified name should be used
        typeNameObject = cd.getName();
        DeclarationDescriptor parent = cd.getContainingDeclaration();
        while (parent instanceof ClassDescriptor) {
          typeNameObject = parent.getName() + "." + typeNameObject;
          parent = parent.getContainingDeclaration();
        }
      } else {
        typeNameObject = DescriptorUtils.getFQName(cd);
      }
    }

    sb.append(typeNameObject);
    if (!type.getArguments().isEmpty()) {
      sb.append("<");
      appendTypeProjections(sb, type.getArguments(), shortNamesOnly);
      sb.append(">");
    }
    if (type.isNullable()) {
      sb.append("?");
    }
    return sb.toString();
  }
  // Returns list with type arguments info from supertypes
  // Example:
  //     - Foo<A, B> is a subtype of Bar<A, List<B>>, Baz<Boolean, A>
  //     - input: klass = Foo, typesFromSuper = [Bar<String, List<Int>>, Baz<Boolean, CharSequence>]
  //     - output[0] = [String, CharSequence], output[1] = []
  private static List<List<TypeProjectionAndVariance>> calculateTypeArgumentsFromSuper(
      @NotNull ClassDescriptor klass, @NotNull Collection<TypeAndVariance> typesFromSuper) {
    // For each superclass of klass and its parameters, hold their mapping to klass' parameters
    // #0 of Bar ->  A
    // #1 of Bar ->  List<B>
    // #0 of Baz ->  Boolean
    // #1 of Baz ->  A
    // #0 of Foo ->  A (mapped to itself)
    // #1 of Foo ->  B (mapped to itself)
    Multimap<TypeConstructor, TypeProjection> substitution =
        SubstitutionUtils.buildDeepSubstitutionMultimap(
            TypeUtils.makeUnsubstitutedType(klass, JetScope.EMPTY));

    // for each parameter of klass, hold arguments in corresponding supertypes
    List<List<TypeProjectionAndVariance>> parameterToArgumentsFromSuper = Lists.newArrayList();
    for (TypeParameterDescriptor ignored : klass.getTypeConstructor().getParameters()) {
      parameterToArgumentsFromSuper.add(new ArrayList<TypeProjectionAndVariance>());
    }

    // Enumerate all types from super and all its parameters
    for (TypeAndVariance typeFromSuper : typesFromSuper) {
      for (TypeParameterDescriptor parameter :
          typeFromSuper.type.getConstructor().getParameters()) {
        TypeProjection argument = typeFromSuper.type.getArguments().get(parameter.getIndex());

        // for given example, this block is executed four times:
        // 1. typeFromSuper = Bar<String, List<Int>>,      parameter = "#0 of Bar",  argument =
        // String
        // 2. typeFromSuper = Bar<String, List<Int>>,      parameter = "#1 of Bar",  argument =
        // List<Int>
        // 3. typeFromSuper = Baz<Boolean, CharSequence>,  parameter = "#0 of Baz",  argument =
        // Boolean
        // 4. typeFromSuper = Baz<Boolean, CharSequence>,  parameter = "#1 of Baz",  argument =
        // CharSequence

        // if it is mapped to klass' parameter, then store it into map
        for (TypeProjection projection : substitution.get(parameter.getTypeConstructor())) {
          // 1. projection = A
          // 2. projection = List<B>
          // 3. projection = Boolean
          // 4. projection = A
          ClassifierDescriptor classifier =
              projection.getType().getConstructor().getDeclarationDescriptor();

          // this condition is true for 1 and 4, false for 2 and 3
          if (classifier instanceof TypeParameterDescriptor
              && classifier.getContainingDeclaration() == klass) {
            int parameterIndex = ((TypeParameterDescriptor) classifier).getIndex();
            Variance effectiveVariance =
                parameter.getVariance().superpose(typeFromSuper.varianceOfPosition);
            parameterToArgumentsFromSuper
                .get(parameterIndex)
                .add(new TypeProjectionAndVariance(argument, effectiveVariance));
          }
        }
      }
    }
    return parameterToArgumentsFromSuper;
  }
Example #6
0
  @Nullable
  public static Name getNameIfStandardType(@NotNull JetType type) {
    ClassifierDescriptor descriptor = type.getConstructor().getDeclarationDescriptor();
    if (descriptor != null
        && descriptor.getContainingDeclaration()
            == KotlinBuiltIns.getInstance().getBuiltInsPackageFragment()) {
      return descriptor.getName();
    }

    return null;
  }
Example #7
0
 @NotNull
 private String renderTypeName(@NotNull TypeConstructor typeConstructor) {
   ClassifierDescriptor cd = typeConstructor.getDeclarationDescriptor();
   if (cd instanceof TypeParameterDescriptor) {
     return renderName(cd.getName());
   } else if (cd instanceof ClassDescriptor) {
     return renderClassName((ClassDescriptor) cd);
   } else {
     assert cd == null : "Unexpected classifier: " + cd.getClass();
     return typeConstructor.toString();
   }
 }
 @Nullable
 private JetType lookupNamespaceOrClassObject(
     @NotNull JetSimpleNameExpression expression, @NotNull ResolutionContext context) {
   Name referencedName = expression.getReferencedNameAsName();
   ClassifierDescriptor classifier = context.scope.getClassifier(referencedName);
   if (classifier != null) {
     JetType classObjectType = classifier.getClassObjectType();
     if (classObjectType != null) {
       context.trace.record(REFERENCE_TARGET, expression, classifier);
       JetType result;
       if (context.expressionPosition == ExpressionPosition.LHS_OF_DOT
           && classifier instanceof ClassDescriptor) {
         JetScope scope =
             new ChainedScope(
                 classifier,
                 classObjectType.getMemberScope(),
                 getStaticNestedClassesScope((ClassDescriptor) classifier));
         result = new NamespaceType(referencedName, scope);
       } else if (context.expressionPosition == ExpressionPosition.LHS_OF_DOT
           || classifier.isClassObjectAValue()) {
         result = classObjectType;
       } else {
         context.trace.report(NO_CLASS_OBJECT.on(expression, classifier));
         result = null;
       }
       return DataFlowUtils.checkType(result, expression, context);
     }
   }
   JetType[] result = new JetType[1];
   TemporaryBindingTrace temporaryTrace =
       TemporaryBindingTrace.create(
           context.trace, "trace for namespace/class object lookup of name", referencedName);
   if (furtherNameLookup(expression, result, context.replaceBindingTrace(temporaryTrace))) {
     temporaryTrace.commit();
     return DataFlowUtils.checkType(result[0], expression, context);
   }
   // To report NO_CLASS_OBJECT when no namespace found
   if (classifier != null) {
     if (context.expressionPosition == ExpressionPosition.FREE) {
       context.trace.report(NO_CLASS_OBJECT.on(expression, classifier));
     }
     context.trace.record(REFERENCE_TARGET, expression, classifier);
     JetScope scopeForStaticMembersResolution =
         classifier instanceof ClassDescriptor
             ? getStaticNestedClassesScope((ClassDescriptor) classifier)
             : JetScope.EMPTY;
     return new NamespaceType(referencedName, scopeForStaticMembersResolution);
   }
   temporaryTrace.commit();
   return result[0];
 }
Example #9
0
 @Nullable
 public static JetType getPrimitiveRangeElementType(JetType rangeType) {
   ClassifierDescriptor declarationDescriptor =
       rangeType.getConstructor().getDeclarationDescriptor();
   assert declarationDescriptor != null;
   if (declarationDescriptor
       != KotlinBuiltIns.getInstance()
           .getBuiltInsScope()
           .getClassifier(declarationDescriptor.getName())) {
     // Must be a standard library class
     return null;
   }
   return RANGE_TO_ELEMENT_TYPE.get(declarationDescriptor.getName().getName());
 }
  @Nullable
  private JetType getExtendedClassObjectType(
      @NotNull JetType classObjectType,
      @NotNull Name referencedName,
      @NotNull ClassifierDescriptor classifier,
      @NotNull ResolutionContext context) {
    if (context.expressionPosition == ExpressionPosition.LHS_OF_DOT
        && classifier instanceof ClassDescriptor) {
      List<JetScope> scopes = new ArrayList<JetScope>(3);

      scopes.add(classObjectType.getMemberScope());
      scopes.add(getStaticNestedClassesScope((ClassDescriptor) classifier));

      NamespaceDescriptor namespace = context.scope.getNamespace(referencedName);
      if (namespace != null) {
        scopes.add(namespace.getMemberScope());
      }

      JetScope scope = new ChainedScope(classifier, scopes.toArray(new JetScope[scopes.size()]));
      return new NamespaceType(referencedName, scope);
    } else if (context.expressionPosition == ExpressionPosition.LHS_OF_DOT
        || classifier.isClassObjectAValue()) {
      return classObjectType;
    } else {
      return null;
    }
  }
  @NotNull
  private List<TypeProjection> getTypeArgsOfType(
      @NotNull JetType autoType,
      @NotNull ClassifierDescriptor classifier,
      @NotNull List<TypeAndVariance> typesFromSuper) {
    List<TypeProjection> autoArguments = autoType.getArguments();

    if (!(classifier instanceof ClassDescriptor)) {
      assert autoArguments.isEmpty()
          : "Unexpected type arguments when type constructor is not ClassDescriptor, type = "
              + autoType;
      return autoArguments;
    }

    List<List<TypeProjectionAndVariance>> typeArgumentsFromSuper =
        calculateTypeArgumentsFromSuper((ClassDescriptor) classifier, typesFromSuper);

    // Modify type arguments using info from typesFromSuper
    List<TypeProjection> resultArguments = Lists.newArrayList();
    for (TypeParameterDescriptor parameter : classifier.getTypeConstructor().getParameters()) {
      TypeProjection argument = autoArguments.get(parameter.getIndex());

      JetType argumentType = argument.getType();
      List<TypeProjectionAndVariance> projectionsFromSuper =
          typeArgumentsFromSuper.get(parameter.getIndex());
      List<TypeAndVariance> argTypesFromSuper = getTypes(projectionsFromSuper);

      JetType type =
          modifyTypeAccordingToSuperMethods(argumentType, argTypesFromSuper, TYPE_ARGUMENT);
      Variance projectionKind =
          calculateArgumentProjectionKindFromSuper(argument, projectionsFromSuper);

      resultArguments.add(new TypeProjection(projectionKind, type));
    }
    return resultArguments;
  }
Example #12
0
  /**
   * Remember that we are trying to cast something of type {@code supertype} to {@code subtype}.
   *
   * <p>Since at runtime we can only check the class (type constructor), the rest of the subtype
   * should be known statically, from supertype. This method reconstructs all static information
   * that can be obtained from supertype.
   *
   * <p>Example 1: supertype = Collection<String> subtype = List<...> result = List<String>, all
   * arguments are inferred
   *
   * <p>Example 2: supertype = Any subtype = List<...> result = List<*>, some arguments were not
   * inferred, replaced with '*'
   */
  public static TypeReconstructionResult findStaticallyKnownSubtype(
      @NotNull JetType supertype, @NotNull TypeConstructor subtypeConstructor) {
    assert !supertype.isNullable() : "This method only makes sense for non-nullable types";

    // Assume we are casting an expression of type Collection<Foo> to List<Bar>
    // First, let's make List<T>, where T is a type variable
    ClassifierDescriptor descriptor = subtypeConstructor.getDeclarationDescriptor();
    assert descriptor != null : "Can't create default type for " + subtypeConstructor;
    JetType subtypeWithVariables = descriptor.getDefaultType();

    // Now, let's find a supertype of List<T> that is a Collection of something,
    // in this case it will be Collection<T>
    JetType supertypeWithVariables =
        TypeCheckingProcedure.findCorrespondingSupertype(subtypeWithVariables, supertype);

    final List<TypeParameterDescriptor> variables =
        subtypeWithVariables.getConstructor().getParameters();

    Map<TypeConstructor, TypeProjection> substitution;
    if (supertypeWithVariables != null) {
      // Now, let's try to unify Collection<T> and Collection<Foo> solution is a map from T to Foo
      TypeUnifier.UnificationResult solution =
          TypeUnifier.unify(
              new TypeProjectionImpl(supertype),
              new TypeProjectionImpl(supertypeWithVariables),
              new Predicate<TypeConstructor>() {
                @Override
                public boolean apply(TypeConstructor typeConstructor) {
                  ClassifierDescriptor descriptor = typeConstructor.getDeclarationDescriptor();
                  return descriptor instanceof TypeParameterDescriptor
                      && variables.contains(descriptor);
                }
              });
      substitution = Maps.newHashMap(solution.getSubstitution());
    } else {
      // If there's no corresponding supertype, no variables are determined
      // This may be OK, e.g. in case 'Any as List<*>'
      substitution = Maps.newHashMapWithExpectedSize(variables.size());
    }

    // If some of the parameters are not determined by unification, it means that these parameters
    // are lost,
    // let's put stars instead, so that we can only cast to something like List<*>, e.g. (a: Any) as
    // List<*>
    boolean allArgumentsInferred = true;
    for (TypeParameterDescriptor variable : variables) {
      TypeProjection value = substitution.get(variable.getTypeConstructor());
      if (value == null) {
        substitution.put(
            variable.getTypeConstructor(), SubstitutionUtils.makeStarProjection(variable));
        allArgumentsInferred = false;
      }
    }

    // At this point we have values for all type parameters of List
    // Let's make a type by substituting them: List<T> -> List<Foo>
    JetType substituted =
        TypeSubstitutor.create(substitution).substitute(subtypeWithVariables, Variance.INVARIANT);

    return new TypeReconstructionResult(substituted, allArgumentsInferred);
  }