From 9059dae6731b639e0798d7ab7ea5f3f92288ea87 Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Mon, 25 Apr 2011 19:54:48 +0400 Subject: [PATCH] Namespace types are only allowed in appropriate contexts --- .../jet/lang/resolve/JetModuleUtil.java | 5 +- .../jet/lang/resolve/TopDownAnalyzer.java | 2 +- .../jet/lang/resolve/TypeResolver.java | 6 +- .../jetbrains/jet/lang/types/ErrorUtils.java | 3 +- .../jet/lang/types/JetTypeInferrer.java | 77 ++++++++++++++++--- .../checker/NamespaceAsExpression.jet | 8 ++ 6 files changed, 82 insertions(+), 19 deletions(-) create mode 100644 idea/testData/checker/NamespaceAsExpression.jet diff --git a/idea/src/org/jetbrains/jet/lang/resolve/JetModuleUtil.java b/idea/src/org/jetbrains/jet/lang/resolve/JetModuleUtil.java index a3ae81d39f2..83b7b08e240 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/JetModuleUtil.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/JetModuleUtil.java @@ -1,13 +1,14 @@ package org.jetbrains.jet.lang.resolve; import org.jetbrains.jet.lang.psi.JetElement; +import org.jetbrains.jet.lang.types.NamespaceType; /** * @author abreslav */ public class JetModuleUtil { - public static JetScope getRootNamespaceScope(JetElement expression) { + public static NamespaceType getRootNamespaceType(JetElement expression) { // TODO: this is a stub: at least the modules' root namespaces must be indexed here - return JetScope.EMPTY; + return new NamespaceType("", JetScope.EMPTY); } } diff --git a/idea/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java b/idea/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java index bff4df6c9f4..e84be350184 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java @@ -114,7 +114,7 @@ public class TopDownAnalyzer { if (importDirective.isAllUnder()) { JetExpression importedReference = importDirective.getImportedReference(); if (importedReference != null) { - JetType type = semanticServices.getTypeInferrer(trace, JetFlowInformationProvider.THROW_EXCEPTION).getType(namespaceScope, importedReference, false); + JetType type = semanticServices.getTypeInferrer(trace, JetFlowInformationProvider.THROW_EXCEPTION).getTypeWithNamespaces(namespaceScope, importedReference, false); if (type != null) { namespaceScope.importScope(type.getMemberScope()); } diff --git a/idea/src/org/jetbrains/jet/lang/resolve/TypeResolver.java b/idea/src/org/jetbrains/jet/lang/resolve/TypeResolver.java index 972b4e1f997..0b3cbd64e85 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/TypeResolver.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/TypeResolver.java @@ -202,9 +202,9 @@ public class TypeResolver { if (referencedName == null) { return null; } - ClassifierDescriptor classifierDescriptor = null; + ClassifierDescriptor classifierDescriptor; if (userType.isAbsoluteInRootNamespace()) { - classifierDescriptor = JetModuleUtil.getRootNamespaceScope(userType).getClassifier(referencedName); + classifierDescriptor = JetModuleUtil.getRootNamespaceType(userType).getMemberScope().getClassifier(referencedName); } else { JetUserType qualifier = userType.getQualifier(); @@ -238,7 +238,7 @@ public class TypeResolver { @Nullable private NamespaceDescriptor resolveNamespace(JetScope scope, JetUserType userType) { if (userType.isAbsoluteInRootNamespace()) { - return resolveNamespace(JetModuleUtil.getRootNamespaceScope(userType), userType); + return resolveNamespace(JetModuleUtil.getRootNamespaceType(userType).getMemberScope(), userType); } JetUserType qualifier = userType.getQualifier(); diff --git a/idea/src/org/jetbrains/jet/lang/types/ErrorUtils.java b/idea/src/org/jetbrains/jet/lang/types/ErrorUtils.java index e260e39a396..adf146176eb 100644 --- a/idea/src/org/jetbrains/jet/lang/types/ErrorUtils.java +++ b/idea/src/org/jetbrains/jet/lang/types/ErrorUtils.java @@ -150,7 +150,8 @@ public class ErrorUtils { } public static boolean isErrorType(JetType type) { - return type instanceof ErrorTypeImpl || isError(type.getConstructor()); + return type instanceof ErrorTypeImpl || + isError(type.getConstructor()); } private static class ErrorTypeImpl implements JetType { diff --git a/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java b/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java index 61aa8937be6..ddd86bd2aa9 100644 --- a/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java +++ b/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java @@ -92,6 +92,10 @@ public class JetTypeInferrer { return new TypeInferrerVisitor(scope, preferBlock).getType(expression); } + public JetType getTypeWithNamespaces(@NotNull final JetScope scope, @NotNull JetExpression expression, final boolean preferBlock) { + return new TypeInferrerVisitorWithNamespaces(scope, preferBlock).getType(expression); + } + @Nullable private List getTypes(JetScope scope, List indexExpressions) { List argumentTypes = new ArrayList(); @@ -557,7 +561,7 @@ public class JetTypeInferrer { //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// private class TypeInferrerVisitor extends JetVisitor { - private final JetScope scope; + protected final JetScope scope; private final boolean preferBlock; protected JetType result; @@ -574,13 +578,18 @@ public class JetTypeInferrer { visitor = this; } else { - visitor = new TypeInferrerVisitor(scope, preferBlock); + visitor = createNew(scope, preferBlock); } JetType type = visitor.getType(expression); visitor.result = null; return type; } + @NotNull + public TypeInferrerVisitor createNew(JetScope scope, boolean preferBlock) { + return new TypeInferrerVisitor(scope, preferBlock); + } + @Nullable public JetType getType(@NotNull JetExpression expression) { assert result == null; @@ -640,19 +649,33 @@ public class JetTypeInferrer { semanticServices.getErrorHandler().genericError(expression.getNode(), "This variable is not readable in this context"); } return; - } else { - NamespaceDescriptor namespace = scope.getNamespace(referencedName); - if (namespace != null) { - trace.recordReferenceResolution(expression, namespace); - result = namespace.getNamespaceType(); - return; - } + } else if (furtherNameLookup(expression, referencedName)) { + return; } semanticServices.getErrorHandler().unresolvedReference(expression); } } } + protected boolean furtherNameLookup(@NotNull JetSimpleNameExpression expression, @NotNull String referencedName) { + NamespaceType namespaceType = lookupNamespaceType(expression, referencedName); + if (namespaceType != null) { + semanticServices.getErrorHandler().genericError(expression.getNode(), "Expression expected, but a namespace name found"); + return true; + } + return false; + } + + @Nullable + protected NamespaceType lookupNamespaceType(@NotNull JetSimpleNameExpression expression, @NotNull String referencedName) { + NamespaceDescriptor namespace = scope.getNamespace(referencedName); + if (namespace == null) { + return null; + } + trace.recordReferenceResolution(expression, namespace); + return namespace.getNamespaceType(); + } + @Override public void visitFunctionLiteralExpression(JetFunctionLiteralExpression expression) { if (preferBlock && !expression.hasParameterSpecification()) { @@ -1164,7 +1187,7 @@ public class JetTypeInferrer { // TODO : functions JetExpression selectorExpression = expression.getSelectorExpression(); JetExpression receiverExpression = expression.getReceiverExpression(); - JetType receiverType = getType(scope, receiverExpression, false); + JetType receiverType = new TypeInferrerVisitorWithNamespaces(scope, false).getType(receiverExpression); if (receiverType != null) { checkNullSafety(receiverType, expression); JetType selectorReturnType = getSelectorReturnType(receiverType, selectorExpression); @@ -1467,9 +1490,39 @@ public class JetTypeInferrer { } @Override - public void visitJetElement(JetElement elem) { - semanticServices.getErrorHandler().genericError(elem.getNode(), "Unsupported element: " + elem + " " + elem.getClass().getCanonicalName()); + public void visitRootNamespaceExpression(JetRootNamespaceExpression expression) { + semanticServices.getErrorHandler().genericError(expression.getNode(), "'namespace' is not an expression"); + result = null; } + + @Override + public void visitJetElement(JetElement elem) { + semanticServices.getErrorHandler().genericError(elem.getNode(), "[JetTypeInferrer] Unsupported element: " + elem + " " + elem.getClass().getCanonicalName()); + } + } + + private class TypeInferrerVisitorWithNamespaces extends TypeInferrerVisitor { + private TypeInferrerVisitorWithNamespaces(@NotNull JetScope scope, boolean preferBlock) { + super(scope, preferBlock); + } + + @NotNull + @Override + public TypeInferrerVisitor createNew(JetScope scope, boolean preferBlock) { + return new TypeInferrerVisitorWithNamespaces(scope, preferBlock); + } + + @Override + public void visitRootNamespaceExpression(JetRootNamespaceExpression expression) { + result = JetModuleUtil.getRootNamespaceType(expression); + } + + @Override + protected boolean furtherNameLookup(@NotNull JetSimpleNameExpression expression, @NotNull String referencedName) { + result = lookupNamespaceType(expression, referencedName); + return result != null; + } + } private class TypeInferrerVisitorWithWritableScope extends TypeInferrerVisitor { diff --git a/idea/testData/checker/NamespaceAsExpression.jet b/idea/testData/checker/NamespaceAsExpression.jet new file mode 100644 index 00000000000..73d53d57808 --- /dev/null +++ b/idea/testData/checker/NamespaceAsExpression.jet @@ -0,0 +1,8 @@ +namespace root + +namespace a { + +} + +val x = a +val y2 = namespace