Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deduplicate module names #2728

Merged
merged 2 commits into from
Mar 31, 2017
Merged

Deduplicate module names #2728

merged 2 commits into from
Mar 31, 2017

Conversation

alfonsogarciacaro
Copy link
Contributor

Giving it a shot at continuing #2686. Apparently I cannot run the tests locally so let see what CI says.

@cartermp
Copy link
Contributor

@alfonsogarciacaro You can always say @dotnet-bot test this please to trigger CI. No need to make a commit to re-trigger 😄

@cartermp cartermp requested a review from dsyme March 29, 2017 22:15
@vasily-kirichenko
Copy link
Contributor

@alfonsogarciacaro you can run those failing tests locally, no need to wait long time until CI finishes.

@alfonsogarciacaro alfonsogarciacaro changed the title CompileOps.qnameOrder uses full file path without extension to compare instead of module name inferred from file name [WIP] CompileOps.qnameOrder uses full file path without extension to compare instead of module name inferred from file name Mar 30, 2017
@alfonsogarciacaro
Copy link
Contributor Author

alfonsogarciacaro commented Mar 30, 2017

@cartermp @vasily-kirichenko The build script refuses to run the tests locally for me.

capture

@vasily-kirichenko
Copy link
Contributor

@alfonsogarciacaro Install NUnit 3 test runner adapter VS extension, find a failing test in test explorer and run it.

@forki
Copy link
Contributor

forki commented Mar 30, 2017

tests now work on my machine.

@forki
Copy link
Contributor

forki commented Mar 30, 2017

error

@alfonsogarciacaro it looks it's one step further. It can't write down the IL because the module is twice in the ILTypeDef list

@dsyme it's failing at:

image

@forki
Copy link
Contributor

forki commented Mar 30, 2017

I think the whole approach is wrong. These implicit modules need to get different internal names. I think we discussed that already somewhere. I will try to look deeper tomorrow. But the qname sorter is definitely too late and fixes only symptoms

@alfonsogarciacaro
Copy link
Contributor Author

A couple of notes:

  • I can reproduce this with Fable 0.7 (which uses FCS 9.0.1) so it doesn't seem to be a regression
  • I cannot reproduce it always when there are two files with same name, I think it's because the problem comes from CanonicalizeFilename which is only called for files which have a single module and other conditions I don't understand :/

@dsyme
Copy link
Contributor

dsyme commented Mar 30, 2017

@alfonsogarciacaro I'll wirk on this first thing in the morning, followed by the stack overflow issue.

I understand now how important this is for Fable 1.0

@alfonsogarciacaro
Copy link
Contributor Author

@dsyme Awesome, thank you!

@forki
Copy link
Contributor

forki commented Mar 31, 2017

@alfonsogarciacaro alfonsogarciacaro changed the title [WIP] CompileOps.qnameOrder uses full file path without extension to compare instead of module name inferred from file name Deduplicate module names Mar 31, 2017
@forki
Copy link
Contributor

forki commented Mar 31, 2017

OK. I think now Impl and Sig files are synced and deduplicated. Ready for review

@forki
Copy link
Contributor

forki commented Mar 31, 2017

Open Question: do we need to do the same for fsi?

@@ -471,7 +471,8 @@ type MetadataTable<'T> =
t |> Array.iteri (fun i x -> h.[x] <- (i+1))

member tbl.AddUniqueEntry nm geterr x =
if tbl.dict.ContainsKey x then failwith ("duplicate entry '"+geterr x+"' in "+nm+" table")
if tbl.dict.ContainsKey x then
failwith ("duplicate entry '" + geterr x + "' in " + nm + " table")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

failwithf maybe?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just changed alignment

@@ -3547,7 +3548,7 @@ let writeBinaryAndReportMappings (outfile, ilg: ILGlobals, pdbfile: string optio
// Store the public key from the signer into the manifest. This means it will be written
// to the binary and also acts as an indicator to leave space for delay sign

reportTime showTimes "Write Started";
reportTime showTimes "Write Started"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💪


member x.Range =
let (QualifiedNameOfFile t) = x
t.idRange
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I find the old code more compact and readable.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed on this one

@@ -303,7 +303,7 @@ module InterfaceFileWriter =
fprintfn os "#light"
fprintfn os ""

for (TImplFile(_, _, mexpr, _, _)) in declaredImpls do
for (TImplFile(_fileName, _, _, mexpr, _, _)) in declaredImpls do
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Other unused fields are ignored with _, so should _fileName.


let inputs =
// Deduplicate module names
let seen = Dictionary<_,Set<_>>()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's unclear what type this seen thing has. Could you add a comment or, at least, types?

let qualifiedNameOfFile = if count = 1 then qualifiedNameOfFile else QualifiedNameOfFile(Ident(id.idText + "___" + count.ToString(),id.idRange))
let input = ParsedInput.SigFile (ParsedSigFileInput.ParsedSigFileInput(fileName,qualifiedNameOfFile,scopedPragmas,hashDirectives,modules))
input,x
| _ ->
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These two branches have a lot in common. Maybe it's worth to extract some logic in a function or two?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, my preference is to encapsulate such name generators (though I haven't done it particularly well - see the ones in ast.fs which are not suitable here since they use range line number information). So

