diff --git a/annotations/com/intellij/util/annotations.xml b/annotations/com/intellij/util/annotations.xml index b6951be234c..3aa90806ee8 100644 --- a/annotations/com/intellij/util/annotations.xml +++ b/annotations/com/intellij/util/annotations.xml @@ -14,4 +14,10 @@ + + + + + + \ No newline at end of file diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilder.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilder.java index 1c37511288e..b2f168f55c3 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilder.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilder.java @@ -20,6 +20,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.cfg.pseudocode.PseudoValue; import org.jetbrains.jet.lang.cfg.pseudocode.Pseudocode; +import org.jetbrains.jet.lang.cfg.pseudocode.TypePredicate; import org.jetbrains.jet.lang.cfg.pseudocode.instructions.eval.AccessTarget; import org.jetbrains.jet.lang.descriptors.ReceiverParameterDescriptor; import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor; @@ -115,6 +116,7 @@ public interface JetControlFlowBuilder { @NotNull JetElement instructionElement, @Nullable JetElement valueElement, @NotNull List inputValues, + @NotNull Map expectedTypes, boolean synthetic ); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilderAdapter.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilderAdapter.java index acd15845357..ce21685711b 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilderAdapter.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilderAdapter.java @@ -20,6 +20,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.cfg.pseudocode.PseudoValue; import org.jetbrains.jet.lang.cfg.pseudocode.Pseudocode; +import org.jetbrains.jet.lang.cfg.pseudocode.TypePredicate; import org.jetbrains.jet.lang.cfg.pseudocode.instructions.eval.AccessTarget; import org.jetbrains.jet.lang.descriptors.ReceiverParameterDescriptor; import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor; @@ -71,9 +72,10 @@ public abstract class JetControlFlowBuilderAdapter implements JetControlFlowBuil @NotNull JetElement instructionElement, @Nullable JetElement valueElement, @NotNull List inputValues, + @NotNull Map expectedTypes, boolean synthetic ) { - return getDelegateBuilder().magic(instructionElement, valueElement, inputValues, synthetic); + return getDelegateBuilder().magic(instructionElement, valueElement, inputValues, expectedTypes, synthetic); } @NotNull diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java index 679f9bd2487..38108fe0e50 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java @@ -22,16 +22,12 @@ import com.intellij.psi.PsiElement; import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.SmartFMap; -import com.intellij.util.containers.ContainerUtil; import kotlin.Function0; import kotlin.Function1; import kotlin.KotlinPackage; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowInstructionsGenerator; -import org.jetbrains.jet.lang.cfg.pseudocode.PseudoValue; -import org.jetbrains.jet.lang.cfg.pseudocode.Pseudocode; -import org.jetbrains.jet.lang.cfg.pseudocode.PseudocodeImpl; +import org.jetbrains.jet.lang.cfg.pseudocode.*; import org.jetbrains.jet.lang.cfg.pseudocode.instructions.eval.AccessTarget; import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.psi.*; @@ -188,12 +184,24 @@ public class JetControlFlowProcessor { @NotNull private PseudoValue createSyntheticValue(@NotNull JetElement instructionElement) { - return builder.magic(instructionElement, null, Collections.emptyList(), true); + return createSyntheticValue(instructionElement, Collections.emptyList()); + } + + @NotNull + private PseudoValue createSyntheticValue(@NotNull JetElement instructionElement, @NotNull List from) { + List values = elementsToValues(from); + return builder.magic(instructionElement, null, values, defaultTypeMap(values), true); } @NotNull private PseudoValue createNonSyntheticValue(@NotNull List from, @NotNull JetElement to) { - return builder.magic(to, to, elementsToValues(from), false); + List values = elementsToValues(from); + return builder.magic(to, to, values, defaultTypeMap(values), false); + } + + @NotNull + private Map defaultTypeMap(List values) { + return PseudocodePackage.expectedTypeFor(AllTypes.instance$, values); } private void mergeValues(@NotNull List from, @NotNull JetExpression to) { @@ -218,10 +226,10 @@ public class JetControlFlowProcessor { } private List elementsToValues(List from) { + if (from.isEmpty()) return Collections.emptyList(); return KotlinPackage.filterNotNull( - KotlinPackage.mapTo( + KotlinPackage.map( from, - new LinkedHashSet(), new Function1() { @Override public PseudoValue invoke(JetElement element) { @@ -862,12 +870,17 @@ public class JetControlFlowProcessor { private void writeLoopParameterAssignment(JetForExpression expression) { JetParameter loopParameter = expression.getLoopParameter(); JetMultiDeclaration multiDeclaration = expression.getMultiParameter(); - JetExpression loopRange = expression.getLoopRange(); + + JetType loopRangeType = trace.get(BindingContext.EXPRESSION_TYPE, loopRange); + TypePredicate loopRangeTypeSet = loopRangeType != null ? new SingleType(loopRangeType) : AllTypes.instance$; + PseudoValue loopRangeValue = builder.getBoundValue(loopRange); + PseudoValue value = builder.magic( loopRange != null ? loopRange : expression, null, - Collections.singletonList(builder.getBoundValue(loopRange)), + Collections.singletonList(loopRangeValue), + Collections.singletonMap(loopRangeValue, loopRangeTypeSet), true ); @@ -1058,7 +1071,10 @@ public class JetControlFlowProcessor { inputExpressions.add(calleeExpression); inputExpressions.add(generateAndGetReceiverIfAny(expression)); - createNonSyntheticValue(inputExpressions, calleeExpression != null ? calleeExpression : expression); + createNonSyntheticValue( + inputExpressions, + calleeExpression != null ? calleeExpression : expression + ); } copyValue(calleeExpression, expression); @@ -1106,16 +1122,16 @@ public class JetControlFlowProcessor { generateInstructions(initializer, NOT_IN_CONDITION); for (JetMultiDeclarationEntry entry : declaration.getEntries()) { builder.declareVariable(entry); + ResolvedCall resolvedCall = trace.get(BindingContext.COMPONENT_RESOLVED_CALL, entry); PseudoValue writtenValue = resolvedCall != null ? builder.call( - entry, - resolvedCall, - getReceiverValues(resolvedCall, false), - Collections.emptyMap() - ) - : builder.magic(entry, null, - ContainerUtil.createMaybeSingletonList(builder.getBoundValue(initializer)), true); + entry, + resolvedCall, + getReceiverValues(resolvedCall, false), + Collections.emptyMap() + ) + : createSyntheticValue(entry, Collections.singletonList(initializer)); if (generateWriteForEntries) { generateInitializer(entry, writtenValue != null ? writtenValue : createSyntheticValue(entry)); } @@ -1209,9 +1225,7 @@ public class JetControlFlowProcessor { JetWhenCondition condition = conditions[i]; condition.accept(conditionVisitor, context); if (i + 1 < conditions.length) { - PseudoValue conditionValue = builder.magic( - condition, null, elementsToValues(Arrays.asList(subjectExpression, condition)), true - ); + PseudoValue conditionValue = createSyntheticValue(condition, Arrays.asList(subjectExpression, condition)); builder.nondeterministicJump(bodyLabel, expression, conditionValue); } } @@ -1221,9 +1235,7 @@ public class JetControlFlowProcessor { PseudoValue conditionValue = null; JetWhenCondition lastCondition = KotlinPackage.lastOrNull(conditions); if (lastCondition != null) { - conditionValue = builder.magic( - lastCondition, null, elementsToValues(Arrays.asList(subjectExpression, lastCondition)), true - ); + conditionValue = createSyntheticValue(lastCondition, Arrays.asList(subjectExpression, lastCondition)); } builder.nondeterministicJump(nextLabel, expression, conditionValue); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/JetControlFlowInstructionsGenerator.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/JetControlFlowInstructionsGenerator.java index ba1eee9dc8e..21878b53024 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/JetControlFlowInstructionsGenerator.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/JetControlFlowInstructionsGenerator.java @@ -420,7 +420,8 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd @NotNull @Override public PseudoValue loadStringTemplate(@NotNull JetStringTemplateExpression expression, @NotNull List inputValues) { - return inputValues.isEmpty() ? read(expression) : magic(expression, expression, inputValues, false); + if (inputValues.isEmpty()) return read(expression); + return magic(expression, expression, inputValues, PseudocodePackage.expectedTypeFor(AllTypes.instance$, inputValues), false); } @NotNull @@ -429,10 +430,12 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd @NotNull JetElement instructionElement, @Nullable JetElement valueElement, @NotNull List inputValues, + @NotNull Map expectedTypes, boolean synthetic ) { - MagicInstruction instruction = - MagicInstruction.object$.create(instructionElement, valueElement, getCurrentScope(), synthetic, inputValues, valueFactory); + MagicInstruction instruction = MagicInstruction.object$.create( + instructionElement, valueElement, getCurrentScope(), synthetic, inputValues, expectedTypes, valueFactory + ); add(instruction); return instruction.getOutputValue(); } @@ -489,7 +492,21 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd @NotNull PredefinedOperation operation, @NotNull List inputValues ) { - return magic(expression, expression, inputValues, false); + Map expectedTypes; + switch(operation) { + case AND: + case OR: + SingleType onlyBoolean = new SingleType(KotlinBuiltIns.getInstance().getBooleanType()); + expectedTypes = PseudocodePackage.expectedTypeFor(onlyBoolean, inputValues); + break; + case NOT_NULL_ASSERTION: + expectedTypes = PseudocodePackage.expectedTypeFor(AllTypes.instance$, inputValues); + break; + default: + throw new IllegalArgumentException("Invalid operation: " + operation); + } + + return magic(expression, expression, inputValues, expectedTypes, false); } @Override diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/TypePredicate.kt b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/TypePredicate.kt new file mode 100644 index 00000000000..ac4bd2030cb --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/TypePredicate.kt @@ -0,0 +1,44 @@ +/* + * Copyright 2010-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.jet.lang.cfg.pseudocode + +import org.jetbrains.jet.lang.types.JetType +import org.jetbrains.jet.lang.types.checker.JetTypeChecker +import org.jetbrains.jet.renderer.DescriptorRenderer +import com.intellij.util.SmartFMap +import org.jetbrains.jet.lang.types.TypeUtils + +public trait TypePredicate: (JetType) -> Boolean { + [suppress("PARAMETER_NAME_CHANGED_ON_OVERRIDE")] + override fun invoke(typeToCheck: JetType): Boolean +} + +public data class SingleType(val targetType: JetType): TypePredicate { + override fun invoke(typeToCheck: JetType): Boolean = JetTypeChecker.INSTANCE.equalTypes(typeToCheck, targetType) + override fun toString(): String = targetType.render() +} + +public object AllTypes : TypePredicate { + override fun invoke(typeToCheck: JetType): Boolean = true + + override fun toString(): String = "" +} + +private fun JetType.render(): String = DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderType(this) + +public fun TypePredicate.expectedTypeFor(keys: Iterable): Map = + keys.fold(SmartFMap.emptyMap()) { (map, key) -> map.plus(key, this) } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/instructions/eval/operationInstructions.kt b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/instructions/eval/operationInstructions.kt index 1696f9013c3..a5d704c3da4 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/instructions/eval/operationInstructions.kt +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/instructions/eval/operationInstructions.kt @@ -26,6 +26,7 @@ import org.jetbrains.jet.lang.cfg.pseudocode.instructions.InstructionVisitor import org.jetbrains.jet.lang.cfg.pseudocode.instructions.InstructionVisitorWithResult import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor +import org.jetbrains.jet.lang.cfg.pseudocode.TypePredicate public abstract class OperationInstruction protected( element: JetElement, @@ -102,8 +103,13 @@ public class MagicInstruction( element: JetElement, lexicalScope: LexicalScope, val synthetic: Boolean, - inputValues: List + inputValues: List, + val expectedTypes: Map ) : OperationInstruction(element, lexicalScope, inputValues), StrictlyValuedOperationInstruction { + protected fun setResult(valueElement: JetElement?, factory: PseudoValueFactory?): OperationInstruction { + return setResult(factory?.newValue(valueElement, this)) + } + override fun accept(visitor: InstructionVisitor) { visitor.visitMagic(this) } @@ -113,7 +119,7 @@ public class MagicInstruction( } override fun createCopy() = - MagicInstruction(element, lexicalScope, synthetic, inputValues).setResult(resultValue) + MagicInstruction(element, lexicalScope, synthetic, inputValues, expectedTypes).setResult(resultValue) override fun toString() = renderInstruction("magic", render(element)) @@ -124,8 +130,11 @@ public class MagicInstruction( lexicalScope: LexicalScope, synthetic: Boolean, inputValues: List, + expectedTypes: Map, factory: PseudoValueFactory - ): MagicInstruction = MagicInstruction(element, lexicalScope, synthetic, inputValues).setResult(factory, valueElement) as MagicInstruction + ): MagicInstruction = MagicInstruction( + element, lexicalScope, synthetic, inputValues, expectedTypes + ).setResult(factory, valueElement) as MagicInstruction } }