Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions src/absil/il.fs
Original file line number Diff line number Diff line change
Expand Up @@ -675,27 +675,33 @@ and [<RequireQualifiedAccess; StructuralEquality; StructuralComparison>]

member x.QualifiedNameWithNoShortPrimaryAssembly =
x.AddQualifiedNameExtensionWithNoShortPrimaryAssembly(x.BasicQualifiedName)

member x.TypeSpec =
match x with
| ILType.Boxed tr | ILType.Value tr -> tr
| _ -> invalidOp "not a nominal type"

member x.Boxity =
match x with
| ILType.Boxed _ -> AsObject
| ILType.Value _ -> AsValue
| _ -> invalidOp "not a nominal type"

member x.TypeRef =
match x with
| ILType.Boxed tspec | ILType.Value tspec -> tspec.TypeRef
| _ -> invalidOp "not a nominal type"

member x.IsNominal =
match x with
| ILType.Boxed _ | ILType.Value _ -> true
| _ -> false

member x.GenericArgs =
match x with
| ILType.Boxed tspec | ILType.Value tspec -> tspec.GenericArgs
| _ -> []

member x.IsTyvar =
match x with
| ILType.TypeVar _ -> true | _ -> false
Expand Down Expand Up @@ -843,9 +849,9 @@ type ILAttribute =

[<NoEquality; NoComparison; Sealed>]
type ILAttributes(f: unit -> ILAttribute[]) =
let mutable array = InlineDelayInit<_>(f)
member x.AsArray = array.Value
member x.AsList = x.AsArray |> Array.toList
let mutable array = InlineDelayInit<_>(f)
member x.AsArray = array.Value
member x.AsList = x.AsArray |> Array.toList

type ILCodeLabel = int

Expand Down
1 change: 1 addition & 0 deletions src/fsharp/CompileOps.fs
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,7 @@ let warningOn err level specificWarnOn =
// Some specific warnings are never on by default, i.e. unused variable warnings
match n with
| 1182 -> false // chkUnusedValue - off by default
| 3218 -> false // ArgumentsInSigAndImplMismatch - off by default
| 3180 -> false // abImplicitHeapAllocation - off by default
| _ -> level >= GetWarningLevel err

Expand Down
1 change: 1 addition & 0 deletions src/fsharp/FSComp.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1420,3 +1420,4 @@ notAFunctionButMaybeIndexerWithName,"This value is not a function and cannot be
notAFunctionButMaybeIndexer,"This expression is not a function and cannot be applied. Did you intend to access the indexer via expr.[index] instead?"
3217,notAFunctionButMaybeIndexerErrorCode,""
notAFunctionButMaybeDeclaration,"This value is not a function and cannot be applied. Did you forget to terminate a declaration?"
3218,ArgumentsInSigAndImplMismatch,"The argument names in the signature '%s' and implementation '%s' do not match. The argument name from the signature file will be used. This may cause problems when debugging or profiling."
12 changes: 6 additions & 6 deletions src/fsharp/FSharp.Core/prim-types.fs
Original file line number Diff line number Diff line change
Expand Up @@ -2781,21 +2781,21 @@ namespace Microsoft.FSharp.Core
inherit FSharpFunc<'T,('U -> 'V)>()
abstract Invoke : 'T * 'U -> 'V
override f.Invoke(t) = (fun u -> f.Invoke(t,u))
static member Adapt(f : 'T -> 'U -> 'V) =
match box f with
static member Adapt(func : 'T -> 'U -> 'V) =
match box func with
// Does it take two arguments without side effect?
| :? FSharpFunc<'T,'U,'V> as f -> f

| _ -> { new FSharpFunc<'T,'U,'V>() with
member x.Invoke(t,u) = (retype f : FSharpFunc<'T,FSharpFunc<'U,'V>>).Invoke(t).Invoke(u) }
member x.Invoke(t,u) = (retype func : FSharpFunc<'T,FSharpFunc<'U,'V>>).Invoke(t).Invoke(u) }

[<AbstractClass>]
type FSharpFunc<'T,'U,'V,'W>() =
inherit FSharpFunc<'T,('U -> 'V -> 'W)>()
abstract Invoke : 'T * 'U * 'V -> 'W
override f.Invoke(t) = (fun u v -> f.Invoke(t,u,v))
static member Adapt(f : 'T -> 'U -> 'V -> 'W) =
match box f with
static member Adapt(func : 'T -> 'U -> 'V -> 'W) =
match box func with
// Does it take three arguments without side effect?
| :? FSharpFunc<'T,'U,'V,'W> as f -> f

Expand All @@ -2805,7 +2805,7 @@ namespace Microsoft.FSharp.Core
member x.Invoke(t,u,v) = f.Invoke(t,u).Invoke(v) }

| _ -> { new FSharpFunc<'T,'U,'V,'W>() with
member x.Invoke(t,u,v) = (retype f : FSharpFunc<'T,('U -> 'V -> 'W)>).Invoke(t) u v }
member x.Invoke(t,u,v) = (retype func : FSharpFunc<'T,('U -> 'V -> 'W)>).Invoke(t) u v }

