@@ -28,6 +28,8 @@ public Compiler(ErrorReporter reporter) {
2828 Coverage = new CoverageInstrumenter ( this ) ;
2929 }
3030
31+ public static string DefaultNameMain = "Main" ;
32+
3133 public abstract string TargetLanguage { get ; }
3234 protected virtual string ModuleSeparator { get => "." ; }
3335 protected virtual string ClassAccessor { get => "." ; }
@@ -1156,7 +1158,7 @@ public void Compile(Program program, TargetWriter wrx) {
11561158 var nt = ( NewtypeDecl ) d ;
11571159 var w = DeclareNewtype ( nt , wr ) ;
11581160 v . Visit ( nt ) ;
1159- CompileClassMembers ( nt , w ) ;
1161+ CompileClassMembers ( program , nt , w ) ;
11601162 } else if ( d is DatatypeDecl ) {
11611163 var dt = ( DatatypeDecl ) d ;
11621164 CheckForCapitalizationConflicts ( dt . Ctors ) ;
@@ -1165,7 +1167,7 @@ public void Compile(Program program, TargetWriter wrx) {
11651167 }
11661168 var w = DeclareDatatype ( dt , wr ) ;
11671169 if ( w != null ) {
1168- CompileClassMembers ( dt , w ) ;
1170+ CompileClassMembers ( program , dt , w ) ;
11691171 }
11701172 } else if ( d is IteratorDecl ) {
11711173 var iter = ( IteratorDecl ) d ;
@@ -1183,7 +1185,7 @@ public void Compile(Program program, TargetWriter wrx) {
11831185 } else if ( d is TraitDecl trait ) {
11841186 // writing the trait
11851187 var w = CreateTrait ( trait . CompileName , trait . IsExtern ( out _ , out _ ) , trait . TypeArgs , trait . ParentTypeInformation . UniqueParentTraits ( ) , trait . tok , wr ) ;
1186- CompileClassMembers ( trait , w ) ;
1188+ CompileClassMembers ( program , trait , w ) ;
11871189 } else if ( d is ClassDecl cl ) {
11881190 var include = true ;
11891191 if ( cl . IsDefaultClass ) {
@@ -1201,12 +1203,12 @@ public void Compile(Program program, TargetWriter wrx) {
12011203 if ( include ) {
12021204 var cw = CreateClass ( IdProtect ( d . EnclosingModuleDefinition . CompileName ) , IdName ( cl ) , classIsExtern , cl . FullName ,
12031205 cl . TypeArgs , cl , cl . ParentTypeInformation . UniqueParentTraits ( ) , cl . tok , wr ) ;
1204- CompileClassMembers ( cl , cw ) ;
1206+ CompileClassMembers ( program , cl , cw ) ;
12051207 cw . Finish ( ) ;
12061208 } else {
12071209 // still check that given members satisfy compilation rules
12081210 var abyss = new NullClassWriter ( ) ;
1209- CompileClassMembers ( cl , abyss ) ;
1211+ CompileClassMembers ( program , cl , abyss ) ;
12101212 }
12111213 } else if ( d is ValuetypeDecl ) {
12121214 // nop
@@ -1335,38 +1337,117 @@ public bool HasMain(Program program, out Method mainMethod) {
13351337 Contract . Ensures ( Contract . Result < bool > ( ) == ( Contract . ValueAtReturn ( out mainMethod ) != null ) ) ;
13361338 mainMethod = null ;
13371339 bool hasMain = false ;
1340+ string name = DafnyOptions . O . MainMethod ;
1341+ if ( name != null && name == "-" ) return false ;
1342+ if ( name != null && name != "" ) {
1343+ foreach ( var module in program . CompileModules ) {
1344+ if ( module . IsAbstract ) {
1345+ // the purpose of an abstract module is to skip compilation
1346+ continue ;
1347+ }
1348+ foreach ( var decl in module . TopLevelDecls ) {
1349+ var c = decl as TopLevelDeclWithMembers ;
1350+ if ( c != null ) {
1351+ foreach ( MemberDecl member in c . Members ) {
1352+ var m = member as Method ;
1353+ if ( m == null ) continue ;
1354+ if ( member . FullDafnyName == name ) {
1355+ mainMethod = m ;
1356+ if ( ! IsPermittedAsMain ( mainMethod , out string reason ) ) {
1357+ Error ( mainMethod . tok , "The method \" {0}\" is not permitted as a main method ({1})." , null , name , reason ) ;
1358+ mainMethod = null ;
1359+ return false ;
1360+ } else {
1361+ return true ;
1362+ }
1363+ }
1364+ }
1365+ }
1366+ }
1367+ }
1368+ Error ( program . DefaultModule . tok , "Could not find the method named by the -Main option: {0}" , null , name ) ;
1369+ }
13381370 foreach ( var module in program . CompileModules ) {
13391371 if ( module . IsAbstract ) {
13401372 // the purpose of an abstract module is to skip compilation
13411373 continue ;
13421374 }
13431375 foreach ( var decl in module . TopLevelDecls ) {
1344- var c = decl as ClassDecl ;
1376+ var c = decl as TopLevelDeclWithMembers ;
13451377 if ( c != null ) {
13461378 foreach ( var member in c . Members ) {
13471379 var m = member as Method ;
1348- if ( m != null && IsMain ( m ) ) {
1380+ if ( m != null && Attributes . Contains ( m . Attributes , "main" ) ) {
13491381 if ( mainMethod == null ) {
13501382 mainMethod = m ;
13511383 hasMain = true ;
13521384 } else {
13531385 // more than one main in the program
1354- Error ( m . tok , "More than one method is declared as \" main\" . First declaration appeared at {0}." , null , ErrorReporter . TokenToString ( mainMethod . tok ) ) ;
1386+ Error ( m . tok , "More than one method is marked \" {{:main}}\" . First declaration appeared at {0}." , null ,
1387+ ErrorReporter . TokenToString ( mainMethod . tok ) ) ;
13551388 hasMain = false ;
13561389 }
13571390 }
13581391 }
13591392 }
13601393 }
13611394 }
1362- if ( ! hasMain ) {
1395+ if ( hasMain ) {
1396+ if ( ! IsPermittedAsMain ( mainMethod , out string reason ) ) {
1397+ Error ( mainMethod . tok , "This method marked \" {{:main}}\" is not permitted as a main method ({0})." , null , reason ) ;
1398+ mainMethod = null ;
1399+ return false ;
1400+ } else {
1401+ return true ;
1402+ }
1403+ }
1404+ if ( mainMethod != null ) {
1405+ mainMethod = null ;
1406+ return false ;
1407+ }
1408+
1409+ mainMethod = null ;
1410+ foreach ( var module in program . CompileModules ) {
1411+ if ( module . IsAbstract ) {
1412+ // the purpose of an abstract module is to skip compilation
1413+ continue ;
1414+ }
1415+ foreach ( var decl in module . TopLevelDecls ) {
1416+ var c = decl as TopLevelDeclWithMembers ;
1417+ if ( c != null ) {
1418+ foreach ( var member in c . Members ) {
1419+ var m = member as Method ;
1420+ if ( m != null && m . Name == DefaultNameMain ) {
1421+ if ( mainMethod == null ) {
1422+ mainMethod = m ;
1423+ hasMain = true ;
1424+ } else {
1425+ // more than one main in the program
1426+ Error ( m . tok , "More than one method is declared as \" {0}\" . First declaration appeared at {1}." , null ,
1427+ DefaultNameMain , ErrorReporter . TokenToString ( mainMethod . tok ) ) ;
1428+ hasMain = false ;
1429+ }
1430+ }
1431+ }
1432+ }
1433+ }
1434+ }
1435+
1436+ if ( hasMain ) {
1437+ if ( ! IsPermittedAsMain ( mainMethod , out string reason ) ) {
1438+ Error ( mainMethod . tok , "This method \" Main\" is not permitted as a main method ({0})." , null , reason ) ;
1439+ return false ;
1440+ } else {
1441+ return true ;
1442+ }
1443+ } else {
13631444 // make sure "mainMethod" returns as null
13641445 mainMethod = null ;
1446+ return false ;
13651447 }
1366- return hasMain ;
13671448 }
13681449
1369- public static bool IsMain ( Method m ) {
1450+ public static bool IsPermittedAsMain ( Method m , out String reason ) {
13701451 Contract . Requires ( m . EnclosingClass is TopLevelDeclWithMembers ) ;
13711452 // In order to be a legal Main() method, the following must be true:
13721453 // The method is not a ghost method
@@ -1382,18 +1463,45 @@ public static bool IsMain(Method m) {
13821463 // Note, in the case where the method is annotated with {:main}, the method is allowed to have preconditions and modifies clauses.
13831464 // This lets the programmer add some explicit assumptions about the outside world, modeled, for example, via ghost parameters.
13841465 var cl = ( TopLevelDeclWithMembers ) m . EnclosingClass ;
1385- if ( ! m . IsGhost && m . TypeArgs . Count == 0 && cl . TypeArgs . Count == 0 ) {
1386- if ( m . Ins . TrueForAll ( f => f . IsGhost ) && m . Outs . TrueForAll ( f => f . IsGhost ) ) {
1387- if ( m . IsStatic || ( cl is ClassDecl klass && ! ( klass is TraitDecl ) && ! klass . HasConstructor ) ) {
1388- if ( m . Name == "Main" && m . Req . Count == 0 && m . Mod . Expressions . Count == 0 ) {
1389- return true ;
1390- } else if ( Attributes . Contains ( m . Attributes , "main" ) ) {
1391- return true ;
1392- }
1393- }
1394- }
1466+ if ( m . IsGhost ) {
1467+ reason = "the method is ghost" ;
1468+ return false ;
13951469 }
1396- return false ;
1470+ if ( m . TypeArgs . Count != 0 ) {
1471+ reason = "the method has type parameters" ;
1472+ return false ;
1473+ }
1474+ if ( cl . TypeArgs . Count != 0 ) {
1475+ reason = "the enclosing class has type parameters" ;
1476+ return false ;
1477+ }
1478+ if ( ! m . IsStatic && ! cl . Members . TrueForAll ( f => ! ( f is Constructor ) ) ) {
1479+ reason = "the method is not static and the enclosing class has constructors" ;
1480+ return false ;
1481+ }
1482+ if ( ! m . Ins . TrueForAll ( f => f . IsGhost ) ) {
1483+ reason = "the method has non-ghost parameters" ;
1484+ return false ;
1485+ }
1486+ if ( ! m . Outs . TrueForAll ( f => f . IsGhost ) ) {
1487+ reason = "the method has non-ghost out parameters" ;
1488+ return false ;
1489+ }
1490+ if ( Attributes . Contains ( m . Attributes , "main" ) ) {
1491+ reason = "" ;
1492+ return true ;
1493+ }
1494+ if ( m . Req . Count != 0 )
1495+ {
1496+ reason = "the method has requires clauses" ;
1497+ return false ;
1498+ }
1499+ if ( m . Mod . Expressions . Count != 0 ) {
1500+ reason = "the method has modifies clauses" ;
1501+ return false ;
1502+ }
1503+ reason = "" ;
1504+ return true ;
13971505 }
13981506
13991507 void OrderedBySCC ( List < MemberDecl > decls , TopLevelDeclWithMembers c ) {
@@ -1426,7 +1534,7 @@ public static bool NeedsCustomReceiver(MemberDecl member) {
14261534 return false ;
14271535 }
14281536
1429- void CompileClassMembers ( TopLevelDeclWithMembers c , IClassWriter classWriter ) {
1537+ void CompileClassMembers ( Program program , TopLevelDeclWithMembers c , IClassWriter classWriter ) {
14301538 Contract . Requires ( c != null ) ;
14311539 Contract . Requires ( classWriter != null ) ;
14321540 Contract . Requires ( thisContext == null ) ;
@@ -1641,10 +1749,10 @@ void CompileClassMembers(TopLevelDeclWithMembers c, IClassWriter classWriter) {
16411749 RedeclareInheritedMember ( m , classWriter ) ;
16421750 }
16431751 if ( m . Body != null ) {
1644- CompileMethod ( m , classWriter , true ) ;
1752+ CompileMethod ( program , m , classWriter , true ) ;
16451753 }
16461754 } else {
1647- CompileMethod ( m , classWriter , false ) ;
1755+ CompileMethod ( program , m , classWriter , false ) ;
16481756 }
16491757 v . Visit ( m ) ;
16501758 } else {
@@ -2052,7 +2160,7 @@ private void CompileFunction(Function f, IClassWriter cw, bool lookasideBody) {
20522160 }
20532161 }
20542162
2055- private void CompileMethod ( Method m , IClassWriter cw , bool lookasideBody ) {
2163+ private void CompileMethod ( Program program , Method m , IClassWriter cw , bool lookasideBody ) {
20562164 Contract . Requires ( cw != null ) ;
20572165 Contract . Requires ( m != null ) ;
20582166 Contract . Requires ( m . Body != null || Attributes . Contains ( m . Attributes , "dllimport" ) || ( IncludeExternMembers && Attributes . Contains ( m . Attributes , "extern" ) ) ) ;
@@ -2086,8 +2194,7 @@ private void CompileMethod(Method m, IClassWriter cw, bool lookasideBody) {
20862194 }
20872195 }
20882196
2089- // allow the Main method to be an instance method
2090- if ( IsMain ( m ) && ( ! m . IsStatic || m . CompileName != "Main" ) ) {
2197+ if ( m == program . MainMethod && IssueCreateStaticMain ( m ) ) {
20912198 w = CreateStaticMain ( cw ) ;
20922199 if ( ! m . IsStatic ) {
20932200 var c = m . EnclosingClass ;
@@ -2102,6 +2209,11 @@ private void CompileMethod(Method m, IClassWriter cw, bool lookasideBody) {
21022209 }
21032210 }
21042211
2212+ protected virtual bool IssueCreateStaticMain ( Method m ) {
2213+ return ! m . IsStatic ;
2214+ }
2215+
2216+
21052217 void TrCasePatternOpt < VT > ( CasePattern < VT > pat , Expression rhs , TargetWriter wr , bool inLetExprBody ) where VT : IVariable {
21062218 TrCasePatternOpt ( pat , rhs , null , rhs . Type , rhs . tok , wr , inLetExprBody ) ;
21072219 }
0 commit comments