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

Project References for net sdk projects. #3653

Closed
wants to merge 0 commits into from

Conversation

KevinRansom
Copy link
Member

@KevinRansom KevinRansom commented Sep 27, 2017

Approach

  1. Move ProjectSite wrapping to projectsitesandfiles.fs
  2. Plumb serviceProvider and commandLineOptions deep to allow wrapping
  3. Merge commandline options from disgntime build with FSharpProjectOptimes.

Addresses #3571

@KevinRansom
Copy link
Member Author

@dotnet-bot test Windows_NT Release_ci_part2 Build please

@KevinRansom
Copy link
Member Author

@dsyme , @cartermp, @brettfo can you guys check this out pls

@Pilchie
Copy link
Member

Pilchie commented Sep 30, 2017

I've tried to review this several times, and it's a little dense for me to follow - let's talk about it together on Tuesday.

@KevinRansom
Copy link
Member Author

Sure

@KevinRansom KevinRansom changed the title WIP: Project References for net sdk projects. Project References for net sdk projects. Sep 30, 2017
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.

Some changes needed, see comments

@@ -126,6 +122,8 @@ type internal FSharpProjectOptionsManager
member this.ClearInfoForSingleFileProject(projectId) =
singleFileProjectTable.TryRemove(projectId) |> ignore

member __.CommandLineOptions with get() = commandLineOptions
Copy link
Contributor

Choose a reason for hiding this comment

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

You can (and should) remove with get() to be idiomatic

Copy link
Member Author

Choose a reason for hiding this comment

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

Hmm I need to work on my F# programming skillz :-)

