diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/GenerationState.java b/compiler/backend/src/org/jetbrains/jet/codegen/GenerationState.java index 56b432cf2c9..c106eeaed70 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/GenerationState.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/GenerationState.java @@ -30,7 +30,7 @@ public class GenerationState { public GenerationState(Project project, ClassBuilderFactory builderFactory) { this.project = project; - this.standardLibrary = JetStandardLibrary.getJetStandardLibrary(project); + this.standardLibrary = JetStandardLibrary.getJetStandardLibrary(project, true); this.factory = new ClassFileFactory(builderFactory, this); this.intrinsics = new IntrinsicMethods(project, standardLibrary); } @@ -82,7 +82,7 @@ public class GenerationState { public void compile(JetFile psiFile) { final JetNamespace namespace = psiFile.getRootNamespace(); - final BindingContext bindingContext = AnalyzingUtils.getInstance(JavaDefaultImports.JAVA_DEFAULT_IMPORTS).analyzeNamespace(namespace, JetControlFlowDataTraceFactory.EMPTY); + final BindingContext bindingContext = AnalyzingUtils.getInstance(JavaDefaultImports.JAVA_DEFAULT_IMPORTS, true).analyzeNamespace(namespace, JetControlFlowDataTraceFactory.EMPTY); AnalyzingUtils.throwExceptionOnErrors(bindingContext); compileCorrectNamespaces(bindingContext, Collections.singletonList(namespace)); // NamespaceCodegen codegen = forNamespace(namespace); diff --git a/compiler/backend/src/org/jetbrains/jet/compiler/CompileSession.java b/compiler/backend/src/org/jetbrains/jet/compiler/CompileSession.java index e90fda9eb8a..43f4661b726 100644 --- a/compiler/backend/src/org/jetbrains/jet/compiler/CompileSession.java +++ b/compiler/backend/src/org/jetbrains/jet/compiler/CompileSession.java @@ -84,7 +84,7 @@ public class CompileSession { } return false; } - final AnalyzingUtils instance = AnalyzingUtils.getInstance(JavaDefaultImports.JAVA_DEFAULT_IMPORTS); + final AnalyzingUtils instance = AnalyzingUtils.getInstance(JavaDefaultImports.JAVA_DEFAULT_IMPORTS, true); List allNamespaces = new ArrayList(mySourceFileNamespaces); allNamespaces.addAll(myLibrarySourceFileNamespaces); myBindingContext = instance.analyzeNamespaces(myEnvironment.getProject(), allNamespaces, Predicates.alwaysTrue(), JetControlFlowDataTraceFactory.EMPTY); diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/AnalyzerFacade.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/AnalyzerFacade.java index 6ad38396927..9be40fce997 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/AnalyzerFacade.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/AnalyzerFacade.java @@ -34,7 +34,7 @@ public class AnalyzerFacade { } }; - private static final AnalyzingUtils ANALYZING_UTILS = AnalyzingUtils.getInstance(JavaDefaultImports.JAVA_DEFAULT_IMPORTS); + private static final AnalyzingUtils ANALYZING_UTILS = AnalyzingUtils.getInstance(JavaDefaultImports.JAVA_DEFAULT_IMPORTS, true); private final static Key> BINDING_CONTEXT = Key.create("BINDING_CONTEXT"); private static final Object lock = new Object(); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/JetSemanticServices.java b/compiler/frontend/src/org/jetbrains/jet/lang/JetSemanticServices.java index 5a73728db37..c666125cd19 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/JetSemanticServices.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/JetSemanticServices.java @@ -17,7 +17,11 @@ public class JetSemanticServices { } public static JetSemanticServices createSemanticServices(Project project) { - return new JetSemanticServices(JetStandardLibrary.getJetStandardLibrary(project)); + return createSemanticServices(project, true); + } + + public static JetSemanticServices createSemanticServices(Project project, boolean loadFullLibrary) { + return new JetSemanticServices(JetStandardLibrary.getJetStandardLibrary(project, loadFullLibrary)); } private final JetStandardLibrary standardLibrary; diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/CallableDescriptor.java b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/CallableDescriptor.java index 4e78d2c81f5..afc9560badb 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/CallableDescriptor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/CallableDescriptor.java @@ -1,6 +1,7 @@ package org.jetbrains.jet.lang.descriptors; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.TypeSubstitutor; @@ -24,6 +25,9 @@ public interface CallableDescriptor extends DeclarationDescriptor { @NotNull JetType getReturnType(); + @Nullable + JetType getReturnTypeSafe(); + @NotNull @Override CallableDescriptor getOriginal(); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/FunctionDescriptorImpl.java b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/FunctionDescriptorImpl.java index ef3ab5aefa0..7f8a7943a88 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/FunctionDescriptorImpl.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/FunctionDescriptorImpl.java @@ -125,6 +125,12 @@ public class FunctionDescriptorImpl extends DeclarationDescriptorImpl implements return unsubstitutedReturnType; } + @Override + @Nullable + public JetType getReturnTypeSafe() { + return unsubstitutedReturnType; + } + @NotNull @Override public FunctionDescriptor getOriginal() { diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/PropertyDescriptor.java b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/PropertyDescriptor.java index 354979ecac9..1205e95477d 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/PropertyDescriptor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/PropertyDescriptor.java @@ -118,6 +118,11 @@ public class PropertyDescriptor extends VariableDescriptorImpl implements Callab return getOutType(); } + @Override + @Nullable + public JetType getReturnTypeSafe() { + return getOutType(); + } public boolean isVar() { return isVar; diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/PropertyGetterDescriptor.java b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/PropertyGetterDescriptor.java index 01bde2bf062..753d0cd4923 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/PropertyGetterDescriptor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/PropertyGetterDescriptor.java @@ -45,6 +45,12 @@ public class PropertyGetterDescriptor extends PropertyAccessorDescriptor { return returnType; } + @Override + @Nullable + public JetType getReturnTypeSafe() { + return returnType; + } + @Override public R accept(DeclarationDescriptorVisitor visitor, D data) { return visitor.visitPropertyGetterDescriptor(this, data); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/PropertySetterDescriptor.java b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/PropertySetterDescriptor.java index d5f2038a282..365aa645651 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/PropertySetterDescriptor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/PropertySetterDescriptor.java @@ -53,6 +53,11 @@ public class PropertySetterDescriptor extends PropertyAccessorDescriptor { return JetStandardClasses.getUnitType(); } + @Override + public JetType getReturnTypeSafe() { + return getReturnType(); + } + @Override public R accept(DeclarationDescriptorVisitor visitor, D data) { return visitor.visitPropertySetterDescriptor(this, data); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/VariableDescriptorImpl.java b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/VariableDescriptorImpl.java index 6daefbce285..827fcbeab9a 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/VariableDescriptorImpl.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/VariableDescriptorImpl.java @@ -89,4 +89,10 @@ public abstract class VariableDescriptorImpl extends DeclarationDescriptorImpl i public JetType getReturnType() { return getOutType(); } + + @Override + @Nullable + public JetType getReturnTypeSafe() { + return getOutType(); + } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java index da7edd9d6fe..785e9abbae6 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java @@ -16,6 +16,7 @@ import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.Collection; import java.util.Iterator; +import java.util.List; import static org.jetbrains.jet.lang.diagnostics.Severity.ERROR; import static org.jetbrains.jet.lang.diagnostics.Severity.WARNING; @@ -275,7 +276,10 @@ public interface Errors { ParameterizedDiagnosticFactory2 TYPE_MISMATCH_IN_TUPLE_PATTERN = ParameterizedDiagnosticFactory2.create(ERROR, "Type mismatch: subject is of type {0} but the pattern is of type Tuple{1}"); // TODO: message ParameterizedDiagnosticFactory2 TYPE_MISMATCH_IN_BINDING_PATTERN = ParameterizedDiagnosticFactory2.create(ERROR, "{0} must be a supertype of {1}. Use 'is' to match against {0}"); ParameterizedDiagnosticFactory2 INCOMPATIBLE_TYPES = ParameterizedDiagnosticFactory2.create(ERROR, "Incompatible types: {0} and {1}"); - + + ParameterizedDiagnosticFactory1 CANNOT_CHECK_FOR_ERASED = ParameterizedDiagnosticFactory1.create(ERROR, "Cannot check for instance of erased type: {0}"); + ParameterizedDiagnosticFactory2 UNCHECKED_CAST = ParameterizedDiagnosticFactory2.create(WARNING, "Unchecked cast: {0} to {1}"); + ParameterizedDiagnosticFactory3> INCONSISTENT_TYPE_PARAMETER_VALUES = new ParameterizedDiagnosticFactory3>(ERROR, "Type parameter {0} of {1} has inconsistent values: {2}") { @Override protected String makeMessageForA(@NotNull TypeParameterDescriptor typeParameterDescriptor) { diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/AnalyzingUtils.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/AnalyzingUtils.java index 483a5673739..2eb18914627 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/AnalyzingUtils.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/AnalyzingUtils.java @@ -28,8 +28,8 @@ import java.util.*; * @author abreslav */ public class AnalyzingUtils { - public static AnalyzingUtils getInstance(@NotNull ImportingStrategy importingStrategy) { - return new AnalyzingUtils(importingStrategy); + public static AnalyzingUtils getInstance(@NotNull ImportingStrategy importingStrategy, boolean loadStdlib) { + return new AnalyzingUtils(importingStrategy, loadStdlib); } public static void checkForSyntacticErrors(@NotNull PsiElement root) { @@ -53,9 +53,11 @@ public class AnalyzingUtils { } private final ImportingStrategy importingStrategy; + private final boolean loadStdlib; - private AnalyzingUtils(ImportingStrategy importingStrategy) { + private AnalyzingUtils(ImportingStrategy importingStrategy, boolean loadStdlib) { this.importingStrategy = importingStrategy; + this.loadStdlib = loadStdlib; } public BindingContext analyzeNamespace(@NotNull JetNamespace namespace, @NotNull JetControlFlowDataTraceFactory flowDataTraceFactory) { @@ -71,7 +73,7 @@ public class AnalyzingUtils { @NotNull Predicate filesToAnalyzeCompletely, @NotNull JetControlFlowDataTraceFactory flowDataTraceFactory) { BindingTraceContext bindingTraceContext = new BindingTraceContext(); - JetSemanticServices semanticServices = JetSemanticServices.createSemanticServices(project); + JetSemanticServices semanticServices = JetSemanticServices.createSemanticServices(project, loadStdlib); JetScope libraryScope = semanticServices.getStandardLibrary().getLibraryScope(); ModuleDescriptor owner = new ModuleDescriptor(""); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BodyResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BodyResolver.java index ef5e309947f..7637f611a8e 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BodyResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BodyResolver.java @@ -82,7 +82,7 @@ public class BodyResolver { resolveSecondaryConstructorBodies(); resolveFunctionBodies(); - computeDeferredTypes(); + computeDeferredTypes(); } private void resolveDelegationSpecifierLists() { @@ -501,6 +501,18 @@ public class BodyResolver { for (Map.Entry entry : this.context.getFunctions().entrySet()) { JetNamedFunction declaration = entry.getKey(); FunctionDescriptor descriptor = entry.getValue(); + + if (descriptor.getReturnType() instanceof DeferredType) { + // handle type inference loop: function body contains a closure that calls that function + // + // fun f() = { f() } + // + // function type resolution must be started before function body resolution + // + + DeferredType returnType = (DeferredType) descriptor.getReturnType(); + returnType.getActualType(); + } JetScope declaringScope = this.context.getDeclaringScopes().get(declaration); assert declaringScope != null; @@ -545,7 +557,8 @@ public class BodyResolver { private void computeDeferredTypes() { Collection> deferredTypes = context.getTrace().getKeys(DEFERRED_TYPE); if (deferredTypes != null) { - final Queue queue = new Queue(deferredTypes.size()); + // +1 is a work around agains new Queue(0).addLast(...) bug // stepan.koltsov@ 2011-11-21 + final Queue queue = new Queue(deferredTypes.size() + 1); context.getTrace().addHandler(DEFERRED_TYPE, new ObservableBindingTrace.RecordHandler, Boolean>() { @Override public void handleRecord(WritableSlice, Boolean> deferredTypeKeyDeferredTypeWritableSlice, Box key, Boolean value) { diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/JetStandardLibrary.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/JetStandardLibrary.java index 62923713125..c90e935e043 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/JetStandardLibrary.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/JetStandardLibrary.java @@ -29,16 +29,24 @@ import java.util.Set; public class JetStandardLibrary { // TODO : consider releasing this memory - private static JetStandardLibrary cachedLibrary = null; + private static JetStandardLibrary cachedFullLibrary = null; + private static JetStandardLibrary cachedQuickLibrary = null; // private static final Map standardLibraryCache = new HashMap(); // TODO : double checked locking synchronized - public static JetStandardLibrary getJetStandardLibrary(@NotNull Project project) { - if (cachedLibrary == null) { - cachedLibrary = new JetStandardLibrary(project); + public static JetStandardLibrary getJetStandardLibrary(@NotNull Project project, boolean loadFullLibrary) { + if (loadFullLibrary) { + if (cachedFullLibrary == null) { + cachedFullLibrary = new JetStandardLibrary(project, true); + } + return cachedFullLibrary; + } else { + if (cachedQuickLibrary == null) { + cachedQuickLibrary = new JetStandardLibrary(project, false); + } + return cachedQuickLibrary; } - return cachedLibrary; // JetStandardLibrary standardLibrary = standardLibraryCache.get(project); // if (standardLibrary == null) { // standardLibrary = new JetStandardLibrary(project); @@ -47,6 +55,12 @@ public class JetStandardLibrary { // return standardLibrary; } + public static JetStandardLibrary getJetStandardLibrary(@NotNull Project project) { + return getJetStandardLibrary(project, true); + } + + private final boolean loadFullLibrary; + private JetScope libraryScope; private ClassDescriptor numberClass; @@ -122,20 +136,27 @@ public class JetStandardLibrary { private NamespaceDescriptor typeInfoNamespace; private Set typeInfoFunction; - private JetStandardLibrary(@NotNull Project project) { - // TODO : review - InputStream stream = JetStandardClasses.class.getClassLoader().getResourceAsStream("jet/Library.jet"); + private JetStandardLibrary(@NotNull Project project, boolean loadFullLibrary) { + this.loadFullLibrary = loadFullLibrary; + try { - //noinspection IOResourceOpenedButNotSafelyClosed - JetFile file = (JetFile) PsiFileFactory.getInstance(project).createFileFromText("Library.jet", - JetFileType.INSTANCE, FileUtil.loadTextAndClose(new InputStreamReader(stream))); + JetFile file = null; + if (loadFullLibrary) { + // TODO : review + InputStream stream = JetStandardClasses.class.getClassLoader().getResourceAsStream("jet/Library.jet"); + //noinspection IOResourceOpenedButNotSafelyClosed + file = (JetFile) PsiFileFactory.getInstance(project).createFileFromText("Library.jet", + JetFileType.INSTANCE, FileUtil.loadTextAndClose(new InputStreamReader(stream))); + } JetSemanticServices bootstrappingSemanticServices = JetSemanticServices.createSemanticServices(this); BindingTraceContext bindingTraceContext = new BindingTraceContext(); WritableScopeImpl writableScope = new WritableScopeImpl(JetStandardClasses.STANDARD_CLASSES, JetStandardClasses.STANDARD_CLASSES_NAMESPACE, RedeclarationHandler.THROW_EXCEPTION).setDebugName("Root bootstrap scope"); // this.libraryScope = bootstrappingTDA.process(JetStandardClasses.STANDARD_CLASSES, file.getRootNamespace().getDeclarations()); // bootstrappingTDA.process(writableScope, JetStandardClasses.STANDARD_CLASSES_NAMESPACE, file.getRootNamespace().getDeclarations()); - TopDownAnalyzer.processStandardLibraryNamespace(bootstrappingSemanticServices, bindingTraceContext, writableScope, JetStandardClasses.STANDARD_CLASSES_NAMESPACE, file.getRootNamespace()); + if (loadFullLibrary) { + TopDownAnalyzer.processStandardLibraryNamespace(bootstrappingSemanticServices, bindingTraceContext, writableScope, JetStandardClasses.STANDARD_CLASSES_NAMESPACE, file.getRootNamespace()); + } // this.libraryScope = JetStandardClasses.STANDARD_CLASSES_NAMESPACE.getMemberScope(); AnalyzingUtils.throwExceptionOnErrors(bindingTraceContext.getBindingContext()); @@ -153,6 +174,11 @@ public class JetStandardLibrary { private void initStdClasses() { if(libraryScope == null) { this.libraryScope = JetStandardClasses.STANDARD_CLASSES_NAMESPACE.getMemberScope(); + + if (!loadFullLibrary) { + return; + } + this.numberClass = (ClassDescriptor) libraryScope.getClassifier("Number"); this.byteClass = (ClassDescriptor) libraryScope.getClassifier("Byte"); this.charClass = (ClassDescriptor) libraryScope.getClassifier("Char"); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java index 0446105d479..10c3ca8cae5 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java @@ -1,6 +1,7 @@ package org.jetbrains.jet.lang.types.expressions; import com.google.common.collect.Lists; +import com.google.common.collect.Multimap; import com.intellij.lang.ASTNode; import com.intellij.psi.PsiElement; import com.intellij.psi.tree.IElementType; @@ -8,6 +9,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.JetNodeTypes; import org.jetbrains.jet.lang.descriptors.*; +import org.jetbrains.jet.lang.diagnostics.Errors; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.*; import org.jetbrains.jet.lang.resolve.calls.CallMaker; @@ -245,10 +247,58 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { else { if (typeChecker.isSubtypeOf(actualType, targetType)) { context.trace.report(USELESS_CAST.on(expression, expression.getOperationSign())); + } else { + if (isCastErased(actualType, targetType)) { + context.trace.report(Errors.UNCHECKED_CAST.on(expression, actualType, targetType)); + } } } } + /** + * Check if assignment from ActualType to TargetType is erased. + * It is an error in "is" statement and warning in "as". + */ + public static boolean isCastErased(JetType actualType, JetType targetType) { + + JetType targetTypeClerared = TypeUtils.makeUnsubstitutedType( + (ClassDescriptor) targetType.getConstructor().getDeclarationDescriptor(), null); + + Multimap clearTypeSubstitutionMap = + TypeUtils.buildDeepSubstitutionMultimap(targetTypeClerared); + + Set clearSubstituted = new HashSet(); + + for (int i = 0; i < actualType.getConstructor().getParameters().size(); ++i) { + TypeParameterDescriptor subjectTypeParameterDescriptor = actualType.getConstructor().getParameters().get(i); + + Collection subst = clearTypeSubstitutionMap.get(subjectTypeParameterDescriptor.getTypeConstructor()); + for (TypeProjection proj : subst) { + clearSubstituted.add(proj.getType()); + } + } + + for (int i = 0; i < targetType.getConstructor().getParameters().size(); ++i) { + TypeParameterDescriptor typeParameter = targetType.getConstructor().getParameters().get(i); + TypeProjection typeProjection = targetType.getArguments().get(i); + + if (typeParameter.isReified()) { + continue; + } + + // "is List<*>" + if (typeProjection.equals(TypeUtils.makeStarProjection(typeParameter))) { + continue; + } + + // if parameter is mapped to nothing then it is erased + if (!clearSubstituted.contains(typeParameter.getDefaultType())) { + return true; + } + } + return false; + } + @Override public JetType visitTupleExpression(JetTupleExpression expression, ExpressionTypingContext context) { List entries = expression.getEntries(); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/PatternMatchingTypingVisitor.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/PatternMatchingTypingVisitor.java index 6b8b8d0630c..86bc4e82677 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/PatternMatchingTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/PatternMatchingTypingVisitor.java @@ -1,11 +1,14 @@ package org.jetbrains.jet.lang.types.expressions; +import com.google.common.collect.Multimap; import com.google.common.collect.Sets; import com.intellij.lang.ASTNode; import com.intellij.openapi.util.Ref; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor; import org.jetbrains.jet.lang.descriptors.VariableDescriptor; +import org.jetbrains.jet.lang.diagnostics.Errors; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo; import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowValue; @@ -17,8 +20,7 @@ import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; import org.jetbrains.jet.lang.resolve.scopes.receivers.TransientReceiver; import org.jetbrains.jet.lang.types.*; -import java.util.List; -import java.util.Set; +import java.util.*; import static org.jetbrains.jet.lang.diagnostics.Errors.*; import static org.jetbrains.jet.lang.types.expressions.ExpressionTypingUtils.ensureBooleanResultWithCustomSubject; @@ -245,6 +247,9 @@ public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor { } } + /* + * (a: SubjectType) is Type + */ private void checkTypeCompatibility(@Nullable JetType type, @NotNull JetType subjectType, @NotNull JetElement reportErrorOn) { // TODO : Take auto casts into account? if (type == null) { @@ -253,6 +258,29 @@ public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor { if (TypeUtils.intersect(context.semanticServices.getTypeChecker(), Sets.newHashSet(type, subjectType)) == null) { // context.trace.getErrorHandler().genericError(reportErrorOn.getNode(), "Incompatible types: " + type + " and " + subjectType); context.trace.report(INCOMPATIBLE_TYPES.on(reportErrorOn, type, subjectType)); + return; + } + + { + // check parameters compatible + Multimap typeSubstritutionMap = TypeUtils.buildDeepSubstitutionMultimap(type); + + for (int i = 0; i < subjectType.getConstructor().getParameters().size(); ++i) { + TypeParameterDescriptor subjectTypeParameterDescriptor = subjectType.getConstructor().getParameters().get(i); + TypeProjection subjectParameterType = subjectType.getArguments().get(i); + + Collection xxy = typeSubstritutionMap.get(subjectTypeParameterDescriptor.getTypeConstructor()); + for (TypeProjection proj : xxy) { + if (!context.semanticServices.getTypeChecker().isSubtypeOf(subjectParameterType.getType(), proj.getType())) { + context.trace.report(INCOMPATIBLE_TYPES.on(reportErrorOn, type, subjectType)); + continue; + } + } + } + } + + if (BasicExpressionTypingVisitor.isCastErased(subjectType, type)) { + context.trace.report(Errors.CANNOT_CHECK_FOR_ERASED.on(reportErrorOn, type)); } } diff --git a/compiler/frontend/src/org/jetbrains/jet/resolve/DescriptorRenderer.java b/compiler/frontend/src/org/jetbrains/jet/resolve/DescriptorRenderer.java index b744988a594..8b2ccbd024a 100644 --- a/compiler/frontend/src/org/jetbrains/jet/resolve/DescriptorRenderer.java +++ b/compiler/frontend/src/org/jetbrains/jet/resolve/DescriptorRenderer.java @@ -73,7 +73,11 @@ public class DescriptorRenderer implements Renderer { } public String renderType(JetType type) { - return escape(type.toString()); + if (type == null) { + return escape(""); + } else { + return escape(type.toString()); + } } protected String escape(String s) { @@ -222,7 +226,7 @@ public class DescriptorRenderer implements Renderer { renderName(descriptor, builder); renderValueParameters(descriptor, builder); - builder.append(" : ").append(escape(renderType(descriptor.getReturnType()))); + builder.append(" : ").append(escape(renderType(descriptor.getReturnTypeSafe()))); return super.visitFunctionDescriptor(descriptor, builder); } diff --git a/compiler/testData/checkerWithErrorTypes/full/Casts.jet b/compiler/testData/checkerWithErrorTypes/full/Casts.jet index 163619fd4d0..e34a90b945a 100644 --- a/compiler/testData/checkerWithErrorTypes/full/Casts.jet +++ b/compiler/testData/checkerWithErrorTypes/full/Casts.jet @@ -1,3 +1,5 @@ +// -JDK + fun test() : Unit { var x : Int? = 0 var y : Int = 0 @@ -13,4 +15,4 @@ fun test() : Unit { x as? Int? : Int? y as? Int? : Int? () -} \ No newline at end of file +} diff --git a/compiler/testData/checkerWithErrorTypes/full/RecursiveTypeInference.jet b/compiler/testData/checkerWithErrorTypes/full/RecursiveTypeInference.jet index 11eb880a193..0a6a5b1e2e7 100644 --- a/compiler/testData/checkerWithErrorTypes/full/RecursiveTypeInference.jet +++ b/compiler/testData/checkerWithErrorTypes/full/RecursiveTypeInference.jet @@ -5,15 +5,15 @@ namespace a { } namespace b { - fun foo() = bar() + fun foo() = bar() - fun bar() = foo() + fun bar() = foo() } namespace c { - fun bazz() = bar() + fun bazz() = bar() - fun foo() = bazz() + fun foo() = bazz() fun bar() = foo() } @@ -39,4 +39,4 @@ namespace ok { fun bar() = foo() } -} \ No newline at end of file +} diff --git a/compiler/testData/checkerWithErrorTypes/full/cast/AsErasedError.jet b/compiler/testData/checkerWithErrorTypes/full/cast/AsErasedError.jet new file mode 100644 index 00000000000..bff067d20ee --- /dev/null +++ b/compiler/testData/checkerWithErrorTypes/full/cast/AsErasedError.jet @@ -0,0 +1,4 @@ +import java.util.List; +import java.util.Collection; + +fun ff(c: Collection) = c as List diff --git a/compiler/testData/checkerWithErrorTypes/full/cast/AsErasedFine.jet b/compiler/testData/checkerWithErrorTypes/full/cast/AsErasedFine.jet new file mode 100644 index 00000000000..341f370d108 --- /dev/null +++ b/compiler/testData/checkerWithErrorTypes/full/cast/AsErasedFine.jet @@ -0,0 +1,4 @@ +import java.util.List; +import java.util.Collection; + +fun ff(c: Collection) = c as List diff --git a/compiler/testData/checkerWithErrorTypes/full/cast/AsErasedStar.jet b/compiler/testData/checkerWithErrorTypes/full/cast/AsErasedStar.jet new file mode 100644 index 00000000000..b9c2faf0d9a --- /dev/null +++ b/compiler/testData/checkerWithErrorTypes/full/cast/AsErasedStar.jet @@ -0,0 +1,4 @@ +import java.util.List; + +fun ff(l: Any) = l as List<*> + diff --git a/compiler/testData/checkerWithErrorTypes/full/cast/AsErasedWarning.jet b/compiler/testData/checkerWithErrorTypes/full/cast/AsErasedWarning.jet new file mode 100644 index 00000000000..a55f6b7d58b --- /dev/null +++ b/compiler/testData/checkerWithErrorTypes/full/cast/AsErasedWarning.jet @@ -0,0 +1,3 @@ +import java.util.List; + +fun ff(a: Any) = a as List diff --git a/compiler/testData/checkerWithErrorTypes/full/cast/IsErasedAllow.jet b/compiler/testData/checkerWithErrorTypes/full/cast/IsErasedAllow.jet new file mode 100644 index 00000000000..7f32b79eba2 --- /dev/null +++ b/compiler/testData/checkerWithErrorTypes/full/cast/IsErasedAllow.jet @@ -0,0 +1,5 @@ +import java.util.Collection; +import java.util.List; + +fun ff(l: Collection) = l is List + diff --git a/compiler/testData/checkerWithErrorTypes/full/cast/IsErasedAllowParameterSubtype.jet b/compiler/testData/checkerWithErrorTypes/full/cast/IsErasedAllowParameterSubtype.jet new file mode 100644 index 00000000000..d1694229dc6 --- /dev/null +++ b/compiler/testData/checkerWithErrorTypes/full/cast/IsErasedAllowParameterSubtype.jet @@ -0,0 +1,9 @@ +import java.util.Collection; +import java.util.List; + +open class A + +class B : A + +fun ff(l: Collection) = l is List + diff --git a/compiler/testData/checkerWithErrorTypes/full/cast/IsErasedDisallowFromAny.jet b/compiler/testData/checkerWithErrorTypes/full/cast/IsErasedDisallowFromAny.jet new file mode 100644 index 00000000000..eb3b402ccc7 --- /dev/null +++ b/compiler/testData/checkerWithErrorTypes/full/cast/IsErasedDisallowFromAny.jet @@ -0,0 +1,3 @@ +import java.util.List; + +fun ff(l: Any) = l is List diff --git a/compiler/testData/checkerWithErrorTypes/full/cast/IsErasedDisallowFromParameter.jet b/compiler/testData/checkerWithErrorTypes/full/cast/IsErasedDisallowFromParameter.jet new file mode 100644 index 00000000000..a70b5932999 --- /dev/null +++ b/compiler/testData/checkerWithErrorTypes/full/cast/IsErasedDisallowFromParameter.jet @@ -0,0 +1,5 @@ +import java.util.List; +import java.util.Collection; + +fun ff(l: Collection) = l is List + diff --git a/compiler/testData/checkerWithErrorTypes/full/cast/IsErasedStar.jet b/compiler/testData/checkerWithErrorTypes/full/cast/IsErasedStar.jet new file mode 100644 index 00000000000..404d8f8f3b0 --- /dev/null +++ b/compiler/testData/checkerWithErrorTypes/full/cast/IsErasedStar.jet @@ -0,0 +1,3 @@ +import java.util.List; + +fun ff(l: Any) = l is List<*> diff --git a/compiler/testData/checkerWithErrorTypes/full/cast/IsReified.jet b/compiler/testData/checkerWithErrorTypes/full/cast/IsReified.jet new file mode 100644 index 00000000000..247196d6e84 --- /dev/null +++ b/compiler/testData/checkerWithErrorTypes/full/cast/IsReified.jet @@ -0,0 +1,3 @@ +class MyList + +fun ff(a: Any) = a is MyList diff --git a/compiler/testData/checkerWithErrorTypes/full/cast/IsReifiedDisallow.jet b/compiler/testData/checkerWithErrorTypes/full/cast/IsReifiedDisallow.jet new file mode 100644 index 00000000000..9abceb5f1e6 --- /dev/null +++ b/compiler/testData/checkerWithErrorTypes/full/cast/IsReifiedDisallow.jet @@ -0,0 +1,3 @@ +class MyList + +fun ff(l: MyList) = l is MyList diff --git a/compiler/testData/checkerWithErrorTypes/full/cast/IsTraits.jet b/compiler/testData/checkerWithErrorTypes/full/cast/IsTraits.jet new file mode 100644 index 00000000000..99656c2ab24 --- /dev/null +++ b/compiler/testData/checkerWithErrorTypes/full/cast/IsTraits.jet @@ -0,0 +1,4 @@ +trait Aaa +trait Bbb + +fun f(a: Aaa) = a is Bbb diff --git a/compiler/testData/checkerWithErrorTypes/full/cast/WhenErasedDisallowFromAny.jet b/compiler/testData/checkerWithErrorTypes/full/cast/WhenErasedDisallowFromAny.jet new file mode 100644 index 00000000000..f38a4b14fbe --- /dev/null +++ b/compiler/testData/checkerWithErrorTypes/full/cast/WhenErasedDisallowFromAny.jet @@ -0,0 +1,6 @@ +import java.util.List; + +fun ff(l: Any) = when(l) { + is List => 1 + else 2 +} diff --git a/compiler/testData/checkerWithErrorTypes/quick/regressions/kt328.jet b/compiler/testData/checkerWithErrorTypes/quick/regressions/kt328.jet new file mode 100644 index 00000000000..2593c440b51 --- /dev/null +++ b/compiler/testData/checkerWithErrorTypes/quick/regressions/kt328.jet @@ -0,0 +1,3 @@ +fun bar() = { + bar() +} diff --git a/compiler/testData/checkerWithErrorTypes/quick/regressions/kt328Complex.jet b/compiler/testData/checkerWithErrorTypes/quick/regressions/kt328Complex.jet new file mode 100644 index 00000000000..9caa6193206 --- /dev/null +++ b/compiler/testData/checkerWithErrorTypes/quick/regressions/kt328Complex.jet @@ -0,0 +1,3 @@ +fun bar() = { + fun foo() = bar() +} diff --git a/compiler/testData/checkerWithErrorTypes/quick/regressions/kt328DuplicatedByKt329.jet b/compiler/testData/checkerWithErrorTypes/quick/regressions/kt328DuplicatedByKt329.jet new file mode 100644 index 00000000000..35a66da2884 --- /dev/null +++ b/compiler/testData/checkerWithErrorTypes/quick/regressions/kt328DuplicatedByKt329.jet @@ -0,0 +1,7 @@ +// http://youtrack.jetbrains.net/issue/KT-329 + +fun block(f : fun() : Unit) = f() + +fun bar() = block{ foo() // <-- missing closing curly bracket +fun foo() = block{ bar() } + diff --git a/compiler/testData/codegen/patternMatching/is.jet b/compiler/testData/codegen/patternMatching/is.jet index a5b5f33195f..9fac50c586b 100644 --- a/compiler/testData/codegen/patternMatching/is.jet +++ b/compiler/testData/codegen/patternMatching/is.jet @@ -1,6 +1,6 @@ fun typeName(a: Any?) : String { return when(a) { - is java.util.ArrayList => "array list" + is java.util.ArrayList<*> => "array list" else => "no idea" } } @@ -8,4 +8,4 @@ fun typeName(a: Any?) : String { fun box() : String { if(typeName(java.util.ArrayList ()) != "array list") return "array list failed" return "OK" -} \ No newline at end of file +} diff --git a/compiler/tests/org/jetbrains/jet/checkers/CheckerTestUtilTest.java b/compiler/tests/org/jetbrains/jet/checkers/CheckerTestUtilTest.java index 06ffed74d04..8663cc4d9fc 100644 --- a/compiler/tests/org/jetbrains/jet/checkers/CheckerTestUtilTest.java +++ b/compiler/tests/org/jetbrains/jet/checkers/CheckerTestUtilTest.java @@ -81,7 +81,7 @@ public class CheckerTestUtilTest extends JetLiteFixture { } public void test(PsiFile psiFile) { - BindingContext bindingContext = AnalyzerFacade.analyzeFileWithCache(AnalyzingUtils.getInstance(ImportingStrategy.NONE), (JetFile) psiFile, AnalyzerFacade.SINGLE_DECLARATION_PROVIDER); + BindingContext bindingContext = AnalyzerFacade.analyzeFileWithCache(AnalyzingUtils.getInstance(ImportingStrategy.NONE, true), (JetFile) psiFile, AnalyzerFacade.SINGLE_DECLARATION_PROVIDER); String expectedText = CheckerTestUtil.addDiagnosticMarkersToText(psiFile, bindingContext).toString(); List diagnosedRanges = Lists.newArrayList(); diff --git a/compiler/tests/org/jetbrains/jet/checkers/FullJetPsiCheckerTest.java b/compiler/tests/org/jetbrains/jet/checkers/FullJetPsiCheckerTest.java index 986f6501d10..5b4646d207e 100644 --- a/compiler/tests/org/jetbrains/jet/checkers/FullJetPsiCheckerTest.java +++ b/compiler/tests/org/jetbrains/jet/checkers/FullJetPsiCheckerTest.java @@ -8,8 +8,11 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.JetLiteFixture; import org.jetbrains.jet.JetTestCaseBuilder; import org.jetbrains.jet.lang.diagnostics.DiagnosticUtils; +import org.jetbrains.jet.lang.resolve.AnalyzingUtils; import org.jetbrains.jet.lang.resolve.BindingContext; +import org.jetbrains.jet.lang.resolve.ImportingStrategy; import org.jetbrains.jet.lang.resolve.java.AnalyzerFacade; +import org.jetbrains.jet.lang.resolve.java.JavaDefaultImports; import java.util.List; @@ -42,7 +45,13 @@ public class FullJetPsiCheckerTest extends JetLiteFixture { String clearText = CheckerTestUtil.parseDiagnosedRanges(expectedText, diagnosedRanges); myFile = createPsiFile(myName, clearText); - BindingContext bindingContext = AnalyzerFacade.analyzeFileWithCache(myFile, AnalyzerFacade.SINGLE_DECLARATION_PROVIDER); + + boolean loadStdlib = !expectedText.contains("-STDLIB"); + boolean importJdk = !expectedText.contains("-JDK"); + + ImportingStrategy importingStrategy = importJdk ? JavaDefaultImports.JAVA_DEFAULT_IMPORTS : ImportingStrategy.NONE; + + BindingContext bindingContext = AnalyzerFacade.analyzeFileWithCache(AnalyzingUtils.getInstance(importingStrategy, loadStdlib), myFile, AnalyzerFacade.SINGLE_DECLARATION_PROVIDER); CheckerTestUtil.diagnosticsDiff(diagnosedRanges, bindingContext.getDiagnostics(), new CheckerTestUtil.DiagnosticDiffCallbacks() { @Override diff --git a/compiler/tests/org/jetbrains/jet/checkers/QuickJetPsiCheckerTest.java b/compiler/tests/org/jetbrains/jet/checkers/QuickJetPsiCheckerTest.java index d6ead64cdf1..a69f04a21c7 100644 --- a/compiler/tests/org/jetbrains/jet/checkers/QuickJetPsiCheckerTest.java +++ b/compiler/tests/org/jetbrains/jet/checkers/QuickJetPsiCheckerTest.java @@ -13,6 +13,7 @@ import org.jetbrains.jet.lang.resolve.AnalyzingUtils; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.ImportingStrategy; import org.jetbrains.jet.lang.resolve.java.AnalyzerFacade; +import org.jetbrains.jet.lang.resolve.java.JavaDefaultImports; import java.util.List; @@ -40,7 +41,12 @@ public class QuickJetPsiCheckerTest extends JetLiteFixture { createAndCheckPsiFile(name, clearText); JetFile jetFile = (JetFile) myFile; - BindingContext bindingContext = AnalyzerFacade.analyzeFileWithCache(AnalyzingUtils.getInstance(ImportingStrategy.NONE), jetFile, AnalyzerFacade.SINGLE_DECLARATION_PROVIDER); + boolean loadStdlib = !expectedText.contains("-STDLIB"); + boolean importJdk = expectedText.contains("+JDK"); + + ImportingStrategy importingStrategy = importJdk ? JavaDefaultImports.JAVA_DEFAULT_IMPORTS : ImportingStrategy.NONE; + + BindingContext bindingContext = AnalyzerFacade.analyzeFileWithCache(AnalyzingUtils.getInstance(importingStrategy, loadStdlib), jetFile, AnalyzerFacade.SINGLE_DECLARATION_PROVIDER); CheckerTestUtil.diagnosticsDiff(diagnosedRanges, bindingContext.getDiagnostics(), new CheckerTestUtil.DiagnosticDiffCallbacks() { @Override diff --git a/compiler/tests/org/jetbrains/jet/resolve/JetResolveTest.java b/compiler/tests/org/jetbrains/jet/resolve/JetResolveTest.java index ca206ae88c0..f4bf68958a1 100644 --- a/compiler/tests/org/jetbrains/jet/resolve/JetResolveTest.java +++ b/compiler/tests/org/jetbrains/jet/resolve/JetResolveTest.java @@ -44,7 +44,7 @@ public class JetResolveTest extends ExtensibleResolveTestCase { @Override protected ExpectedResolveData getExpectedResolveData() { Project project = getProject(); - JetStandardLibrary lib = JetStandardLibrary.getJetStandardLibrary(project); + JetStandardLibrary lib = JetStandardLibrary.getJetStandardLibrary(project, true); Map nameToDescriptor = new HashMap(); nameToDescriptor.put("std::Int.plus(Int)", standardFunction(lib.getInt(), "plus", lib.getIntType())); FunctionDescriptor descriptorForGet = standardFunction(lib.getArray(), Collections.singletonList(new TypeProjection(lib.getIntType())), "get", lib.getIntType()); diff --git a/idea/src/org/jetbrains/jet/plugin/compiler/JetCompiler.java b/idea/src/org/jetbrains/jet/plugin/compiler/JetCompiler.java index 0a16cb56f58..0a34294d80f 100644 --- a/idea/src/org/jetbrains/jet/plugin/compiler/JetCompiler.java +++ b/idea/src/org/jetbrains/jet/plugin/compiler/JetCompiler.java @@ -80,7 +80,7 @@ public class JetCompiler implements TranslatingCompiler { } } - BindingContext bindingContext = AnalyzingUtils.getInstance(JavaDefaultImports.JAVA_DEFAULT_IMPORTS).analyzeNamespaces( + BindingContext bindingContext = AnalyzingUtils.getInstance(JavaDefaultImports.JAVA_DEFAULT_IMPORTS, true).analyzeNamespaces( compileContext.getProject(), namespaces, Predicates.alwaysTrue(), JetControlFlowDataTraceFactory.EMPTY); diff --git a/idea/src/org/jetbrains/jet/plugin/java/JavaElementFinder.java b/idea/src/org/jetbrains/jet/plugin/java/JavaElementFinder.java index 7cfa0fe1b86..1967f70b22e 100644 --- a/idea/src/org/jetbrains/jet/plugin/java/JavaElementFinder.java +++ b/idea/src/org/jetbrains/jet/plugin/java/JavaElementFinder.java @@ -211,7 +211,7 @@ public class JavaElementFinder extends PsiElementFinder { if (dirty.size() > 0) { - final BindingContext context = AnalyzingUtils.getInstance(JavaDefaultImports.JAVA_DEFAULT_IMPORTS).shallowAnalyzeFiles(dirty); + final BindingContext context = AnalyzingUtils.getInstance(JavaDefaultImports.JAVA_DEFAULT_IMPORTS, true).shallowAnalyzeFiles(dirty); state.compileCorrectNamespaces(context, AnalyzingUtils.collectRootNamespaces(dirty)); state.getFactory().files(); } diff --git a/idea/testData/checker/RecursiveTypeInference.jet b/idea/testData/checker/RecursiveTypeInference.jet index a73cf01cc0e..c8e0006f350 100644 --- a/idea/testData/checker/RecursiveTypeInference.jet +++ b/idea/testData/checker/RecursiveTypeInference.jet @@ -1,19 +1,19 @@ namespace a { - val foo = bar() + val foo = bar() fun bar() = foo } namespace b { - fun foo() = bar() + fun foo() = bar() - fun bar() = foo() + fun bar() = foo() } namespace c { - fun bazz() = bar() + fun bazz() = bar() - fun foo() = bazz() + fun foo() = bazz() fun bar() = foo() } @@ -39,4 +39,4 @@ namespace ok { fun bar() = foo() } -} \ No newline at end of file +}