Skip to content

Commit dcafb5f

Browse files
committed
WIP - making .fsi files work
1 parent b8d45e0 commit dcafb5f

8 files changed

Lines changed: 359 additions & 61 deletions

File tree

src/Compiler/Driver/ParseAndCheckInputs.fs

Lines changed: 149 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1383,8 +1383,13 @@ let CheckOneInput
13831383
)
13841384
}
13851385

1386+
type FsiBackedInfo =
1387+
Import.ImportMap * string list option * ModuleOrNamespaceType *
1388+
bool * ParsedImplFileInput * TcState * ModuleOrNamespaceType
13861389

1390+
let mutable asts = Dictionary<string, ParsedInput>()
13871391

1392+
let mutable fsiBackedInfos = Dictionary<string, FsiBackedInfo>()
13881393

13891394
/// Typecheck a single file (or interactive entry into F# Interactive)
13901395
let CheckOneInputAux'
@@ -1438,74 +1443,162 @@ let CheckOneInputAux'
14381443
tcState.tcsTcSigEnv
14391444
file
14401445

1446+
// Open the prefixPath for fsi.exe
1447+
let tcEnv, _openDecls1 =
1448+
match prefixPathOpt with
1449+
| None -> tcEnv, []
1450+
| Some prefixPath ->
1451+
let m = qualNameOfFile.Range
1452+
TcOpenModuleOrNamespaceDecl tcSink tcGlobals amap m tcEnv (prefixPath, m)
1453+
14411454
return fun tcState ->
1442-
let rootSigs = Zmap.add qualNameOfFile sigFileType tcState.tcsRootSigs
1443-
1444-
// Add the signature to the signature env (unless it had an explicit signature)
1445-
let ccuSigForFile = CombineCcuContentFragments [ sigFileType; tcState.tcsCcuSig ]
1446-
1447-
// Open the prefixPath for fsi.exe
1448-
let tcEnv, _openDecls1 =
1449-
match prefixPathOpt with
1450-
| None -> tcEnv, []
1451-
| Some prefixPath ->
1452-
let m = qualNameOfFile.Range
1453-
TcOpenModuleOrNamespaceDecl tcSink tcGlobals amap m tcEnv (prefixPath, m)
1454-
1455-
let partialResult = tcEnv, EmptyTopAttrs, None, ccuSigForFile
1455+
let fsiPartialResult, tcState =
1456+
let rootSigs = Zmap.add qualNameOfFile sigFileType tcState.tcsRootSigs
1457+
1458+
// Add the signature to the signature env (unless it had an explicit signature)
1459+
let ccuSigForFile = CombineCcuContentFragments [ sigFileType; tcState.tcsCcuSig ]
1460+
1461+
let partialResult = tcEnv, EmptyTopAttrs, None, ccuSigForFile
1462+
1463+
let tcState =
1464+
{ tcState with
1465+
tcsTcSigEnv = tcEnv
1466+
tcsTcImplEnv = tcState.tcsTcImplEnv
1467+
tcsRootSigs = rootSigs
1468+
tcsCreatesGeneratedProvidedTypes = tcState.tcsCreatesGeneratedProvidedTypes || createsGeneratedProvidedTypes
1469+
}
1470+
partialResult, tcState
14561471

1457-
let tcState =
1458-
{ tcState with
1459-
tcsTcSigEnv = tcEnv
1460-
tcsTcImplEnv = tcState.tcsTcImplEnv
1461-
tcsRootSigs = rootSigs
1462-
tcsCreatesGeneratedProvidedTypes = tcState.tcsCreatesGeneratedProvidedTypes || createsGeneratedProvidedTypes
1463-
}
1464-
1465-
partialResult, tcState
1472+
// Create dedicated state & some data for the .fs file type-checking later on - save it in a dict
1473+
let fsTcState =
1474+
let hadSig = true
1475+
// Add dummy .fs results
1476+
// Adjust the TcState as if it has been checked, which makes the signature for the file available later
1477+
// in the compilation order.
1478+
let tcStateForImplFile = tcState
1479+
let fsName = file.FileName.TrimEnd('i')
1480+
let fsQualifiedName = asts[fsName].QualifiedName
1481+
let qualNameOfFile = fsQualifiedName
1482+
let priorErrors = checkForErrors ()
1483+
1484+
// Add dummy TcState so that others can use this file through the .fsi stuff, without type-checking .fs
1485+
// Don't use it for this file's type-checking - it will cause duplicates
1486+
let ccuSigForFile, tcState =
1487+
AddCheckResultsToTcState
1488+
(tcGlobals, amap, hadSig, prefixPathOpt, tcSink, tcState.tcsTcImplEnv, qualNameOfFile, sigFileType)
1489+
tcState
1490+
1491+
// Save info needed for type-checking .fs file later on
1492+
let fsiBackedInfo: FsiBackedInfo =
1493+
let ast = asts[fsName]
1494+
let file =
1495+
match ast with
1496+
| ParsedInput.ImplFile parsedImplFileInput -> parsedImplFileInput
1497+
| ParsedInput.SigFile _ -> failwith "Unexpected SigFile"
1498+
amap, conditionalDefines, sigFileType, priorErrors, file, tcStateForImplFile, ccuSigForFile
1499+
1500+
fsiBackedInfos[fsName] <- fsiBackedInfo
1501+
1502+
tcState
1503+
//
1504+
// let _, finalTcState =
1505+
// match dummyFsPartialResult with
1506+
// | amap, _conditionalDefines, rootSig, _priorErrors, file, tcStateForImplFile, _ccuSigForFile ->
1507+
// AddDummyCheckResultsToTcState(
1508+
// tcGlobals,
1509+
// amap,
1510+
// file.QualifiedName,
1511+
// prefixPathOpt,
1512+
// tcSink,
1513+
// fsTcState,
1514+
// tcStateForImplFile,
1515+
// rootSig
1516+
// )
1517+
1518+
fsiPartialResult, fsTcState
14661519