Some options
else
Some { ProjectFileName = options.ProjectFileName
SourceFiles = if sourcePaths.Length = 0 then options.SourceFiles else sourcePaths
Copy link
Contributor

Choose a reason for hiding this comment

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

You already know from the preceding condition that sourcePaths.Lengths = 0 is false, you can simplify this

Copy link
Member Author

Choose a reason for hiding this comment

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

The other line is an 'or' || so I don't necessarily know that it is 0.

            if sourcePaths.Length = 0 || otherOptions.Length = 0 then

Copy link
Contributor

Choose a reason for hiding this comment

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

ok

@@ -183,7 +181,23 @@ type internal FSharpProjectOptionsManager
/// Get the options for a project
member this.TryGetOptionsForProject(projectId: ProjectId) =
match projectTable.TryGetValue(projectId) with
| true, ((_referencedProjects, options), _) -> Some options
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm concerned by this change. the whole point of TryGetOptionsForProject and projectTable is to maintain the canonical FSharpProjectOptions object for the project so it doesn't need to be recomputed - and FCS can use Stamp to tell if the project options of dependent projects have changed. For example, each time you make a new options object you should bump Stamp.

But with this change, the options stored in projectTable are no longer canonical and up-to-date - instead you have to go through this routine to get the latest options.

It would be better to update options entry in projectTable either here (on-demand) or at some earlier point when we know that the CommandLineOptions/sourcePaths/otherOptions results change

Copy link
Contributor

Choose a reason for hiding this comment

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

Note that failing to keep the projectTable canonical may have correctness of performance effects on incorrect or recomputation of project options.

@@ -411,13 +367,20 @@ type

let optionsAssociation = ConditionalWeakTable<IWorkspaceProjectContext, string[]>()

member private this.OnProjectAdded(projectId:ProjectId, _newSolution:Solution) = projectInfoManager.UpdateProjectInfoWithProjectId(projectId, "OnProjectAdded")
member private this.OnProjectAdded(projectId:ProjectId, _newSolution:Solution) = projectInfoManager.UpdateProjectInfoWithProjectId(projectId, "OnProjectAdded")
Copy link
Contributor

Choose a reason for hiding this comment

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

If _newSolution is unused then why not remove it?

Copy link
Member Author

Choose a reason for hiding this comment

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

I suspect that we will be using eventually. It's just not necessary right now.

| WorkspaceChangeKind.ProjectAdded -> this.OnProjectAdded(args.ProjectId, args.NewSolution)
| WorkspaceChangeKind.ProjectChanged -> this.OnProjectChanged(args.ProjectId, args.NewSolution)
| WorkspaceChangeKind.ProjectReloaded -> this.OnProjectReloaded(args.ProjectId, args.NewSolution)
// | WorkspaceChangeKind.ProjectRemoved -> this.OnProjectRemoved(args.ProjectId, args.NewSolution)
Copy link
Contributor

Choose a reason for hiding this comment

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

What's up with Removed? Please add a comment as to what needs to be done here

@@ -101,7 +109,75 @@ type private ProjectSiteOfSingleFile(sourceFile) =
override this.AssemblyReferences() = [||]

override x.ToString() = sprintf "ProjectSiteOfSingleFile(%s)" sourceFile

type CommandLineOptions (isEmpty:bool) =
Copy link
Contributor

Choose a reason for hiding this comment

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

Please add a /// comment explaining what this is. Always...


new () = CommandLineOptions(false)

member __.GetOptionsWithProjectId(projectId:ProjectId) =
Copy link
Contributor

Choose a reason for hiding this comment

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

Please add /// comments on all new members

type CommandLineOptions (isEmpty:bool) =

let commandLineOptions = new ConcurrentDictionary<ProjectId, string[]*string[]*string[]>()
static let emptyCommandLineOptions = lazy new CommandLineOptions(true)
Copy link
Contributor

Choose a reason for hiding this comment

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

There is no point in making such a trivial object allocation lazy - just remove the ``lazy`


static member Empty with get () = emptyCommandLineOptions.Value
Copy link
Contributor

Choose a reason for hiding this comment

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

Remove the with get()

member __.GetOptionsWithProjectId(projectId:ProjectId) =
match commandLineOptions.TryGetValue projectId with
| true, value -> value
| _ -> [||], [||], [||]
Copy link
Contributor

Choose a reason for hiding this comment

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

This should return a None on this branch

@KevinRansom
Copy link
Member Author

Hmm seems as if I have broken p2p references :-(

@KevinRansom
Copy link
Member Author

@dotnet-bot test Windows_NT Release_ci_part1 Build

@@ -207,8 +207,9 @@ type internal FSharpProjectOptionsManager
match hier with
| h when (h.IsCapabilityMatch("CPS")) ->
let project = workspace.CurrentSolution.GetProject(projectId)
let siteProvider = provideProjectSiteProvider(workspace, project, serviceProvider, Some projectOptionsTable)
this.UpdateProjectInfo(tryGetOrCreateProjectId, projectId, siteProvider.GetProjectSite(), userOpName)
if project <> null then
Copy link
Contributor

@cartermp cartermp Oct 5, 2017

Choose a reason for hiding this comment

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

is x = null or x <> null strictly less efficient than a pattern match or isNull/not isNull call? Not sure if my knowledge here is rusty or not

Copy link
Contributor

Choose a reason for hiding this comment

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

IIRC 'x = null' can throw NullReferenceException at runtime when x is null and the compiler thinks that it cannot be null.

Copy link
Member Author

@KevinRansom KevinRansom Oct 5, 2017

Choose a reason for hiding this comment

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

isNotNull x is probably the way to go.

Copy link
Member Author

@KevinRansom KevinRansom Oct 5, 2017

Choose a reason for hiding this comment

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

Copy link
Contributor

Choose a reason for hiding this comment

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

Because it changed fsharp.core surface area when I added it. And my changes where rolled back.

Copy link
Contributor

Choose a reason for hiding this comment

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

In other words: it was public for a week or so

Copy link
Contributor

Choose a reason for hiding this comment

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

See fsharp/fslang-suggestions#99 (comment)

... we have a design rule not to put "NotXYZ" predicates in the core library

Copy link
Member Author

Choose a reason for hiding this comment

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

@dsyme ahh well this doen't fall under that rule because it is:
isNotNull :-)

It is a decent api we should make it public for FSharp.Core 4.3

Copy link
Contributor

Choose a reason for hiding this comment

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

The design rule is clear both for F# and for .NET - we don't put negative "not" predicates in our libraries. It is a slippery slope and we should not go down it. Just use not (isNull x).

If that's not satisfactory we would be much better off putting effort into fsharp/fslang-suggestions#569 to eventually allow !isNull x

@KevinRansom
Copy link
Member Author

So this doesn't work unless the project has been pre-built for dotnet sdk projects I still need to figure that out.

@cartermp
Copy link
Contributor

cartermp commented Oct 6, 2017

This doesn't work for me if the libraries are pre-built either. This is on 15.5 Preview 1 bits. Should I be testing against something else?

@dotnet dotnet deleted a comment from forki Oct 10, 2017
| _ -> ()
| None -> ()
| None ->
Copy link
Contributor

Choose a reason for hiding this comment

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

This is dubious - your new code is only being hit when solutionService is None, which should never happen?

// not the intermediate output directory.
// so as a Giant kludge transform obj to bin
// ======================================================================
yield Some projectId, project.FilePath, outputPath.Replace(@"\obj\", @"\bin\"), siteProvider
Copy link
Member

Choose a reason for hiding this comment

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

Yeah, this won't work in general. Both of these paths can (and frequently are) changed by msbuild variables. In Roslyn for non-CPS projects, we get this from the hierarchy with this code. Not sure if that would work for CPS or not. (Tag @davkean)

Copy link
Member Author

Choose a reason for hiding this comment

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

I know it won't that's why the 'Hack!!!!!!' I think I am pretty sure I need the project System to have set this value. Or I should figure out why FCS needs it ... which is probably more of a winner here.

// project.OutputFilePath does not have a value at this point ...
// so calculate one by peeking at the command line options ... --out:
// ======================================================================
match projectOptionsTable with
Copy link
Member

Choose a reason for hiding this comment

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

I don't understand why this works. According to what @davkean was telling me yesterday, at the point where the OutputFilePath is still null, we shouldn't have any options yet, just the source files because it comes from evaluation only...

Copy link
Member Author

Choose a reason for hiding this comment

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

@kevinpi. Well the command line options from designtimebuild have been received at this point.

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.

6 participants