[<AbstractClass>]
type FSharpFunc<'T,'U,'V,'W,'X>() =
Expand Down
5 changes: 5 additions & 0 deletions src/fsharp/SignatureConformance.fs
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,11 @@ type Checker(g, amap, denv, remapInfo: SignatureRepackageInfo, checkingSig) =
let res =
(implArgInfos,sigArgInfos) ||> List.forall2 (List.forall2 (fun implArgInfo sigArgInfo ->
checkAttribs aenv implArgInfo.Attribs sigArgInfo.Attribs (fun attribs ->
match implArgInfo.Name, sigArgInfo.Name with
| Some iname, Some sname when sname.idText <> iname.idText ->
Copy link
Contributor

Choose a reason for hiding this comment

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

should the comparison be locale aware, or be StringCompare.Ordinal?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Everywhere else in signature conformance checking we just use default F# string equality i.e. System.String.Equals(string1,string2), e.g.

            if implTycon.LogicalName <> sigTycon.LogicalName then (errorR (Error (FSComp.SR.DefinitionsInSigAndImplNotCompatibleNamesDiffer(implTycon.TypeOrMeasureKind.ToString(),sigTycon.LogicalName,implTycon.LogicalName),m)); false) else
            if implTycon.CompiledName <> sigTycon.CompiledName then (errorR (Error (FSComp.SR.DefinitionsInSigAndImplNotCompatibleNamesDiffer(implTycon.TypeOrMeasureKind.ToString(),sigTycon.CompiledName,implTycon.CompiledName),m)); false) else

If we change it in one place we'd need to change it everywhere

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes ... but what is the right thing to do?

It may be that locale aware case sensitive is the right thing to do. It's not clear to me is all.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think we can't change this at this stage - all the name lookups in the compiler are based on exact string equality.

Also, part of the intent of using the signature names is to make sure that the .NET/IL/C#/debug and F# views of named arguments are the same. We don't know what equality check is used by visual studio when you mouse-hover over an identifier and it tries to look it up.

In any case, it's an orthogonal issue to this PR

warning(Error (FSComp.SR.ArgumentsInSigAndImplMismatch(sname.idText, iname.idText),iname.idRange))
| _ -> ()

implArgInfo.Name <- sigArgInfo.Name
implArgInfo.Attribs <- attribs))) &&

Expand Down
7 changes: 7 additions & 0 deletions tests/fsharp/tests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -2142,6 +2142,12 @@ module TypecheckTests =
[<Test>]
let ``type check neg99`` () = singleNegTest (testConfig "typecheck/sigs") "neg99"

[<Test>]
let ``type check neg100`` () =
let cfg = testConfig "typecheck/sigs"
let cfg = { cfg with fsc_flags = cfg.fsc_flags + " --warnon:3218" }
singleNegTest cfg "neg100"

[<Test>]
let ``type check neg_byref_1`` () = singleNegTest (testConfig "typecheck/sigs") "neg_byref_1"

Expand Down Expand Up @@ -2208,6 +2214,7 @@ module TypecheckTests =
[<Test>]
let ``type check neg_byref_23`` () = singleNegTest (testConfig "typecheck/sigs") "neg_byref_23"


module FscTests =
[<Test>]
let ``should be raised if AssemblyInformationalVersion has invalid version`` () =
Expand Down
18 changes: 18 additions & 0 deletions tests/fsharp/typecheck/sigs/neg100.bsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@

neg100.fs(9,12,9,16): typecheck error FS3218: The argument names in the signature 'xxxx' and implementation 'qqqq' do not match. The argument name from the signature file will be used. This may cause problems when debugging or profiling.

neg100.fs(8,12,8,16): typecheck error FS3218: The argument names in the signature 'xxx' and implementation 'qqqq' do not match. The argument name from the signature file will be used. This may cause problems when debugging or profiling.

