public void step3(Map<String,String> fileNameToPackageName,Map<String,List<FunDef>> fileNameToFunctions) throws SyntaxException {
  for (  STypeDef sTypeDef : typeDefSet) {
    if (sTypeDef instanceof SClassDef) {
      List<STypeDef> circularRecorder=new ArrayList<>();
      SClassDef parent=((SClassDef)sTypeDef).parent();
      while (parent != null) {
        circularRecorder.add(parent);
        if (parent.equals(sTypeDef)) {
          err.SyntaxException("circular inheritance " + circularRecorder,LineCol.SYNTHETIC);
          return;
        }
        parent=parent.parent();
      }
      circularRecorder.clear();
    }
 else     if (sTypeDef instanceof SInterfaceDef) {
      SInterfaceDef i=(SInterfaceDef)sTypeDef;
      checkInterfaceCircularInheritance(i,i.superInterfaces(),new ArrayList<>());
    }
 else {
      throw new LtBug("wrong STypeDefType " + sTypeDef.getClass());
    }
  }
  for (  STypeDef sTypeDef : typeDefSet) {
    checkOverrideAllMethods(sTypeDef);
  }
  for (  String fileName : mapOfStatements.keySet()) {
    List<Import> imports=fileNameToImport.get(fileName);
    String pkg=fileNameToPackageName.get(fileName);
    List<FunDef> functionDefs=fileNameToFunctions.get(fileName);
    for (    FunDef fun : functionDefs) {
      STypeDef type=getTypeWithAccess(fun.superType,imports);
      if (!(type instanceof SClassDef || type instanceof SInterfaceDef)) {
        err.SyntaxException("function super type should be functional interfaces or functional abstract classes",fun.superType.line_col());
        return;
      }
      SConstructorDef[] zeroParamConstructor=new SConstructorDef[1];
      SMethodDef[] methodToOverride=new SMethodDef[1];
      if (!getMethodForLambda(type,zeroParamConstructor,methodToOverride)) {
        err.SyntaxException("function super type should be functional interfaces or functional abstract classes",fun.superType.line_col());
        return;
      }
      SClassDef sClassDef=(SClassDef)types.get(pkg + fun.name);
      parseAnnos(fun.annos,sClassDef,imports,ElementType.TYPE,Arrays.asList(ElementType.METHOD,ElementType.CONSTRUCTOR));
      if (zeroParamConstructor[0] == null) {
        sClassDef.setParent(getObject_Class());
        assert type instanceof SInterfaceDef;
        sClassDef.superInterfaces().add((SInterfaceDef)type);
      }
 else {
        sClassDef.setParent((SClassDef)zeroParamConstructor[0].declaringType());
      }
      SConstructorDef cons=new SConstructorDef(LineCol.SYNTHETIC);
      parseAnnos(fun.annos,cons,imports,ElementType.CONSTRUCTOR,Arrays.asList(ElementType.TYPE,ElementType.METHOD));
      cons.setDeclaringType(sClassDef);
      sClassDef.constructors().add(cons);
      if (zeroParamConstructor[0] == null) {
        zeroParamConstructor[0]=getObject_Class().constructors().get(0);
      }
      cons.statements().add(new Ins.InvokeSpecial(new Ins.This(sClassDef),zeroParamConstructor[0],LineCol.SYNTHETIC));
      cons.modifiers().add(SModifier.PUBLIC);
      SMethodDef method=new SMethodDef(LineCol.SYNTHETIC);
      method.setDeclaringType(sClassDef);
      method.setReturnType(getRealReturnType(methodToOverride[0].getReturnType(),true));
      method.setName(methodToOverride[0].name());
      sClassDef.methods().add(method);
      parseAnnos(fun.annos,method,imports,ElementType.METHOD,Arrays.asList(ElementType.TYPE,ElementType.CONSTRUCTOR));
      method.modifiers().add(SModifier.PUBLIC);
      parseParameters(fun.params,fun.params.size(),method,imports,false);
      methodToStatements.put(method,fun.statements);
      checkOverrideAllMethods(sClassDef);
    }
  }
  for (  STypeDef typeDef : typeDefSet) {
    for (    SAnno anno : typeDef.annos()) {
      if (anno.type().fullName().equals("java.lang.FunctionalInterface")) {
        final String msg=typeDef + " is not a functional interface";
        if (typeDef instanceof SInterfaceDef) {
          if (!getMethodForLambda(typeDef,new SConstructorDef[1],new SMethodDef[1])) {
            err.SyntaxException(msg,typeDef.line_col());
            return;
          }
        }
 else {
          err.SyntaxException(msg,typeDef.line_col());
          return;
        }
      }
 else       if (anno.type().fullName().equals("lt.lang.FunctionalAbstractClass")) {
        final String msg=typeDef + " is not a functional abstract class";
        if (typeDef instanceof SClassDef) {
          if (!getMethodForLambda(typeDef,new SConstructorDef[1],new SMethodDef[1])) {
            err.SyntaxException(msg,typeDef.line_col());
            return;
          }
        }
 else {
          err.SyntaxException(msg,typeDef.line_col());
          return;
        }
      }
    }
    List<SMethodDef> methods;
    if (typeDef instanceof SClassDef)     methods=((SClassDef)typeDef).methods();
 else     methods=((SInterfaceDef)typeDef).methods();
    for (    SMethodDef method : methods) {
      for (      SAnno anno : method.annos()) {
        if (anno.type().fullName().equals("java.lang.Override")) {
          if (method.overRide().isEmpty()) {
            err.SyntaxException(method + " doesn't override any method",method.line_col());
            return;
          }
        }
      }
    }
  }
  for (  STypeDef typeDef : typeDefSet) {
    if (typeDef instanceof SClassDef) {
      SClassDef cls=(SClassDef)typeDef;
      if (cls.isDataClass()) {
        fillMethodsIntoDataClass(cls);
      }
    }
  }
}