type UniqueNameGenerator() = 
    let seen = Dictionary...
    member x.GetName(text) = 
           match seen.TryGetValue text with
           | true, paths ->
               let count = if paths.Contains path then paths.Count else paths.Count + 1
               seen.[text] <- Set.add path paths
               if count = 1 then text else text + "___" + count.ToString()

etc

@@ -1812,7 +1846,7 @@ let main1(Args (ctok, tcGlobals, tcImports: TcImports, frameworkTcImports, gener
// it as the updated global error logger and never remove it
let oldLogger = errorLogger
let errorLogger =
let scopedPragmas = [ for (TImplFile(_, pragmas, _, _, _)) in typedImplFiles do yield! pragmas ]
let scopedPragmas = [ for (TImplFile(_fileName, _, pragmas, _, _, _)) in typedImplFiles do yield! pragmas ]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same, just use _.

error(Error(FSComp.SR.fscProblemWritingBinary(outfile, msg), rangeCmdArgs))
with e ->
errorRecoveryNoRange e
exiter.Exit 1
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why nested try..with? Is it for handling possible exceptions thrown by error(Error(FSComp.SR.fscProblemWritingBinary(outfile, msg), rangeCmdArgs))?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

He's just changing the indenting in this case ( @forki - perhaps remove the formatting changes to make the PR minimal? I don't mind either way though)

@vasily-kirichenko
Copy link
Contributor

It's hard to review because of lots of whitespace changes.

@forki
Copy link
Contributor

forki commented Mar 31, 2017 via email

@dsyme
Copy link
Contributor

dsyme commented Mar 31, 2017

@forki Stepping back a bit, this whole QualifiedNameOfFile stuff is really irritating. AFAICS it's only used for the names given to these internally generated classes:

image

That's all. Just a simple name. So easy. I believe the only issue is that name must match between the processing of the signature of implementation - because other files are allowed to access straight into these items - e.g. when taking the address of a mutable static fields.

So on a quick glance your approach is basically right - generate nice names but be careful about de-duplicating. That said, there's probably a much easier way to do this all (the whole thing, not just the de-duplicating) given the end result is so simple, or even just to somehow get rid of the information altogether

@forki
Copy link
Contributor

forki commented Mar 31, 2017

My approach is to try to not break backwards compatibility. ;-)

Copy link
Contributor

@dsyme dsyme left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor changes requested


member x.Range =
let (QualifiedNameOfFile t) = x
t.idRange
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed on this one

error(Error(FSComp.SR.fscProblemWritingBinary(outfile, msg), rangeCmdArgs))
with e ->
errorRecoveryNoRange e
exiter.Exit 1
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

He's just changing the indenting in this case ( @forki - perhaps remove the formatting changes to make the PR minimal? I don't mind either way though)

let qualifiedNameOfFile = if count = 1 then qualifiedNameOfFile else QualifiedNameOfFile(Ident(id.idText + "___" + count.ToString(),id.idRange))
let input = ParsedInput.SigFile (ParsedSigFileInput.ParsedSigFileInput(fileName,qualifiedNameOfFile,scopedPragmas,hashDirectives,modules))
input,x
| _ ->
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, my preference is to encapsulate such name generators (though I haven't done it particularly well - see the ones in ast.fs which are not suitable here since they use range line number information). So

type UniqueNameGenerator() = 
    let seen = Dictionary...
    member x.GetName(text) = 
           match seen.TryGetValue text with
           | true, paths ->
               let count = if paths.Contains path then paths.Count else paths.Count + 1
               seen.[text] <- Set.add path paths
               if count = 1 then text else text + "___" + count.ToString()

etc

@dsyme
Copy link
Contributor

dsyme commented Mar 31, 2017

My approach is to try to not break backwards compatibility. ;-)

Agreed.

@dsyme
Copy link
Contributor

dsyme commented Mar 31, 2017

@alfonsogarciacaro You say you need this for Fable 1.0 - I presume you need it integrated to FCS? thanks

Copy link
Contributor

@forki forki left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool! So how do we get that into FCS? ;-)

@alfonsogarciacaro
Copy link
Contributor Author

@forki has removed the whitespace changes and I've tried to implement some of the comments, please review.

@dsyme Yes, this would be needed for FCS. I can send a PR there but I guess it's no use, as changes in this repo will flow to FCS anyway. It would be ideal if a new FCS version is pushed to nuget, but it it's cumbersome to do it at this moment, I can just fork it and add the change manually for the time being.

@dsyme
Copy link
Contributor

dsyme commented Mar 31, 2017

@alfonsogarciacaro Please submit just the fix to FCS. Don't worry about the test

@KevinRansom
Copy link
Member

@alfonsogarciacaro
Thank you for this

Kevin

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants