private void generateDataClassEqualsIfNeeded(@NotNull List<PropertyDescriptor> properties) { FunctionDescriptor function = getDeclaredMember("equals", builtIns.getBoolean(), builtIns.getAny()); if (function != null && isTrivial(function)) { generateEqualsMethod(function, properties); } }
public static boolean shouldRecordInitializerForProperty( @NotNull VariableDescriptor variable, @NotNull KotlinType type) { if (variable.isVar() || type.isError()) return false; if (TypeUtils.acceptsNullable(type)) return true; KotlinBuiltIns builtIns = getBuiltIns(variable); return KotlinBuiltIns.isPrimitiveType(type) || KotlinTypeChecker.DEFAULT.equalTypes(builtIns.getStringType(), type) || KotlinTypeChecker.DEFAULT.equalTypes(builtIns.getNumber().getDefaultType(), type) || KotlinTypeChecker.DEFAULT.equalTypes(builtIns.getAnyType(), type); }
private static boolean isFromBuiltinModule(@NotNull DeclarationDescriptor originalDescriptor) { // TODO This is optimization only // It should be rewritten by checking declarationDescriptor.getSource(), when the latter returns // something non-trivial for builtins. return KotlinBuiltIns.getInstance().getBuiltInsModule() == DescriptorUtils.getContainingModule(originalDescriptor); }
public boolean isMain(@NotNull JetNamedFunction function) { if (!"main".equals(function.getName())) return false; FunctionDescriptor functionDescriptor = getFunctionDescriptor.fun(function); List<ValueParameterDescriptor> parameters = functionDescriptor.getValueParameters(); if (parameters.size() != 1) return false; ValueParameterDescriptor parameter = parameters.get(0); JetType parameterType = parameter.getType(); if (!KotlinBuiltIns.isArray(parameterType)) return false; List<TypeProjection> typeArguments = parameterType.getArguments(); if (typeArguments.size() != 1) return false; JetType typeArgument = typeArguments.get(0).getType(); if (!JetTypeChecker.DEFAULT.equalTypes( typeArgument, getBuiltIns(functionDescriptor).getStringType())) return false; if (DescriptorUtils.isTopLevelDeclaration(functionDescriptor)) return true; DeclarationDescriptor containingDeclaration = functionDescriptor.getContainingDeclaration(); return containingDeclaration instanceof ClassDescriptor && ((ClassDescriptor) containingDeclaration).getKind().isSingleton() && AnnotationsPackage.hasPlatformStaticAnnotation(functionDescriptor); }
private static boolean isInlinableParameter(@NotNull CallableDescriptor descriptor) { JetType type = descriptor.getReturnType(); return type != null && KotlinBuiltIns.isExactFunctionOrExtensionFunctionType(type) && !type.isMarkedNullable() && !InlineUtil.hasNoinlineAnnotation(descriptor); }
private TypeParameterDescriptor createTypeVariable(String name) { return TypeParameterDescriptorImpl.createWithDefaultBound( builtIns.getBuiltInsModule(), Annotations.Companion.getEMPTY(), false, Variance.INVARIANT, Name.identifier(name), 0); }
private KotlinTypeInfo getTypeOfLastExpressionInBlock( @NotNull KtExpression statementExpression, @NotNull ExpressionTypingContext context, @NotNull CoercionStrategy coercionStrategyForLastExpression, @NotNull ExpressionTypingInternals blockLevelVisitor) { if (context.expectedType != NO_EXPECTED_TYPE) { KotlinType expectedType; if (context.expectedType == UNIT_EXPECTED_TYPE || // the first check is necessary to avoid invocation 'isUnit(UNIT_EXPECTED_TYPE)' (coercionStrategyForLastExpression == COERCION_TO_UNIT && KotlinBuiltIns.isUnit(context.expectedType))) { expectedType = UNIT_EXPECTED_TYPE; } else { expectedType = context.expectedType; } return blockLevelVisitor.getTypeInfo( statementExpression, context.replaceExpectedType(expectedType), true); } KotlinTypeInfo result = blockLevelVisitor.getTypeInfo(statementExpression, context, true); if (coercionStrategyForLastExpression == COERCION_TO_UNIT) { boolean mightBeUnit = false; if (statementExpression instanceof KtDeclaration) { mightBeUnit = true; } if (statementExpression instanceof KtBinaryExpression) { KtBinaryExpression binaryExpression = (KtBinaryExpression) statementExpression; IElementType operationType = binaryExpression.getOperationToken(); //noinspection SuspiciousMethodCalls if (operationType == KtTokens.EQ || OperatorConventions.ASSIGNMENT_OPERATIONS.containsKey(operationType)) { mightBeUnit = true; } } if (mightBeUnit) { // ExpressionTypingVisitorForStatements should return only null or Unit for declarations and // assignments, // but (for correct assignment / initialization analysis) data flow info must be preserved assert result.getType() == null || KotlinBuiltIns.isUnit(result.getType()); result = result.replaceType(expressionTypingComponents.builtIns.getUnitType()); } } return result; }
@Override public void setUp() throws Exception { super.setUp(); builtIns = KotlinBuiltIns.getInstance(); ContainerForTests container = DiPackage.createContainerForTests(getProject(), JetTestUtils.createEmptyModule()); typeResolver = container.getTypeResolver(); expressionTypingServices = container.getExpressionTypingServices(); scopeWithImports = getDeclarationsScope("compiler/testData/type-checker-test.kt"); }
@Nullable public static KotlinType getDefaultPrimitiveNumberType( @NotNull Collection<KotlinType> supertypes) { if (supertypes.isEmpty()) { return null; } KotlinBuiltIns builtIns = supertypes.iterator().next().getConstructor().getBuiltIns(); KotlinType doubleType = builtIns.getDoubleType(); if (supertypes.contains(doubleType)) { return doubleType; } KotlinType intType = builtIns.getIntType(); if (supertypes.contains(intType)) { return intType; } KotlinType longType = builtIns.getLongType(); if (supertypes.contains(longType)) { return longType; } return null; }
public static Map<String, DeclarationDescriptor> prepareDefaultNameToDescriptors( Project project, KotlinCoreEnvironment environment) { KotlinBuiltIns builtIns = JvmPlatform.INSTANCE.getBuiltIns(); Map<String, DeclarationDescriptor> nameToDescriptor = new HashMap<String, DeclarationDescriptor>(); nameToDescriptor.put( "kotlin::Int.plus(Int)", standardFunction(builtIns.getInt(), "plus", project, builtIns.getIntType())); FunctionDescriptor descriptorForGet = standardFunction(builtIns.getArray(), "get", project, builtIns.getIntType()); nameToDescriptor.put("kotlin::Array.get(Int)", descriptorForGet.getOriginal()); nameToDescriptor.put( "kotlin::Int.compareTo(Double)", standardFunction(builtIns.getInt(), "compareTo", project, builtIns.getDoubleType())); @NotNull FunctionDescriptor descriptorForSet = standardFunction( builtIns.getArray(), "set", project, builtIns.getIntType(), builtIns.getIntType()); nameToDescriptor.put("kotlin::Array.set(Int, Int)", descriptorForSet.getOriginal()); return nameToDescriptor; }
// As this method produces a warning, it must be _complete_ (not sound), i.e. every time it says // "cast impossible", // it must be really impossible public static boolean isCastPossible( @NotNull KotlinType lhsType, @NotNull KotlinType rhsType, @NotNull PlatformToKotlinClassMap platformToKotlinClassMap) { if (KotlinBuiltIns.isNullableNothing(lhsType) && !TypeUtils.isNullableType(rhsType)) return false; if (isRelated(lhsType, rhsType, platformToKotlinClassMap)) return true; // This is an oversimplification (which does not render the method incomplete): // we consider any type parameter capable of taking any value, which may be made more precise if // we considered bounds if (TypeUtils.isTypeParameter(lhsType) || TypeUtils.isTypeParameter(rhsType)) return true; if (isFinal(lhsType) || isFinal(rhsType)) return false; if (isTrait(lhsType) || isTrait(rhsType)) return true; return false; }
/** @return true if the member is an inherited implementation of a method from Any */ private boolean isTrivial(@NotNull FunctionDescriptor function) { if (function.getKind() == CallableMemberDescriptor.Kind.DECLARATION) { return false; } for (CallableDescriptor overridden : OverrideResolver.getOverriddenDeclarations(function)) { if (overridden instanceof CallableMemberDescriptor && ((CallableMemberDescriptor) overridden).getKind() == CallableMemberDescriptor.Kind.DECLARATION && !overridden.getContainingDeclaration().equals(builtIns.getAny())) { return false; } } return true; }
private static boolean isInvokeOrInlineExtension(@NotNull CallableDescriptor descriptor) { if (!(descriptor instanceof SimpleFunctionDescriptor)) { return false; } DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration(); boolean isInvoke = descriptor.getName().asString().equals("invoke") && containingDeclaration instanceof ClassDescriptor && KotlinBuiltIns.isExactFunctionOrExtensionFunctionType( ((ClassDescriptor) containingDeclaration).getDefaultType()); return isInvoke || // or inline extension ((SimpleFunctionDescriptor) descriptor).getInlineStrategy().isInline(); }
private static List<FunctionDescriptor> generateFunctionsToAdd(JetNamedFunction functionElement) { FunctionDescriptor functionDescriptor = (FunctionDescriptor) ResolvePackage.resolveToDescriptor(functionElement); DeclarationDescriptor containingDeclaration = functionDescriptor.getContainingDeclaration(); if (!(containingDeclaration instanceof ClassDescriptor)) return Collections.emptyList(); List<FunctionDescriptor> functions = Lists.newArrayList(); ClassDescriptor classDescriptor = (ClassDescriptor) containingDeclaration; // TODO: filter out impossible supertypes (for example when argument's type isn't visible in a // superclass). for (ClassDescriptor supertypeDescriptor : getSupertypes(classDescriptor)) { if (KotlinBuiltIns.isAnyOrNullableAny(supertypeDescriptor.getDefaultType())) continue; functions.add(generateFunctionSignatureForType(functionDescriptor, supertypeDescriptor)); } return functions; }
@NotNull protected Collection<KotlinType> computeSupertypes() { if (KotlinBuiltIns.isSpecialClassWithNoSupertypes(this)) { return Collections.emptyList(); } KtClassOrObject classOrObject = declarationProvider.getOwnerInfo().getCorrespondingClassOrObject(); if (classOrObject == null) { return Collections.<KotlinType>singleton(c.getModuleDescriptor().getBuiltIns().getAnyType()); } List<KotlinType> allSupertypes = c.getDescriptorResolver() .resolveSupertypes( getScopeForClassHeaderResolution(), this, classOrObject, c.getTrace()); return Lists.newArrayList(Collections2.filter(allSupertypes, VALID_SUPERTYPE)); }
private static synchronized void initialize() { if (instance == null) { if (initializationFailed != null) { throw new RuntimeException( "builtin library initialization failed previously: " + initializationFailed, initializationFailed); } if (initializing) { throw new IllegalStateException("builtin library initialization loop"); } initializing = true; try { instance = new KotlinBuiltIns(); instance.doInitialize(); } catch (Throwable e) { initializationFailed = e; throw new RuntimeException("builtin library initialization failed: " + e, e); } finally { initializing = false; } } }
@NotNull private KotlinTypeInfo getTypeInfoWhenOnlyOneBranchIsPresent( @NotNull KtExpression presentBranch, @NotNull LexicalWritableScope presentScope, @NotNull DataFlowInfo presentInfo, @NotNull DataFlowInfo otherInfo, @NotNull ExpressionTypingContext context, @NotNull KtIfExpression ifExpression, boolean isStatement) { ExpressionTypingContext newContext = context .replaceDataFlowInfo(presentInfo) .replaceExpectedType(NO_EXPECTED_TYPE) .replaceContextDependency(INDEPENDENT); KotlinTypeInfo typeInfo = components.expressionTypingServices.getBlockReturnedTypeWithWritableScope( presentScope, Collections.singletonList(presentBranch), CoercionStrategy.NO_COERCION, newContext); KotlinType type = typeInfo.getType(); DataFlowInfo dataFlowInfo; if (type != null && KotlinBuiltIns.isNothing(type)) { dataFlowInfo = otherInfo; } else { dataFlowInfo = typeInfo.getDataFlowInfo().or(otherInfo); } return components .dataFlowAnalyzer .checkImplicitCast( components.dataFlowAnalyzer.checkType( typeInfo.replaceType(components.builtIns.getUnitType()), ifExpression, context), ifExpression, context, isStatement) .replaceDataFlowInfo(dataFlowInfo); }
@NotNull private TypeProjection unsafeSubstitute( @NotNull TypeProjection originalProjection, int recursionDepth) throws SubstitutionException { assertRecursionDepth(recursionDepth, originalProjection, substitution); if (originalProjection.isStarProjection()) return originalProjection; // The type is within the substitution range, i.e. T or T? JetType type = originalProjection.getType(); TypeProjection replacement = substitution.get(type); Variance originalProjectionKind = originalProjection.getProjectionKind(); if (replacement == null && FlexibleTypesKt.isFlexible(type) && !TypeCapabilitiesKt.isCustomTypeVariable(type)) { Flexibility flexibility = FlexibleTypesKt.flexibility(type); TypeProjection substitutedLower = unsafeSubstitute( new TypeProjectionImpl(originalProjectionKind, flexibility.getLowerBound()), recursionDepth + 1); TypeProjection substitutedUpper = unsafeSubstitute( new TypeProjectionImpl(originalProjectionKind, flexibility.getUpperBound()), recursionDepth + 1); Variance substitutedProjectionKind = substitutedLower.getProjectionKind(); assert (substitutedProjectionKind == substitutedUpper.getProjectionKind()) && originalProjectionKind == Variance.INVARIANT || originalProjectionKind == substitutedProjectionKind : "Unexpected substituted projection kind: " + substitutedProjectionKind + "; original: " + originalProjectionKind; JetType substitutedFlexibleType = DelegatingFlexibleType.create( substitutedLower.getType(), substitutedUpper.getType(), flexibility.getExtraCapabilities()); return new TypeProjectionImpl(substitutedProjectionKind, substitutedFlexibleType); } if (KotlinBuiltIns.isNothing(type) || type.isError()) return originalProjection; if (replacement != null) { VarianceConflictType varianceConflict = conflictType(originalProjectionKind, replacement.getProjectionKind()); // Captured type might be substituted in an opposite projection: // out 'Captured (in Int)' = out Int // in 'Captured (out Int)' = in Int boolean allowVarianceConflict = CapturedTypeConstructorKt.isCaptured(type); if (!allowVarianceConflict) { //noinspection EnumSwitchStatementWhichMissesCases switch (varianceConflict) { case OUT_IN_IN_POSITION: throw new SubstitutionException("Out-projection in in-position"); case IN_IN_OUT_POSITION: // todo use the right type parameter variance and upper bound return new TypeProjectionImpl( Variance.OUT_VARIANCE, type.getConstructor().getBuiltIns().getNullableAnyType()); } } JetType substitutedType; CustomTypeVariable typeVariable = TypeCapabilitiesKt.getCustomTypeVariable(type); if (replacement.isStarProjection()) { return replacement; } else if (typeVariable != null) { substitutedType = typeVariable.substitutionResult(replacement.getType()); } else { // this is a simple type T or T?: if it's T, we should just take replacement, if T? - we // make replacement nullable substitutedType = TypeUtils.makeNullableIfNeeded(replacement.getType(), type.isMarkedNullable()); } // substitutionType.annotations = replacement.annotations ++ type.annotations if (!type.getAnnotations().isEmpty()) { Annotations typeAnnotations = filterOutUnsafeVariance(type.getAnnotations()); substitutedType = TypeUtilsKt.replaceAnnotations( substitutedType, new CompositeAnnotations(substitutedType.getAnnotations(), typeAnnotations)); } Variance resultingProjectionKind = varianceConflict == VarianceConflictType.NO_CONFLICT ? combine(originalProjectionKind, replacement.getProjectionKind()) : originalProjectionKind; return new TypeProjectionImpl(resultingProjectionKind, substitutedType); } // The type is not within the substitution range, i.e. Foo, Bar<T> etc. return substituteCompoundType(originalProjection, recursionDepth); }
@NotNull public LineResult eval(@NotNull String line) { ++lineNumber; FqName scriptFqName = new FqName("Line" + lineNumber); Type scriptClassType = asmTypeByFqNameWithoutInnerClasses(scriptFqName); StringBuilder fullText = new StringBuilder(); for (String prevLine : previousIncompleteLines) { fullText.append(prevLine).append("\n"); } fullText.append(line); LightVirtualFile virtualFile = new LightVirtualFile( "line" + lineNumber + JetParserDefinition.STD_SCRIPT_EXT, JetLanguage.INSTANCE, fullText.toString()); virtualFile.setCharset(CharsetToolkit.UTF8_CHARSET); JetFile psiFile = (JetFile) psiFileFactory.trySetupPsiForFile(virtualFile, JetLanguage.INSTANCE, true, false); assert psiFile != null : "Script file not analyzed at line " + lineNumber + ": " + fullText; ReplMessageCollectorWrapper errorCollector = new ReplMessageCollectorWrapper(); AnalyzerWithCompilerReport.SyntaxErrorReport syntaxErrorReport = AnalyzerWithCompilerReport.reportSyntaxErrors( psiFile, errorCollector.getMessageCollector()); if (syntaxErrorReport.isHasErrors() && syntaxErrorReport.isAllErrorsAtEof()) { previousIncompleteLines.add(line); return LineResult.incomplete(); } previousIncompleteLines.clear(); if (syntaxErrorReport.isHasErrors()) { return LineResult.error(errorCollector.getString()); } prepareForTheNextReplLine(topDownAnalysisContext); trace.clearDiagnostics(); //noinspection ConstantConditions psiFile.getScript().putUserData(ScriptPriorities.PRIORITY_KEY, lineNumber); ScriptDescriptor scriptDescriptor = doAnalyze(psiFile, errorCollector); if (scriptDescriptor == null) { return LineResult.error(errorCollector.getString()); } List<Pair<ScriptDescriptor, Type>> earlierScripts = Lists.newArrayList(); for (EarlierLine earlierLine : earlierLines) { earlierScripts.add( Pair.create(earlierLine.getScriptDescriptor(), earlierLine.getClassType())); } GenerationState state = new GenerationState( psiFile.getProject(), ClassBuilderFactories.BINARIES, module, trace.getBindingContext(), Collections.singletonList(psiFile)); compileScript( psiFile.getScript(), scriptClassType, earlierScripts, state, CompilationErrorHandler.THROW_EXCEPTION); for (OutputFile outputFile : state.getFactory().asList()) { classLoader.addClass( JvmClassName.byInternalName(outputFile.getRelativePath().replaceFirst("\\.class$", "")), outputFile.asByteArray()); } try { Class<?> scriptClass = classLoader.loadClass(scriptFqName.asString()); Class<?>[] constructorParams = new Class<?>[earlierLines.size()]; Object[] constructorArgs = new Object[earlierLines.size()]; for (int i = 0; i < earlierLines.size(); ++i) { constructorParams[i] = earlierLines.get(i).getScriptClass(); constructorArgs[i] = earlierLines.get(i).getScriptInstance(); } Constructor<?> scriptInstanceConstructor = scriptClass.getConstructor(constructorParams); Object scriptInstance; try { scriptInstance = scriptInstanceConstructor.newInstance(constructorArgs); } catch (Throwable e) { return LineResult.error(renderStackTrace(e.getCause())); } Field rvField = scriptClass.getDeclaredField("rv"); rvField.setAccessible(true); Object rv = rvField.get(scriptInstance); earlierLines.add( new EarlierLine(line, scriptDescriptor, scriptClass, scriptInstance, scriptClassType)); JetType returnType = scriptDescriptor.getScriptCodeDescriptor().getReturnType(); return LineResult.successful(rv, returnType != null && KotlinBuiltIns.isUnit(returnType)); } catch (Throwable e) { @SuppressWarnings("UseOfSystemOutOrSystemErr") PrintWriter writer = new PrintWriter(System.err); classLoader.dumpClasses(writer); writer.flush(); throw UtilsPackage.rethrow(e); } }
@Override public boolean processUsage(JetChangeInfo changeInfo, PsiElement element) { JetParameterList parameterList; JetPsiFactory psiFactory = JetPsiFactory(element.getProject()); if (element instanceof JetFunction) { JetFunction function = (JetFunction) element; parameterList = function.getValueParameterList(); if (changeInfo.isNameChanged()) { PsiElement identifier = function.getNameIdentifier(); if (identifier != null) { identifier.replace(psiFactory.createIdentifier(changeInfo.getNewName())); } } boolean returnTypeIsNeeded = (changeInfo.isRefactoringTarget(originalFunctionDescriptor) || !(function instanceof JetFunctionLiteral) || function.getTypeReference() != null) && !(function instanceof JetSecondaryConstructor); if (changeInfo.isReturnTypeChanged() && returnTypeIsNeeded) { function.setTypeReference(null); String returnTypeText = changeInfo.renderReturnType((JetFunctionDefinitionUsage<PsiElement>) this); // TODO use ChangeFunctionReturnTypeFix.invoke when JetTypeCodeFragment.getType() is ready if (!KotlinBuiltIns.getInstance().getUnitType().toString().equals(returnTypeText)) { ShortenPackage.addToShorteningWaitSet( function.setTypeReference(JetPsiFactory(function).createType(returnTypeText)), Options.DEFAULT); } } } else { parameterList = ((JetClass) element).getPrimaryConstructorParameterList(); } if (changeInfo.isParameterSetOrOrderChanged()) { processParameterListWithStructuralChanges(changeInfo, element, parameterList, psiFactory); } else if (parameterList != null) { int paramIndex = 0; for (JetParameter parameter : parameterList.getParameters()) { JetParameterInfo parameterInfo = changeInfo.getNewParameters()[paramIndex]; changeParameter(paramIndex, parameter, parameterInfo); paramIndex++; } ShortenPackage.addToShorteningWaitSet(parameterList, Options.DEFAULT); } if (element instanceof JetFunction && changeInfo.isReceiverTypeChanged()) { //noinspection unchecked String receiverTypeText = changeInfo.renderReceiverType((JetFunctionDefinitionUsage<PsiElement>) this); JetTypeReference receiverTypeRef = receiverTypeText != null ? psiFactory.createType(receiverTypeText) : null; JetTypeReference newReceiverTypeRef = TypeRefHelpersPackage.setReceiverTypeReference((JetFunction) element, receiverTypeRef); if (newReceiverTypeRef != null) { ShortenPackage.addToShorteningWaitSet( newReceiverTypeRef, ShortenReferences.Options.DEFAULT); } } if (changeInfo.isVisibilityChanged() && !JetPsiUtil.isLocal((JetDeclaration) element)) { changeVisibility(changeInfo, element); } return true; }
public void testConstants() throws Exception { assertType("1", builtIns.getIntType()); assertType("0x1", builtIns.getIntType()); assertType("0X1", builtIns.getIntType()); assertType("0b1", builtIns.getIntType()); assertType("0B1", builtIns.getIntType()); assertType("1.toLong()", builtIns.getLongType()); assertType("1.0", builtIns.getDoubleType()); assertType("1.0.toDouble()", builtIns.getDoubleType()); assertType("0x1.fffffffffffffp1023", builtIns.getDoubleType()); assertType("1.0.toFloat()", builtIns.getFloatType()); assertType("0x1.fffffffffffffp1023.toFloat()", builtIns.getFloatType()); assertType("true", builtIns.getBooleanType()); assertType("false", builtIns.getBooleanType()); assertType("'d'", builtIns.getCharType()); assertType("\"d\"", builtIns.getStringType()); assertType("\"\"\"d\"\"\"", builtIns.getStringType()); assertType("Unit", KotlinBuiltIns.getInstance().getUnitType()); assertType("null", KotlinBuiltIns.getInstance().getNullableNothingType()); }
public KotlinTypeInfo visitIfExpression( KtIfExpression ifExpression, ExpressionTypingContext contextWithExpectedType, boolean isStatement) { ExpressionTypingContext context = contextWithExpectedType.replaceExpectedType(NO_EXPECTED_TYPE); KtExpression condition = ifExpression.getCondition(); DataFlowInfo conditionDataFlowInfo = checkCondition(context.scope, condition, context); KtExpression elseBranch = ifExpression.getElse(); KtExpression thenBranch = ifExpression.getThen(); LexicalWritableScope thenScope = newWritableScopeImpl(context, "Then scope"); LexicalWritableScope elseScope = newWritableScopeImpl(context, "Else scope"); DataFlowInfo thenInfo = components .dataFlowAnalyzer .extractDataFlowInfoFromCondition(condition, true, context) .and(conditionDataFlowInfo); DataFlowInfo elseInfo = components .dataFlowAnalyzer .extractDataFlowInfoFromCondition(condition, false, context) .and(conditionDataFlowInfo); if (elseBranch == null) { if (thenBranch != null) { KotlinTypeInfo result = getTypeInfoWhenOnlyOneBranchIsPresent( thenBranch, thenScope, thenInfo, elseInfo, contextWithExpectedType, ifExpression, isStatement); // If jump was possible, take condition check info as the jump info return result.getJumpOutPossible() ? result.replaceJumpOutPossible(true).replaceJumpFlowInfo(conditionDataFlowInfo) : result; } return TypeInfoFactoryKt.createTypeInfo( components.dataFlowAnalyzer.checkImplicitCast( components.builtIns.getUnitType(), ifExpression, contextWithExpectedType, isStatement), thenInfo.or(elseInfo)); } if (thenBranch == null) { return getTypeInfoWhenOnlyOneBranchIsPresent( elseBranch, elseScope, elseInfo, thenInfo, contextWithExpectedType, ifExpression, isStatement); } KtPsiFactory psiFactory = KtPsiFactoryKt.KtPsiFactory(ifExpression); KtBlockExpression thenBlock = psiFactory.wrapInABlockWrapper(thenBranch); KtBlockExpression elseBlock = psiFactory.wrapInABlockWrapper(elseBranch); Call callForIf = createCallForSpecialConstruction( ifExpression, ifExpression, Lists.newArrayList(thenBlock, elseBlock)); MutableDataFlowInfoForArguments dataFlowInfoForArguments = createDataFlowInfoForArgumentsForIfCall(callForIf, thenInfo, elseInfo); ResolvedCall<FunctionDescriptor> resolvedCall = components.controlStructureTypingUtils.resolveSpecialConstructionAsCall( callForIf, ResolveConstruct.IF, Lists.newArrayList("thenBranch", "elseBranch"), Lists.newArrayList(false, false), contextWithExpectedType, dataFlowInfoForArguments); BindingContext bindingContext = context.trace.getBindingContext(); KotlinTypeInfo thenTypeInfo = BindingContextUtils.getRecordedTypeInfo(thenBranch, bindingContext); KotlinTypeInfo elseTypeInfo = BindingContextUtils.getRecordedTypeInfo(elseBranch, bindingContext); assert thenTypeInfo != null : "'Then' branch of if expression was not processed: " + ifExpression; assert elseTypeInfo != null : "'Else' branch of if expression was not processed: " + ifExpression; boolean loopBreakContinuePossible = thenTypeInfo.getJumpOutPossible() || elseTypeInfo.getJumpOutPossible(); KotlinType thenType = thenTypeInfo.getType(); KotlinType elseType = elseTypeInfo.getType(); DataFlowInfo thenDataFlowInfo = thenTypeInfo.getDataFlowInfo(); DataFlowInfo elseDataFlowInfo = elseTypeInfo.getDataFlowInfo(); boolean jumpInThen = thenType != null && KotlinBuiltIns.isNothing(thenType); boolean jumpInElse = elseType != null && KotlinBuiltIns.isNothing(elseType); DataFlowInfo resultDataFlowInfo; if (thenType == null && elseType == null) { resultDataFlowInfo = thenDataFlowInfo.or(elseDataFlowInfo); } else if (thenType == null || (jumpInThen && !jumpInElse)) { resultDataFlowInfo = elseDataFlowInfo; } else if (elseType == null || (jumpInElse && !jumpInThen)) { resultDataFlowInfo = thenDataFlowInfo; } else { resultDataFlowInfo = thenDataFlowInfo.or(elseDataFlowInfo); } KotlinType resultType = resolvedCall.getResultingDescriptor().getReturnType(); // If break or continue was possible, take condition check info as the jump info return TypeInfoFactoryKt.createTypeInfo( components.dataFlowAnalyzer.checkImplicitCast( resultType, ifExpression, contextWithExpectedType, isStatement), resultDataFlowInfo, loopBreakContinuePossible, conditionDataFlowInfo); }
public void testJumps() throws Exception { assertType("throw java.lang.Exception()", KotlinBuiltIns.getInstance().getNothingType()); assertType("continue", KotlinBuiltIns.getInstance().getNothingType()); assertType("break", KotlinBuiltIns.getInstance().getNothingType()); }
private void generateDataClassHashCodeIfNeeded(@NotNull List<PropertyDescriptor> properties) { FunctionDescriptor function = getDeclaredMember("hashCode", builtIns.getInt()); if (function != null && isTrivial(function)) { generateHashCodeMethod(function, properties); } }
@Override public KotlinTypeInfo visitReturnExpression( @NotNull KtReturnExpression expression, ExpressionTypingContext context) { KtElement labelTargetElement = LabelResolver.INSTANCE.resolveControlLabel(expression, context); KtExpression returnedExpression = expression.getReturnedExpression(); KotlinType expectedType = NO_EXPECTED_TYPE; KotlinType resultType = components.builtIns.getNothingType(); KtDeclaration parentDeclaration = PsiTreeUtil.getParentOfType(expression, KtDeclaration.class); if (parentDeclaration instanceof KtParameter) { // In a default value for parameter context.trace.report(RETURN_NOT_ALLOWED.on(expression)); } if (expression.getTargetLabel() == null) { while (parentDeclaration instanceof KtMultiDeclaration) { // TODO: It's hacking fix for KT-5100: Strange "Return is not allowed here" for // multi-declaration initializer with elvis expression parentDeclaration = PsiTreeUtil.getParentOfType(parentDeclaration, KtDeclaration.class); } assert parentDeclaration != null : "Can't find parent declaration for " + expression.getText(); DeclarationDescriptor declarationDescriptor = context.trace.get(DECLARATION_TO_DESCRIPTOR, parentDeclaration); Pair<FunctionDescriptor, PsiElement> containingFunInfo = BindingContextUtils.getContainingFunctionSkipFunctionLiterals( declarationDescriptor, false); FunctionDescriptor containingFunctionDescriptor = containingFunInfo.getFirst(); if (containingFunctionDescriptor != null) { if (!InlineUtil.checkNonLocalReturnUsage( containingFunctionDescriptor, expression, context.trace) || isClassInitializer(containingFunInfo)) { // Unqualified, in a function literal context.trace.report(RETURN_NOT_ALLOWED.on(expression)); resultType = ErrorUtils.createErrorType(RETURN_NOT_ALLOWED_MESSAGE); } expectedType = getFunctionExpectedReturnType( containingFunctionDescriptor, (KtElement) containingFunInfo.getSecond(), context); } else { // Outside a function context.trace.report(RETURN_NOT_ALLOWED.on(expression)); resultType = ErrorUtils.createErrorType(RETURN_NOT_ALLOWED_MESSAGE); } } else if (labelTargetElement != null) { SimpleFunctionDescriptor functionDescriptor = context.trace.get(FUNCTION, labelTargetElement); if (functionDescriptor != null) { expectedType = getFunctionExpectedReturnType(functionDescriptor, labelTargetElement, context); if (!InlineUtil.checkNonLocalReturnUsage(functionDescriptor, expression, context.trace)) { // Qualified, non-local context.trace.report(RETURN_NOT_ALLOWED.on(expression)); resultType = ErrorUtils.createErrorType(RETURN_NOT_ALLOWED_MESSAGE); } } else { context.trace.report(NOT_A_RETURN_LABEL.on(expression, expression.getLabelName())); } } if (returnedExpression != null) { facade.getTypeInfo( returnedExpression, context .replaceExpectedType(expectedType) .replaceScope(context.scope) .replaceContextDependency(INDEPENDENT)); } else { if (expectedType != null && !noExpectedType(expectedType) && !KotlinBuiltIns.isUnit(expectedType) && !isDontCarePlaceholder(expectedType)) // for lambda with implicit return type Unit { context.trace.report(RETURN_TYPE_MISMATCH.on(expression, expectedType)); } } return components.dataFlowAnalyzer.createCheckedTypeInfo(resultType, context, expression); }
@Nullable public KotlinType checkIterableConvention( @NotNull ExpressionReceiver loopRange, ExpressionTypingContext context) { KtExpression loopRangeExpression = loopRange.getExpression(); // Make a fake call loopRange.iterator(), and try to resolve it Name iterator = Name.identifier("iterator"); Pair<Call, OverloadResolutionResults<FunctionDescriptor>> calls = fakeCallResolver.makeAndResolveFakeCall( loopRange, context, Collections.<KtExpression>emptyList(), iterator, loopRangeExpression, FakeCallKind.ITERATOR, loopRangeExpression); OverloadResolutionResults<FunctionDescriptor> iteratorResolutionResults = calls.getSecond(); if (iteratorResolutionResults.isSuccess()) { ResolvedCall<FunctionDescriptor> iteratorResolvedCall = iteratorResolutionResults.getResultingCall(); context.trace.record( LOOP_RANGE_ITERATOR_RESOLVED_CALL, loopRangeExpression, iteratorResolvedCall); FunctionDescriptor iteratorFunction = iteratorResolvedCall.getResultingDescriptor(); checkIfOperatorModifierPresent(loopRangeExpression, iteratorFunction, context.trace); symbolUsageValidator.validateCall( iteratorResolvedCall, iteratorFunction, context.trace, loopRangeExpression); KotlinType iteratorType = iteratorFunction.getReturnType(); KotlinType hasNextType = checkConventionForIterator( context, loopRangeExpression, iteratorType, "hasNext", HAS_NEXT_FUNCTION_AMBIGUITY, HAS_NEXT_MISSING, HAS_NEXT_FUNCTION_NONE_APPLICABLE, LOOP_RANGE_HAS_NEXT_RESOLVED_CALL); if (hasNextType != null && !builtIns.isBooleanOrSubtype(hasNextType)) { context.trace.report(HAS_NEXT_FUNCTION_TYPE_MISMATCH.on(loopRangeExpression, hasNextType)); } return checkConventionForIterator( context, loopRangeExpression, iteratorType, "next", NEXT_AMBIGUITY, NEXT_MISSING, NEXT_NONE_APPLICABLE, LOOP_RANGE_NEXT_RESOLVED_CALL); } else { if (iteratorResolutionResults.isAmbiguity()) { context.trace.report( ITERATOR_AMBIGUITY.on( loopRangeExpression, iteratorResolutionResults.getResultingCalls())); } else { context.trace.report(ITERATOR_MISSING.on(loopRangeExpression)); } } return null; }
private TypeProjection makeType(String typeStr) { return makeTypeProjection(builtIns.getBuiltInsPackageScope(), typeStr); }
@Override public void updateUI( Pair<? extends FunctionDescriptor, ResolutionFacade> itemToShow, @NotNull ParameterInfoUIContext context) { // todo: when we will have ability to pass Array as vararg, implement such feature here too? if (context == null || context.getParameterOwner() == null || !context.getParameterOwner().isValid()) { context.setUIComponentEnabled(false); return; } PsiElement parameterOwner = context.getParameterOwner(); if (!(parameterOwner instanceof JetValueArgumentList)) { context.setUIComponentEnabled(false); return; } JetValueArgumentList argumentList = (JetValueArgumentList) parameterOwner; FunctionDescriptor functionDescriptor = itemToShow.first; ResolutionFacade resolutionFacade = itemToShow.second; List<ValueParameterDescriptor> valueParameters = functionDescriptor.getValueParameters(); List<JetValueArgument> valueArguments = argumentList.getArguments(); int currentParameterIndex = context.getCurrentParameterIndex(); int boldStartOffset = -1; int boldEndOffset = -1; boolean isGrey = false; boolean isDeprecated = KotlinBuiltIns.isDeprecated(functionDescriptor); boolean[] usedIndexes = new boolean[valueParameters.size()]; Arrays.fill(usedIndexes, false); boolean namedMode = false; if (!isIndexValid(valueParameters, currentParameterIndex)) { isGrey = true; } StringBuilder builder = new StringBuilder(); PsiElement owner = context.getParameterOwner(); BindingContext bindingContext = resolutionFacade.analyze((JetElement) owner, BodyResolveMode.FULL); for (int i = 0; i < valueParameters.size(); ++i) { if (i != 0) { builder.append(", "); } boolean highlightParameter = i == currentParameterIndex || (!namedMode && i < currentParameterIndex && Iterables.getLast(valueParameters).getVarargElementType() != null); if (highlightParameter) { boldStartOffset = builder.length(); } if (!namedMode) { if (valueArguments.size() > i) { JetValueArgument argument = valueArguments.get(i); if (argument.isNamed()) { namedMode = true; } else { ValueParameterDescriptor param = valueParameters.get(i); builder.append(renderParameter(param, false)); if (i <= currentParameterIndex && !isArgumentTypeValid(bindingContext, argument, param)) { isGrey = true; } usedIndexes[i] = true; } } else { ValueParameterDescriptor param = valueParameters.get(i); builder.append(renderParameter(param, false)); } } if (namedMode) { boolean takeAnyArgument = true; if (valueArguments.size() > i) { JetValueArgument argument = valueArguments.get(i); if (argument.isNamed()) { for (int j = 0; j < valueParameters.size(); ++j) { JetSimpleNameExpression referenceExpression = argument.getArgumentName().getReferenceExpression(); ValueParameterDescriptor param = valueParameters.get(j); if (referenceExpression != null && !usedIndexes[j] && param.getName().equals(referenceExpression.getReferencedNameAsName())) { takeAnyArgument = false; usedIndexes[j] = true; builder.append(renderParameter(param, true)); if (i < currentParameterIndex && !isArgumentTypeValid(bindingContext, argument, param)) { isGrey = true; } break; } } } } if (takeAnyArgument) { if (i < currentParameterIndex) { isGrey = true; } for (int j = 0; j < valueParameters.size(); ++j) { ValueParameterDescriptor param = valueParameters.get(j); if (!usedIndexes[j]) { usedIndexes[j] = true; builder.append(renderParameter(param, true)); break; } } } } if (highlightParameter) { boldEndOffset = builder.length(); } } if (valueParameters.size() == 0) { builder.append(CodeInsightBundle.message("parameter.info.no.parameters")); } assert !builder.toString().isEmpty() : "A message about 'no parameters' or some parameters should be present: " + functionDescriptor; Color color = isResolvedToDescriptor(argumentList, functionDescriptor, bindingContext) ? GREEN_BACKGROUND : context.getDefaultParameterColor(); context.setupUIComponentPresentation( builder.toString(), boldStartOffset, boldEndOffset, isGrey, isDeprecated, false, color); }
private void generateDataClassToStringIfNeeded(@NotNull List<PropertyDescriptor> properties) { FunctionDescriptor function = getDeclaredMember("toString", builtIns.getString()); if (function != null && isTrivial(function)) { generateToStringMethod(function, properties); } }