eclipse-archived / ceylon

The Ceylon compiler, language module, and command line tools
http://ceylon-lang.org
Apache License 2.0
399 stars 62 forks source link

problem implementing higher-order generics #7000

Open gavinking opened 7 years ago

gavinking commented 7 years ago

I'm trying to add support to the JVM backend for the following code:

import ceylon.language.meta.model {
    Attribute
}

shared interface Model<Parent,Result> given Result<T> {
    shared formal Result<Type> get<Type>(Attribute<Parent,Type> attribute);
}

shared interface Expression<T> satisfies Model<T,Expression> {
    shared actual Expression<Type> get<Type>(Attribute<T,Type> attribute)
            => object satisfies Expression<Type> {};
}

Here's what I currently have:

diff --git a/compiler-java/src/com/redhat/ceylon/compiler/java/codegen/AbstractTransformer.java b/compiler-java/src/com/redhat/ceylon/compiler/java/codegen/AbstractTransformer.java
index b08e447526..40a3bb2189 100755
--- a/compiler-java/src/com/redhat/ceylon/compiler/java/codegen/AbstractTransformer.java
+++ b/compiler-java/src/com/redhat/ceylon/compiler/java/codegen/AbstractTransformer.java
@@ -1571,9 +1571,14 @@ public abstract class AbstractTransformer implements Transformation {
     }

     private boolean isTurnedToRawResolved(Type type) {
+        if (type.isTypeConstructor())
+            return true;
         // if we don't have type arguments we can't be raw
         if(type.getTypeArguments().isEmpty())
             return false;
+        
+        if (type.isTypeParameter())
+            return true;

         // we only go raw if any type param is an erased union/intersection
         // start with type but consider ever qualifying type
@@ -1585,6 +1590,8 @@ public abstract class AbstractTransformer implements Transformation {
             Map<TypeParameter, Type> typeArguments = singleType.getTypeArguments();
             for(TypeParameter tp : declaration.getTypeParameters()){
                 Type ta = typeArguments.get(tp);
+                if (ta.isTypeConstructor())
+                    return true;
                 // skip invalid input
                 if(tp == null || ta == null)
                     return false;
@@ -1927,6 +1934,11 @@ public abstract class AbstractTransformer implements Transformation {
         if(type == null || type.isUnknown())
             return make().Erroneous();

+        if (type.isTypeConstructor() || 
+                type.isTypeParameter() && !type.getTypeArgumentList().isEmpty()) {
+            type = type.getDeclaration().getUnit().getObjectType();
+        }
+        
         if (type.getDeclaration() instanceof Constructor) {
             type = type.getExtendedType();
         }
@@ -2480,6 +2492,11 @@ public abstract class AbstractTransformer implements Transformation {
             // and we need to treat "in Anything" specially below
             boolean isAnything = isAnything(ta);

+            if (ta.isTypeConstructor()) {
+                typeArgs = null;
+                break;
+            }
+            
             // Null will claim to be optional, but if we get its non-null type we will land with Nothing, which is not what
             // we want, so we make sure it's not Null
             if (isOptional(ta) && !isNull(ta)) {
diff --git a/compiler-java/src/com/redhat/ceylon/compiler/java/codegen/Strategy.java b/compiler-java/src/com/redhat/ceylon/compiler/java/codegen/Strategy.java
index e8ff5170cc..1121056cb3 100644
--- a/compiler-java/src/com/redhat/ceylon/compiler/java/codegen/Strategy.java
+++ b/compiler-java/src/com/redhat/ceylon/compiler/java/codegen/Strategy.java
@@ -555,6 +555,9 @@ class Strategy {
             }
         } else if (decl instanceof TypeAlias) {
             return ((TypeAlias)decl).getTypeParameters();
+        }
+        else if (decl instanceof TypeParameter) {
+            return Collections.emptyList();
         } else {
             throw BugException.unhandledDeclarationCase((Declaration)decl);
         }
diff --git a/typechecker/src/com/redhat/ceylon/compiler/typechecker/analyzer/ExpressionVisitor.java b/typechecker/src/com/redhat/ceylon/compiler/typechecker/analyzer/ExpressionVisitor.java
index 55da0271ad..7ddd06f70e 100644
--- a/typechecker/src/com/redhat/ceylon/compiler/typechecker/analyzer/ExpressionVisitor.java
+++ b/typechecker/src/com/redhat/ceylon/compiler/typechecker/analyzer/ExpressionVisitor.java
@@ -8138,10 +8138,10 @@ public class ExpressionVisitor extends Visitor {
             }
             if (pt.isTypeConstructor() 
                     && !that.getMetamodel()) {
-                checkNotJvm(that, 
-                        "type functions are not supported on the JVM: '" + 
-                        type.getName(unit) + 
-                        "' is generic (specify explicit type arguments)");
+//                checkNotJvm(that, 
+//                        "type functions are not supported on the JVM: '" + 
+//                        type.getName(unit) + 
+//                        "' is generic (specify explicit type arguments)");
             }
         }
     }
@@ -9982,8 +9982,8 @@ public class ExpressionVisitor extends Visitor {
         TypeParameterList typeParams = 
                 that.getTypeParameterList();
         if (typeParams!=null) {
-            checkNotJvm(typeParams, 
-                    "type functions are not supported on the JVM: type parameter is generic (remove type parameters)");
+//            checkNotJvm(typeParams, 
+//                    "type functions are not supported on the JVM: type parameter is generic (remove type parameters)");
         }
     }

I'm currently stuck on the fact that the compiler, instead of throwing any sort of error, simply ignores the Expression interface.

Over to you @FroMage ;-)

FroMage commented 7 years ago

So this stops generation of the second interface because it contains unknown types. This is done in DeclarationErrorVisitor#177. You can debug the generation in IssuesTests_7000_7499.testBug7000 on the 7000 branch.

gavinking commented 7 years ago

OK great thanks

gavinking commented 6 years ago

Relates to #2358.