55import java .util .Map .Entry ;
66import java .util .Optional ;
77import java .util .Set ;
8-
98import javax .annotation .processing .Messager ;
109import javax .tools .Diagnostic .Kind ;
1110
2726import com .github .javaparser .ast .type .Type ;
2827import com .github .javaparser .ast .visitor .VoidVisitorAdapter ;
2928
29+ import io .github .bldl .annotationProcessing .annotations .MyVariance ;
3030import io .github .bldl .astParsing .util .ClassData ;
3131import io .github .bldl .astParsing .util .ParamData ;
3232import io .github .bldl .graph .ClassHierarchyGraph ;
@@ -40,10 +40,12 @@ public class SubtypingCheckVisitor extends VoidVisitorAdapter<Void> {
4040 private final ClassData classData ;
4141 private final ClassHierarchyGraph <String > classHierarchy ;
4242
43- public SubtypingCheckVisitor (Map <String , Map <Integer , Type >> methodParams , Messager messager ,
43+ public SubtypingCheckVisitor (Map <String , Map <Integer , Type >> methodParams , Map <String , Type > methodTypes ,
44+ Messager messager ,
4445 Set <Pair <String , ClassOrInterfaceType >> varsToWatch , ClassData classData ,
4546 ClassHierarchyGraph <String > classHierarchy ) {
4647 this .methodParams = methodParams ;
48+ this .methodTypes = methodTypes ;
4749 this .messager = messager ;
4850 this .classData = classData ;
4951 this .classHierarchy = classHierarchy ;
@@ -77,6 +79,16 @@ public void visit(AssignExpr assignExpr, Void arg) {
7779 super .visit (assignExpr , arg );
7880 ClassOrInterfaceType assignedType = resolveType (assignExpr .getValue ()),
7981 assigneeType = resolveType (assignExpr .getTarget ());
82+ if (assignedType == null || assigneeType == null ) {
83+ messager .printMessage (Kind .WARNING , "Cannot resolve type for expression: " + assignExpr .toString ());
84+ return ;
85+ }
86+ boolean valid = isValidSubtype (assigneeType , assignedType , null );
87+ if (!valid )
88+ messager .printMessage (Kind .ERROR ,
89+ String .format ("Invalid subtype for assignment expression call: %s\n %s is not a subtype of %s" ,
90+ assignExpr .toString (),
91+ assignedType .toString (), assigneeType .toString ()));
8092 }
8193
8294 public void visit (ForEachStmt n , Void arg ) {
@@ -92,12 +104,16 @@ public void visit(VariableDeclarator declaration, Void arg) {
92104 if (initializer .isEmpty ())
93105 return ;
94106 ClassOrInterfaceType assignedType = resolveType (initializer .get ());
107+ if (assignedType == null )
108+ return ;
95109 boolean valid = isValidSubtype ((ClassOrInterfaceType ) assigneeType ,
96110 assignedType ,
97111 classData .params ());
98112 if (!valid )
99113 messager .printMessage (Kind .ERROR ,
100- String .format ("Invalid subtype for variable declaration: %s" , declaration .toString ()));
114+ String .format ("Invalid subtype for variable declaration: %s\n %s is not a subtype of %s" ,
115+ declaration .toString (),
116+ assignedType .toString (), assigneeType .toString ()));
101117 }
102118
103119 private ClassOrInterfaceType resolveType (Expression e ) {
@@ -147,14 +163,56 @@ private boolean isValidSubtype(ClassOrInterfaceType assigneeType, ClassOrInterfa
147163 String .format ("%s is not a user defined type, so no subtyping checks can be made" , assignedType ));
148164 return true ;
149165 }
150- return true ;
151- // switch (annotation.variance()) {
152- // case COVARIANT:
153- // return classHierarchy.isDescendant(assignedType, assigneeType);
154- // case CONTRAVARIANT:
155- // return classHierarchy.isDescendant(assigneeType, assignedType);
156- // default:
157- // return false;
158- // }
166+ if (!assigneeType .getTypeArguments ().isPresent () || !assignedType .getTypeArguments ().isPresent ())
167+ return true ;
168+
169+ var assigneeArgs = assigneeType .getTypeArguments ().get ();
170+ var assignedArgs = assignedType .getTypeArguments ().get ();
171+ boolean isSubtype = true ;
172+
173+ if (assignedArgs .size () == 0 )
174+ return true ; // cannot perform type inference
175+
176+ if (assigneeType .getNameAsString ().equals (classData .className ())) {
177+ Map <Integer , MyVariance > mp = new HashMap <>();
178+ for (var param : classData .params ().values ())
179+ mp .put (param .index (), param .variance ());
180+ for (int i = 0 ; i < assigneeArgs .size (); ++i ) {
181+ if (!(assignedArgs .get (i ) instanceof ClassOrInterfaceType )
182+ || !(assignedArgs .get (i ) instanceof ClassOrInterfaceType )) {
183+ continue ;
184+ }
185+ if (!mp .containsKey (i )) {
186+ isSubtype = isSubtype && isValidSubtype ((ClassOrInterfaceType ) assigneeArgs .get (i ),
187+ (ClassOrInterfaceType ) assignedArgs .get (i ),
188+ params );
189+ continue ;
190+ }
191+ switch (mp .get (i ).variance ()) {
192+ case COVARIANT :
193+ return classHierarchy .isDescendant (
194+ ((ClassOrInterfaceType ) assigneeArgs .get (i )).getNameAsString (),
195+ ((ClassOrInterfaceType ) assignedArgs .get (i )).getNameAsString (), mp .get (i ).depth ());
196+ case CONTRAVARIANT :
197+ return classHierarchy .isDescendant (
198+ ((ClassOrInterfaceType ) assignedArgs .get (i )).getNameAsString (),
199+ ((ClassOrInterfaceType ) assigneeArgs .get (i )).getNameAsString (), mp .get (i ).depth ());
200+ default :
201+ return false ;
202+ }
203+ }
204+ }
205+
206+ for (int i = 0 ; i < assigneeArgs .size (); ++i ) {
207+ if (!(assignedArgs .get (i ) instanceof ClassOrInterfaceType )
208+ || !(assignedArgs .get (i ) instanceof ClassOrInterfaceType )) {
209+ continue ;
210+ }
211+ isSubtype = isSubtype && isValidSubtype ((ClassOrInterfaceType ) assigneeArgs .get (i ),
212+ (ClassOrInterfaceType ) assignedArgs .get (i ),
213+ params );
214+ }
215+ return classHierarchy .isDescendant (assigneeType .getNameAsString (),
216+ assignedType .getNameAsString (), -1 );
159217 }
160218}
0 commit comments