14671520
| ParsedInput.ImplFile file ->
14681521
let qualNameOfFile = file.QualifiedName
14691522

14701523
// Check if we've got an interface for this fragment
14711524
let rootSigOpt = tcState.tcsRootSigs.TryFind qualNameOfFile
14721525

1473-
// Check if we've already seen an implementation for this fragment
1474-
if Zset.contains qualNameOfFile tcState.tcsRootImpls then
1475-
errorR (Error(FSComp.SR.buildImplementationAlreadyGiven (qualNameOfFile.Text), m))
1476-
1477-
let hadSig = rootSigOpt.IsSome
1478-
1479-
// Typecheck the implementation file
1480-
let! topAttrs, implFile, tcEnvAtEnd, createsGeneratedProvidedTypes =
1481-
CheckOneImplFile(
1482-
tcGlobals,
1483-
amap,
1484-
tcState.tcsCcu,
1485-
tcState.tcsImplicitOpenDeclarations,
1486-
checkForErrors,
1487-
conditionalDefines,
1488-
tcSink,
1489-
tcConfig.internalTestSpanStackReferring,
1490-
tcState.tcsTcImplEnv,
1491-
rootSigOpt,
1492-
file
1493-
)
1526+
match rootSigOpt with
1527+
| Some _ ->
1528+
// Type-check an implementation file backed by a signature file
1529+
let info = fsiBackedInfos[file.FileName]
1530+
match info with
1531+
| amap, conditionalDefines, rootSig, priorErrors, file, tcStateForImplFile, ccuSigForFile ->
1532+
1533+
// Check if we've already seen an implementation for this fragment
1534+
if Zset.contains qualNameOfFile tcStateForImplFile.tcsRootImpls then
1535+
errorR (Error(FSComp.SR.buildImplementationAlreadyGiven (qualNameOfFile.Text), m))
1536+
1537+
// In the first linear part of parallel checking, we use a 'checkForErrors' that checks either for errors
1538+
// somewhere in the files processed prior to this one, including from the first phase, or in the processing
1539+
// of this particular file.
1540+
// TODO: Are we handling the commented out code somewhere else?
1541+
let checkForErrors2 () = priorErrors // || (logger.ErrorCount > 0)
1542+
1543+
let topAttrs, implFile, tcEnvAtEnd, createsGeneratedProvidedTypes =
1544+
CheckOneImplFile(
1545+
tcGlobals,
1546+
amap,
1547+
tcStateForImplFile.tcsCcu,
1548+
tcStateForImplFile.tcsImplicitOpenDeclarations,
1549+
checkForErrors2,
1550+
conditionalDefines,
1551+
TcResultsSink.NoSink,
1552+
tcConfig.internalTestSpanStackReferring,
1553+
tcStateForImplFile.tcsTcImplEnv,
1554+
Some rootSig,
1555+
file
1556+
)
1557+
|> Cancellable.runWithoutCancellation
1558+
1559+
let result = (tcEnvAtEnd, topAttrs, Some implFile, ccuSigForFile)
1560+
1561+
// Type-check .fs file using dedicated stuff, not the main tcState as that will cause duplicates.
1562+
// Do not return resuling tcState - it shouldn't be used for anything.
1563+
// Return old tcState, with the exception of one flag.
1564+
return fun tcState ->
1565+
result, { tcState with tcsCreatesGeneratedProvidedTypes = tcState.CreatesGeneratedProvidedTypes || createsGeneratedProvidedTypes }
1566+
| None ->
1567+
// Typecheck the implementation file not backed by a signature file
1568+
1569+
// Check if we've already seen an implementation for this fragment
1570+
if Zset.contains qualNameOfFile tcState.tcsRootImpls then
1571+
errorR (Error(FSComp.SR.buildImplementationAlreadyGiven (qualNameOfFile.Text), m))
1572+
1573+
let! topAttrs, implFile, tcEnvAtEnd, createsGeneratedProvidedTypes =
1574+
CheckOneImplFile(
1575+
tcGlobals,
1576+
amap,
1577+
tcState.tcsCcu,
1578+
tcState.tcsImplicitOpenDeclarations,
1579+
checkForErrors,
1580+
conditionalDefines,
1581+
tcSink,
1582+
tcConfig.internalTestSpanStackReferring,
1583+
tcState.tcsTcImplEnv,
1584+
None,
1585+
file
1586+
)
14941587