neg100.fs(7,12,7,16): typecheck error FS3218: The argument names in the signature 'xx' and implementation 'qqqq' do not match. The argument name from the signature file will be used. This may cause problems when debugging or profiling.

neg100.fs(6,12,6,16): typecheck error FS3218: The argument names in the signature 'x' and implementation 'qqqq' do not match. The argument name from the signature file will be used. This may cause problems when debugging or profiling.

neg100.fs(15,17,15,22): typecheck error FS3218: The argument names in the signature 'xxxx' and implementation 'qqqq3' do not match. The argument name from the signature file will be used. This may cause problems when debugging or profiling.

neg100.fs(14,17,14,22): typecheck error FS3218: The argument names in the signature 'xxx' and implementation 'qqqq3' do not match. The argument name from the signature file will be used. This may cause problems when debugging or profiling.

neg100.fs(13,17,13,22): typecheck error FS3218: The argument names in the signature 'xx' and implementation 'qqqq3' do not match. The argument name from the signature file will be used. This may cause problems when debugging or profiling.

neg100.fs(12,17,12,22): typecheck error FS3218: The argument names in the signature 'x' and implementation 'qqqq3' do not match. The argument name from the signature file will be used. This may cause problems when debugging or profiling.

neg100.fs(11,9,11,14): typecheck error FS3218: The argument names in the signature 'aaa' and implementation 'qqqq2' do not match. The argument name from the signature file will be used. This may cause problems when debugging or profiling.
16 changes: 16 additions & 0 deletions tests/fsharp/typecheck/sigs/neg100.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@


module M

let ffff ok = ok + 3
let gggg1 (qqqq : int) = qqqq + 3
let gggg2 (qqqq : int) = qqqq + 3
let gggg3 (qqqq : int) = qqqq + 3
let gggg4 (qqqq : int) = qqqq + 3

type C( qqqq2: int) =
member __.M1 (qqqq3: int) = qqqq2 + qqqq3 |> ignore
member __.M2 (qqqq3: int) = qqqq2 + qqqq3 |> ignore
member __.M3 (qqqq3: int) = qqqq2 + qqqq3 |> ignore
member __.M4 (qqqq3: int) = qqqq2 + qqqq3 |> ignore

16 changes: 16 additions & 0 deletions tests/fsharp/typecheck/sigs/neg100.fsi
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@


module M

val ffff : int -> int
val gggg1 : x: int -> int
val gggg2 : xx: int -> int
val gggg3 : xxx: int -> int
val gggg4 : xxxx: int -> int

type C =
new : aaa : int -> C
member M1 : x:int -> unit
member M2 : xx:int -> unit
member M3 : xxx:int -> unit
member M4 : xxxx:int -> unit
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.

namespace rec Microsoft.VisualStudio.FSharp.Editor
namespace Microsoft.VisualStudio.FSharp.Editor

open System.Composition
open System.Collections.Immutable
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.

namespace rec Microsoft.VisualStudio.FSharp.Editor
namespace Microsoft.VisualStudio.FSharp.Editor

open System
open System.Composition
Expand Down
21 changes: 5 additions & 16 deletions vsintegration/src/FSharp.Editor/CodeFix/FixIndexerAccess.fs
Original file line number Diff line number Diff line change
@@ -1,34 +1,22 @@
// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.

namespace rec Microsoft.VisualStudio.FSharp.Editor
namespace Microsoft.VisualStudio.FSharp.Editor

open System
open System.Composition
open System.Collections.Immutable
open System.Threading
open System.Threading.Tasks

open Microsoft.CodeAnalysis
open Microsoft.CodeAnalysis.Text
open Microsoft.CodeAnalysis.CodeFixes
open Microsoft.CodeAnalysis.CodeActions
open SymbolHelpers

[<ExportCodeFixProvider(FSharpConstants.FSharpLanguageName, Name = "FixIndexerAccess"); Shared>]
type internal FSharpFixIndexerAccessCodeFixProvider() =
inherit CodeFixProvider()
let fixableDiagnosticIds = set ["FS3217"]

let createCodeFix (title: string, context: CodeFixContext, textChange: TextChange) =
CodeAction.Create(
title,
(fun (cancellationToken: CancellationToken) ->
async {
let! cancellationToken = Async.CancellationToken
let! sourceText = context.Document.GetTextAsync(cancellationToken) |> Async.AwaitTask
return context.Document.WithText(sourceText.WithChanges(textChange))
} |> RoslynHelpers.StartAsyncAsTask(cancellationToken)),
title)