public void step3 ( Map < String , String > fileNameToPackageName , Map < String , List < FunDef > > fileNameToFunctions ) throws SyntaxException { for ( STypeDef sTypeDef : typeDefSet ) { if ( sTypeDef instanceof SClassDef ) { List < STypeDef > circularRecorder = new ArrayList < > ( ) ; SClassDef parent = ( ( SClassDef ) sTypeDef ) . parent ( ) ; while ( parent != null ) { circularRecorder . add ( parent ) ; if ( parent . equals ( sTypeDef ) ) { err . SyntaxException ( "circular inheritance " + circularRecorder , LineCol . SYNTHETIC ) ; return ; } parent = parent . parent ( ) ; } circularRecorder . clear ( ) ; } else if ( sTypeDef instanceof SInterfaceDef ) { SInterfaceDef i = ( SInterfaceDef ) sTypeDef ; checkInterfaceCircularInheritance ( i , i . superInterfaces ( ) , new ArrayList < > ( ) ) ; } else { throw new LtBug ( "wrong STypeDefType " + sTypeDef . getClass ( ) ) ; } } for ( STypeDef sTypeDef : typeDefSet ) { checkOverrideAllMethods ( sTypeDef ) ; } for ( String fileName : mapOfStatements . keySet ( ) ) { List < Import > imports = fileNameToImport . get ( fileName ) ; String pkg = fileNameToPackageName . get ( fileName ) ; List < FunDef > functionDefs = fileNameToFunctions . get ( fileName ) ; for ( FunDef fun : functionDefs ) { STypeDef type = getTypeWithAccess ( fun . superType , imports ) ; if ( ! ( type instanceof SClassDef || type instanceof SInterfaceDef ) ) { err . SyntaxException ( "function super type should be functional interfaces or functional abstract classes" , fun . superType . line_col ( ) ) ; return ; } SConstructorDef [ ] zeroParamConstructor = new SConstructorDef [ 1 ] ; SMethodDef [ ] methodToOverride = new SMethodDef [ 1 ] ; if ( ! getMethodForLambda ( type , zeroParamConstructor , methodToOverride ) ) { err . SyntaxException ( "function super type should be functional interfaces or functional abstract classes" , fun . superType . line_col ( ) ) ; return ; } SClassDef sClassDef = ( SClassDef ) types . get ( pkg + fun . name ) ; parseAnnos ( fun . annos , sClassDef , imports , ElementType . TYPE , Arrays . asList ( ElementType . METHOD , ElementType . CONSTRUCTOR ) ) ; if ( zeroParamConstructor [ 0 ] == null ) { sClassDef . setParent ( getObject_Class ( ) ) ; assert type instanceof SInterfaceDef ; sClassDef . superInterfaces ( ) . add ( ( SInterfaceDef ) type ) ; } else { sClassDef . setParent ( ( SClassDef ) zeroParamConstructor [ 0 ] . declaringType ( ) ) ; } SConstructorDef cons = new SConstructorDef ( LineCol . SYNTHETIC ) ; parseAnnos ( fun . annos , cons , imports , ElementType . CONSTRUCTOR , Arrays . asList ( ElementType . TYPE , ElementType . METHOD ) ) ; cons . setDeclaringType ( sClassDef ) ; sClassDef . constructors ( ) . add ( cons ) ; if ( zeroParamConstructor [ 0 ] == null ) { zeroParamConstructor [ 0 ] = getObject_Class ( ) . constructors ( ) . get ( 0 ) ; } cons . statements ( ) . add ( new Ins . InvokeSpecial ( new Ins . This ( sClassDef ) , zeroParamConstructor [ 0 ] , LineCol . SYNTHETIC ) ) ; cons . modifiers ( ) . add ( SModifier . PUBLIC ) ; SMethodDef method = new SMethodDef ( LineCol . SYNTHETIC ) ; method . setDeclaringType ( sClassDef ) ; method . setReturnType ( getRealReturnType ( methodToOverride [ 0 ] . getReturnType ( ) , true ) ) ; method . setName ( methodToOverride [ 0 ] . name ( ) ) ; sClassDef . methods ( ) . add ( method ) ; parseAnnos ( fun . annos , method , imports , ElementType . METHOD , Arrays . asList ( ElementType . TYPE , ElementType . CONSTRUCTOR ) ) ; method . modifiers ( ) . add ( SModifier . PUBLIC ) ; parseParameters ( fun . params , fun . params . size ( ) , method , imports , false ) ; methodToStatements . put ( method , fun . statements ) ; checkOverrideAllMethods ( sClassDef ) ; } } for ( STypeDef typeDef : typeDefSet ) { for ( SAnno anno : typeDef . annos ( ) ) { if ( anno . type ( ) . fullName ( ) . equals ( "java.lang.FunctionalInterface" ) ) { final String msg = typeDef + " is not a functional interface" ; if ( typeDef instanceof SInterfaceDef ) { if ( ! getMethodForLambda ( typeDef , new SConstructorDef [ 1 ] , new SMethodDef [ 1 ] ) ) { err . SyntaxException ( msg , typeDef . line_col ( ) ) ; return ; } } else { err . SyntaxException ( msg , typeDef . line_col ( ) ) ; return ; } } else if ( anno . type ( ) . fullName ( ) . equals ( "lt.lang.FunctionalAbstractClass" ) ) { final String msg = typeDef + " is not a functional abstract class" ; if ( typeDef instanceof SClassDef ) { if ( ! getMethodForLambda ( typeDef , new SConstructorDef [ 1 ] , new SMethodDef [ 1 ] ) ) { err . SyntaxException ( msg , typeDef . line_col ( ) ) ; return ; } } else { err . SyntaxException ( msg , typeDef . line_col ( ) ) ; return ; } } } List < SMethodDef > methods ; if ( typeDef instanceof SClassDef ) methods = ( ( SClassDef ) typeDef ) . methods ( ) ; else methods = ( ( SInterfaceDef ) typeDef ) . methods ( ) ; for ( SMethodDef method : methods ) { for ( SAnno anno : method . annos ( ) ) { if ( anno . type ( ) . fullName ( ) . equals ( "java.lang.Override" ) ) { if ( method . overRide ( ) . isEmpty ( ) ) { err . SyntaxException ( method + " doesn't override any method" , method . line_col ( ) ) ; return ; } } } } } for ( STypeDef typeDef : typeDefSet ) { if ( typeDef instanceof SClassDef ) { SClassDef cls = ( SClassDef ) typeDef ; if ( cls . isDataClass ( ) ) { fillMethodsIntoDataClass ( cls ) ; } } } }
= = = = = = = = step 3 = = = = = = = = check circular inheritance