1495-
return fun tcState ->
1496-
let ccuSigForFile, tcState =
1497-
AddCheckResultsToTcState
1498-
(tcGlobals, amap, hadSig, prefixPathOpt, tcSink, tcState.tcsTcImplEnv, qualNameOfFile, implFile.Signature)
1499-
tcState
1588+
return fun tcState ->
1589+
let ccuSigForFile, fsTcState =
1590+
AddCheckResultsToTcState
1591+
(tcGlobals, amap, false, prefixPathOpt, tcSink, tcState.tcsTcImplEnv, qualNameOfFile, implFile.Signature)
1592+
tcState
15001593

1501-
let partialResult = tcEnvAtEnd, topAttrs, Some implFile, ccuSigForFile
1502-
1503-
let tcState =
1504-
{ tcState with
1505-
tcsCreatesGeneratedProvidedTypes = tcState.tcsCreatesGeneratedProvidedTypes || createsGeneratedProvidedTypes
1506-
}
1594+
let partialResult = tcEnvAtEnd, topAttrs, Some implFile, ccuSigForFile
1595+
1596+
let tcState =
1597+
{ fsTcState with
1598+
tcsCreatesGeneratedProvidedTypes = fsTcState.tcsCreatesGeneratedProvidedTypes || createsGeneratedProvidedTypes
1599+
}
15071600

1508-
partialResult, tcState
1601+
partialResult, tcState
15091602

15101603
with e ->
15111604
errorRecovery e range0

src/Compiler/Driver/ParseAndCheckInputs.fsi

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,8 @@ val CheckOneInput:
166166
skipImplIfSigExists: bool ->
167167
Cancellable<(TcEnv * TopAttribs * CheckedImplFile option * ModuleOrNamespaceType) * TcState>
168168

169+
val mutable asts : System.Collections.Generic.Dictionary<string, ParsedInput>
170+
169171
/// Check one input, returned as an Eventually computation
170172
val CheckOneInput':
171173
checkForErrors: (unit -> bool) *

src/Compiler/Utilities/Activity.fs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,6 @@ module Activity =
2222

2323
activity
2424

25-
let startNoTags (name: string) : IDisposable = activitySource.StartActivity(name)
25+
let startNoTags (name: string) : IDisposable =
26+
printfn $"StartNoTags {name}"
27+
activitySource.StartActivity(name)

tests/DiamondTest/AB.fs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module DiamondTest.AB
2+
3+
let ab = 17

tests/DiamondTest/DiamondTest.fsproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
<ItemGroup>
1010
<Compile Include="A.fsi" />
11+
<Compile Include="AB.fs" />
1112
<Compile Include="A.fs" />
1213
<Compile Include="B1.fs" />
1314
<Compile Include="B2.fs" />

tests/FSharp.Compiler.Service.Tests2/DiamondArgs.txt

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -208,9 +208,6 @@
208208
--nowarn:75
209209
--simpleresolution
210210
--refout:C:\projekty\fsharp\heuristic\artifacts\obj\DiamondTest\Debug\net7.0\refint\DiamondTest.dll
211-
C:\projekty\fsharp\heuristic\artifacts\obj\DiamondTest\Debug\net7.0\buildproperties.fs
212-
C:\projekty\fsharp\heuristic\artifacts\obj\DiamondTest\Debug\net7.0\.NETCoreApp,Version=v7.0.AssemblyAttributes.fs
213-
C:\projekty\fsharp\heuristic\artifacts\obj\DiamondTest\Debug\net7.0\DiamondTest.AssemblyInfo.fs
214211
C:\projekty\fsharp\heuristic\tests\DiamondTest\A.fsi
215212
C:\projekty\fsharp\heuristic\tests\DiamondTest\A.fs
216213
C:\projekty\fsharp\heuristic\tests\DiamondTest\B1.fs

tests/FSharp.Compiler.Service.Tests2/ParallelTypeChecking.fs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,11 @@ module internal Real =
8181
AST = inp
8282
}
8383
)
84+
ParseAndCheckInputs.asts <-
85+
inputs
86+
|> List.map (fun ast -> ast.FileName, ast)
87+
|> readOnlyDict
88+
|> Dictionary<_,_>
8489
let graph = DepResolving.AutomatedDependencyResolving.detectFileDependencies sourceFiles
8590

8691
let graphJson = graph.Graph |> Seq.map (fun (KeyValue(file, deps)) -> file.Name, deps |> Array.map (fun d -> d.Name)) |> dict

0 commit comments

Comments
 (0)