override __.FixableDiagnosticIds = Seq.toImmutableArray fixableDiagnosticIds

override __.RegisterCodeFixesAsync context : Task =
Expand Down Expand Up @@ -60,9 +48,10 @@ type internal FSharpFixIndexerAccessCodeFixProvider() =
| _ -> context.Span,sourceText.GetSubText(context.Span).ToString()

let codefix =
createCodeFix(
createTextChangeCodeFix(
FSComp.SR.addIndexerDot(),
context,
TextChange(span, replacement.TrimEnd() + "."))
(fun () -> asyncMaybe.Return [| TextChange(span, replacement.TrimEnd() + ".") |]))

context.RegisterCodeFix(codefix, diagnostics))
} |> RoslynHelpers.StartAsyncUnitAsTask(context.CancellationToken)
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.

namespace rec Microsoft.VisualStudio.FSharp.Editor
namespace Microsoft.VisualStudio.FSharp.Editor

open System
open System.Composition
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.

namespace rec Microsoft.VisualStudio.FSharp.Editor
namespace Microsoft.VisualStudio.FSharp.Editor

open System
open System.Composition
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.

namespace rec Microsoft.VisualStudio.FSharp.Editor
namespace Microsoft.VisualStudio.FSharp.Editor

open System.Composition
open System.Threading.Tasks
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.

namespace rec Microsoft.VisualStudio.FSharp.Editor
namespace Microsoft.VisualStudio.FSharp.Editor

open System.Composition
open System.Threading
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.

namespace Microsoft.VisualStudio.FSharp.Editor

open System
open System.Collections.Immutable
open System.Composition
open System.Threading.Tasks

open Microsoft.CodeAnalysis
open Microsoft.CodeAnalysis.Text
open Microsoft.CodeAnalysis.CodeFixes

open Microsoft.FSharp.Compiler
open Microsoft.FSharp.Compiler.SourceCodeServices
open Microsoft.VisualStudio.FSharp.Editor.SymbolHelpers
open Microsoft.FSharp.Compiler.SourceCodeServices.Keywords

[<ExportCodeFixProvider(FSharpConstants.FSharpLanguageName, Name = "FSharpRenameParamToMatchSignature"); Shared>]
type internal FSharpRenameParamToMatchSignature
[<ImportingConstructor>]
(
checkerProvider: FSharpCheckerProvider,
projectInfoManager: FSharpProjectOptionsManager
) =

inherit CodeFixProvider()
static let userOpName = "RenameParamToMatchSignature"
let fixableDiagnosticIds = ["FS3218"]


override __.FixableDiagnosticIds = Seq.toImmutableArray fixableDiagnosticIds

override __.RegisterCodeFixesAsync context : Task =
asyncMaybe {
match context.Diagnostics |> Seq.filter (fun x -> fixableDiagnosticIds |> List.contains x.Id) |> Seq.toList with
| [diagnostic] ->
let message = diagnostic.GetMessage()
let parts = System.Text.RegularExpressions.Regex.Match(message, ".+'(.+)'.+'(.+)'.+")
if parts.Success then

let diagnostics = ImmutableArray.Create diagnostic
let suggestion = parts.Groups.[1].Value
let replacement = QuoteIdentifierIfNeeded suggestion
let computeChanges() =
asyncMaybe {
let document = context.Document
let! cancellationToken = Async.CancellationToken |> liftAsync
let! sourceText = document.GetTextAsync(cancellationToken)
let! symbolUses = getSymbolUsesOfSymbolAtLocationInDocument (document, context.Span.Start, projectInfoManager, checkerProvider.Checker, userOpName)
let changes =
[| for symbolUse in symbolUses do
match RoslynHelpers.TryFSharpRangeToTextSpan(sourceText, symbolUse.RangeAlternate) with
| None -> ()
| Some span ->
let textSpan = Tokenizer.fixupSpan(sourceText, span)
yield TextChange(textSpan, replacement) |]
return changes
}
let title = FSComp.SR.replaceWithSuggestion suggestion
let codefix = createTextChangeCodeFix(title, context, computeChanges)
context.RegisterCodeFix(codefix, diagnostics)
| _ -> ()
} |> Async.Ignore |> RoslynHelpers.StartAsyncUnitAsTask(context.CancellationToken)
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.

namespace rec Microsoft.VisualStudio.FSharp.Editor
namespace Microsoft.VisualStudio.FSharp.Editor

open System
open System.Composition
Expand Down
Loading