diff --git a/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md b/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md index 0b1b492c678..0c5e2501b9f 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md +++ b/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md @@ -37,6 +37,7 @@ * Add a switch to determine whether to generate a default implementation body for overridden method when completing. [PR #18341](https://github.com/dotnet/fsharp/pull/18341) * Use a more accurate range for CE Combine methods. [PR #18394](https://github.com/dotnet/fsharp/pull/18394) +* Support `CallerArgumentExpression` ([Language Suggestion #966](https://github.com/fsharp/fslang-suggestions/issues/966), [PR #17519](https://github.com/dotnet/fsharp/pull/17519)) ### Changed * FSharpCheckFileResults.ProjectContext.ProjectOptions will not be available when using the experimental Transparent Compiler feature. ([PR #18205](https://github.com/dotnet/fsharp/pull/18205)) diff --git a/docs/release-notes/.Language/preview.md b/docs/release-notes/.Language/preview.md index 905e086a163..f9e6ec0ccd2 100644 --- a/docs/release-notes/.Language/preview.md +++ b/docs/release-notes/.Language/preview.md @@ -5,6 +5,7 @@ * Added type conversions cache, only enabled for compiler runs ([PR#17668](https://github.com/dotnet/fsharp/pull/17668)) * Support ValueOption + Struct attribute as optional parameter for methods ([Language suggestion #1136](https://github.com/fsharp/fslang-suggestions/issues/1136), [PR #18098](https://github.com/dotnet/fsharp/pull/18098)) * Warn when `unit` is passed to an `obj`-typed argument ([PR #18330](https://github.com/dotnet/fsharp/pull/18330)) +* Support `CallerArgumentExpression` ([Language Suggestion #966](https://github.com/fsharp/fslang-suggestions/issues/966), [PR #17519](https://github.com/dotnet/fsharp/pull/17519)) ### Fixed diff --git a/src/Compiler/Checking/MethodCalls.fs b/src/Compiler/Checking/MethodCalls.fs index 19b91dcf0b1..7a60d2b61ae 100644 --- a/src/Compiler/Checking/MethodCalls.fs +++ b/src/Compiler/Checking/MethodCalls.fs @@ -1443,9 +1443,20 @@ let AdjustCallerArgExpr tcVal (g: TcGlobals) amap infoReader ad isOutArg calledA /// matter what order they are applied in as long as they are all composed together. let emptyPreBinder (e: Expr) = e +/// Try to pick the code text of an argument with the given parameter name from a list of assigned arguments. +let tryPickArgumentCodeText assignedArgs paramName = + assignedArgs + |> List.tryPick (fun { CalledArg=called; CallerArg=caller } -> + match called.NameOpt with + | Some x when x.idText = paramName -> + let code = FileContent.getCodeText caller.Range + if System.String.IsNullOrEmpty code then None + else Some code + | _ -> None) + /// Get the expression that must be inserted on the caller side for a CallerSide optional arg, /// i.e. one where there is no corresponding caller arg. -let rec GetDefaultExpressionForCallerSideOptionalArg tcFieldInit g (calledArg: CalledArg) currCalledArgTy currDfltVal eCallerMemberName mMethExpr = +let rec GetDefaultExpressionForCallerSideOptionalArg tcFieldInit g (calledArg: CalledArg) currCalledArgTy currDfltVal eCallerMemberName mMethExpr assignedArgs = match currDfltVal with | MissingValue -> // Add an I_nop if this is an initonly field to make sure we never recognize it as an lvalue. See mkExprAddrOfExpr. @@ -1462,7 +1473,7 @@ let rec GetDefaultExpressionForCallerSideOptionalArg tcFieldInit g (calledArg: C let ctorArgs = [Expr.Const (tcFieldInit mMethExpr fieldInit, mMethExpr, inst)] emptyPreBinder, Expr.Op (TOp.ILCall (false, false, true, true, NormalValUse, false, false, ctor, [inst], [], [currCalledArgTy]), [], ctorArgs, mMethExpr) | ByrefTy g inst -> - GetDefaultExpressionForCallerSideOptionalArg tcFieldInit g calledArg inst (PassByRef(inst, currDfltVal)) eCallerMemberName mMethExpr + GetDefaultExpressionForCallerSideOptionalArg tcFieldInit g calledArg inst (PassByRef(inst, currDfltVal)) eCallerMemberName mMethExpr assignedArgs | _ -> match calledArg.CallerInfo, eCallerMemberName with | CallerLineNumber, _ when typeEquiv g currCalledArgTy g.int_ty -> @@ -1472,6 +1483,14 @@ let rec GetDefaultExpressionForCallerSideOptionalArg tcFieldInit g (calledArg: C emptyPreBinder, Expr.Const (Const.String fileName, mMethExpr, currCalledArgTy) | CallerMemberName, Some callerName when (typeEquiv g currCalledArgTy g.string_ty) -> emptyPreBinder, Expr.Const (Const.String callerName, mMethExpr, currCalledArgTy) + + | CallerArgumentExpression param, _ when g.langVersion.SupportsFeature LanguageFeature.SupportCallerArgumentExpression && typeEquiv g currCalledArgTy g.string_ty -> + let stringConst = + match tryPickArgumentCodeText assignedArgs param with + | Some code -> Const.String code + | None -> tcFieldInit mMethExpr fieldInit + emptyPreBinder, Expr.Const (stringConst, mMethExpr, currCalledArgTy) + | _ -> emptyPreBinder, Expr.Const (tcFieldInit mMethExpr fieldInit, mMethExpr, currCalledArgTy) @@ -1495,13 +1514,13 @@ let rec GetDefaultExpressionForCallerSideOptionalArg tcFieldInit g (calledArg: C | PassByRef (ty, dfltVal2) -> let v, _ = mkCompGenLocal mMethExpr "defaultByrefArg" ty - let wrapper2, rhs = GetDefaultExpressionForCallerSideOptionalArg tcFieldInit g calledArg currCalledArgTy dfltVal2 eCallerMemberName mMethExpr + let wrapper2, rhs = GetDefaultExpressionForCallerSideOptionalArg tcFieldInit g calledArg currCalledArgTy dfltVal2 eCallerMemberName mMethExpr assignedArgs (wrapper2 >> mkCompGenLet mMethExpr v rhs), mkValAddr mMethExpr false (mkLocalValRef v) /// Get the expression that must be inserted on the caller side for a CalleeSide optional arg where /// no caller argument has been provided. Normally this is 'None', however CallerMemberName and friends /// can be used with 'CalleeSide' optional arguments -let GetDefaultExpressionForCalleeSideOptionalArg g (calledArg: CalledArg) eCallerMemberName (mMethExpr: range) = +let GetDefaultExpressionForCalleeSideOptionalArg g (calledArg: CalledArg) eCallerMemberName (mMethExpr: range) assignedArgs = let calledArgTy = calledArg.CalledArgumentType let calledNonOptTy = tryDestOptionalTy g calledArgTy @@ -1516,13 +1535,21 @@ let GetDefaultExpressionForCalleeSideOptionalArg g (calledArg: CalledArg) eCalle | CallerMemberName, Some(callerName) when typeEquiv g calledNonOptTy g.string_ty -> let memberNameExpr = Expr.Const (Const.String callerName, mMethExpr, calledNonOptTy) mkOptionalSome g calledArgTy calledNonOptTy memberNameExpr mMethExpr + + | CallerArgumentExpression param, _ when g.langVersion.SupportsFeature LanguageFeature.SupportCallerArgumentExpression && typeEquiv g calledNonOptTy g.string_ty -> + match tryPickArgumentCodeText assignedArgs param with + | Some code -> + let expr = Expr.Const(Const.String code, mMethExpr, calledNonOptTy) + mkOptionalSome g calledArgTy calledNonOptTy expr mMethExpr + | None -> mkOptionalNone g calledArgTy calledNonOptTy mMethExpr + | _ -> mkOptionalNone g calledArgTy calledNonOptTy mMethExpr /// Get the expression that must be inserted on the caller side for an optional arg where /// no caller argument has been provided. -let GetDefaultExpressionForOptionalArg tcFieldInit g (calledArg: CalledArg) eCallerMemberName mItem (mMethExpr: range) = +let GetDefaultExpressionForOptionalArg tcFieldInit g (calledArg: CalledArg) eCallerMemberName mItem (mMethExpr: range) assignedArgs = let calledArgTy = calledArg.CalledArgumentType let preBinder, expr = match calledArg.OptArgInfo with @@ -1530,10 +1557,10 @@ let GetDefaultExpressionForOptionalArg tcFieldInit g (calledArg: CalledArg) eCal error(InternalError("Unexpected NotOptional", mItem)) | CallerSide dfltVal -> - GetDefaultExpressionForCallerSideOptionalArg tcFieldInit g calledArg calledArgTy dfltVal eCallerMemberName mMethExpr + GetDefaultExpressionForCallerSideOptionalArg tcFieldInit g calledArg calledArgTy dfltVal eCallerMemberName mMethExpr assignedArgs | CalleeSide -> - emptyPreBinder, GetDefaultExpressionForCalleeSideOptionalArg g calledArg eCallerMemberName mMethExpr + emptyPreBinder, GetDefaultExpressionForCalleeSideOptionalArg g calledArg eCallerMemberName mMethExpr assignedArgs // Combine the variable allocators (if any) let callerArg = CallerArg(calledArgTy, mMethExpr, false, expr) @@ -1587,7 +1614,7 @@ let AdjustCallerArgForOptional tcVal tcFieldInit eCallerMemberName (infoReader: mkOptionToNullable g m (destOptionTy g callerArgTy) callerArgExpr else // CSharpMethod(?x=b) when 'b' has optional type and 'x' has non-nullable type --> CSharpMethod(x=Option.defaultValue DEFAULT v) - let _wrapper, defaultExpr = GetDefaultExpressionForCallerSideOptionalArg tcFieldInit g calledArg calledArgTy dfltVal eCallerMemberName m + let _wrapper, defaultExpr = GetDefaultExpressionForCallerSideOptionalArg tcFieldInit g calledArg calledArgTy dfltVal eCallerMemberName m [assignedArg] let ty = destOptionTy g callerArgTy mkOptionDefaultValue g m ty defaultExpr callerArgExpr else @@ -1651,7 +1678,7 @@ let AdjustCallerArgsForOptionals tcVal tcFieldInit eCallerMemberName (infoReader // i.e. there is no corresponding caller arg. let optArgs, optArgPreBinder = (emptyPreBinder, calledMeth.UnnamedCalledOptArgs) ||> List.mapFold (fun preBinder calledArg -> - let preBinder2, arg = GetDefaultExpressionForOptionalArg tcFieldInit g calledArg eCallerMemberName mItem mMethExpr + let preBinder2, arg = GetDefaultExpressionForOptionalArg tcFieldInit g calledArg eCallerMemberName mItem mMethExpr (assignedNamedArgs @ unnamedArgs) arg, (preBinder >> preBinder2)) let adjustedNormalUnnamedArgs = List.map (AdjustCallerArgForOptional tcVal tcFieldInit eCallerMemberName infoReader ad) unnamedArgs diff --git a/src/Compiler/Checking/PostInferenceChecks.fs b/src/Compiler/Checking/PostInferenceChecks.fs index 751112e3918..e0ab6c768a4 100644 --- a/src/Compiler/Checking/PostInferenceChecks.fs +++ b/src/Compiler/Checking/PostInferenceChecks.fs @@ -2391,8 +2391,10 @@ let CheckEntityDefn cenv env (tycon: Entity) = if numCurriedArgSets > 1 && others |> List.exists (fun minfo2 -> not (IsAbstractDefaultPair2 minfo minfo2)) then errorR(Error(FSComp.SR.chkDuplicateMethodCurried(nm, NicePrint.minimalStringOfType cenv.denv ty), m)) + let paramDatas = minfo.GetParamDatas(cenv.amap, m, minfo.FormalMethodInst) + if numCurriedArgSets > 1 && - (minfo.GetParamDatas(cenv.amap, m, minfo.FormalMethodInst) + (paramDatas |> List.existsSquared (fun (ParamData(isParamArrayArg, _isInArg, isOutArg, optArgInfo, callerInfo, _, reflArgInfo, ty)) -> isParamArrayArg || isOutArg || reflArgInfo.AutoQuote || optArgInfo.IsOptional || callerInfo <> NoCallerInfo || isByrefLikeTy g m ty)) then errorR(Error(FSComp.SR.chkCurriedMethodsCantHaveOutParams(), m)) @@ -2418,7 +2420,20 @@ let CheckEntityDefn cenv env (tycon: Entity) = | ValueSome innerTy -> errorR(Error(FSComp.SR.tcCallerInfoWrongType(callerInfo |> string, desiredTyName, NicePrint.minimalStringOfType cenv.denv innerTy), m)) | ValueNone -> errorR(Error(FSComp.SR.tcCallerInfoWrongType(callerInfo |> string, desiredTyName, NicePrint.minimalStringOfType cenv.denv ty), m)) - minfo.GetParamDatas(cenv.amap, m, minfo.FormalMethodInst) + let paramNames = HashSet() + paramDatas + |> List.iterSquared (fun (ParamData(_, _, _, _, _, nameOpt, _, _)) -> + nameOpt |> Option.iter (fun name -> paramNames.Add name.idText |> ignore)) + + let checkArgOfCallerArgumentExpression m arg (nameOpt: Ident option) = + match nameOpt with + | Some ident when arg = ident.idText -> + warning(Error(FSComp.SR.tcCallerArgumentExpressionSelfReferential(), m)) + | _ when not (paramNames.Contains arg) -> + warning(Error(FSComp.SR.tcCallerArgumentExpressionHasInvalidParameterName(), m)) + | _ -> () + + paramDatas |> List.iterSquared (fun (ParamData(_, isInArg, _, optArgInfo, callerInfo, nameOpt, _, ty)) -> ignore isInArg @@ -2436,6 +2451,14 @@ let CheckEntityDefn cenv env (tycon: Entity) = | CalleeSide, CallerLineNumber -> errorIfNotOptional g.int32_ty "int" m ty callerInfo | CallerSide _, (CallerFilePath | CallerMemberName) -> errorIfNotStringTy m ty callerInfo | CalleeSide, (CallerFilePath | CallerMemberName) -> errorIfNotOptional g.string_ty "string" m ty callerInfo + | CallerSide _, CallerArgumentExpression arg -> + checkLanguageFeatureAndRecover g.langVersion LanguageFeature.SupportCallerArgumentExpression m + errorIfNotStringTy m ty callerInfo + checkArgOfCallerArgumentExpression m arg nameOpt + | CalleeSide, CallerArgumentExpression arg -> + checkLanguageFeatureAndRecover g.langVersion LanguageFeature.SupportCallerArgumentExpression m + errorIfNotOptional g.string_ty "string" m ty callerInfo + checkArgOfCallerArgumentExpression m arg nameOpt ) for pinfo in immediateProps do diff --git a/src/Compiler/Checking/infos.fs b/src/Compiler/Checking/infos.fs index 81c777c3685..8a4e001c461 100644 --- a/src/Compiler/Checking/infos.fs +++ b/src/Compiler/Checking/infos.fs @@ -240,6 +240,7 @@ type CallerInfo = | CallerLineNumber | CallerMemberName | CallerFilePath + | CallerArgumentExpression of paramName: string override x.ToString() = sprintf "%+A" x @@ -317,20 +318,25 @@ let CrackParamAttribsInfo g (ty: TType, argInfo: ArgReprInfo) = let isCallerLineNumberArg = HasFSharpAttribute g g.attrib_CallerLineNumberAttribute argInfo.Attribs let isCallerFilePathArg = HasFSharpAttribute g g.attrib_CallerFilePathAttribute argInfo.Attribs let isCallerMemberNameArg = HasFSharpAttribute g g.attrib_CallerMemberNameAttribute argInfo.Attribs + let callerArgumentExpressionArg = + TryFindFSharpAttributeOpt g g.attrib_CallerArgumentExpressionAttribute argInfo.Attribs + |> Option.orElseWith (fun () -> TryFindFSharpAttributeByName "System.Runtime.CompilerServices.CallerArgumentExpressionAttribute" argInfo.Attribs) let callerInfo = - match isCallerLineNumberArg, isCallerFilePathArg, isCallerMemberNameArg with - | false, false, false -> NoCallerInfo - | true, false, false -> CallerLineNumber - | false, true, false -> CallerFilePath - | false, false, true -> CallerMemberName - | false, true, true -> + match isCallerLineNumberArg, isCallerFilePathArg, isCallerMemberNameArg, callerArgumentExpressionArg with + | false, false, false, None -> NoCallerInfo + | true, false, false, None -> CallerLineNumber + | false, true, false, None -> CallerFilePath + | false, false, true, None -> CallerMemberName + | false, false, false, Some(Attrib(_, _, (AttribStringArg x :: _), _, _, _, _)) -> + CallerArgumentExpression(x) + | false, true, true, _ -> match TryFindFSharpAttribute g g.attrib_CallerMemberNameAttribute argInfo.Attribs with | Some(Attrib(_, _, _, _, _, _, callerMemberNameAttributeRange)) -> warning(Error(FSComp.SR.CallerMemberNameIsOverridden(argInfo.Name.Value.idText), callerMemberNameAttributeRange)) CallerFilePath | _ -> failwith "Impossible" - | _, _, _ -> + | _, _, _, _ -> // if multiple caller info attributes are specified, pick the "wrong" one here // so that we get an error later match tryDestOptionTy g ty with @@ -1280,14 +1286,20 @@ type MethInfo = let isCallerLineNumberArg = TryFindILAttribute g.attrib_CallerLineNumberAttribute attrs let isCallerFilePathArg = TryFindILAttribute g.attrib_CallerFilePathAttribute attrs let isCallerMemberNameArg = TryFindILAttribute g.attrib_CallerMemberNameAttribute attrs + let isCallerArgumentExpressionArg = + g.attrib_CallerArgumentExpressionAttribute + |> Option.bind (fun (AttribInfo(tref, _)) -> TryDecodeILAttribute tref attrs) + |> Option.orElseWith (fun () -> TryDecodeILAttributeByName "System.Runtime.CompilerServices.CallerArgumentExpressionAttribute" attrs) let callerInfo = - match isCallerLineNumberArg, isCallerFilePathArg, isCallerMemberNameArg with - | false, false, false -> NoCallerInfo - | true, false, false -> CallerLineNumber - | false, true, false -> CallerFilePath - | false, false, true -> CallerMemberName - | _, _, _ -> + match isCallerLineNumberArg, isCallerFilePathArg, isCallerMemberNameArg, isCallerArgumentExpressionArg with + | false, false, false, None -> NoCallerInfo + | true, false, false, None -> CallerLineNumber + | false, true, false, None -> CallerFilePath + | false, false, true, None -> CallerMemberName + | false, false, false, Some ([ILAttribElem.String (Some name) ], _) -> CallerArgumentExpression(name) + | false, false, false, _ -> NoCallerInfo + | _, _, _, _ -> // if multiple caller info attributes are specified, pick the "wrong" one here // so that we get an error later if p.Type.TypeRef.FullName = "System.Int32" then CallerFilePath diff --git a/src/Compiler/Checking/infos.fsi b/src/Compiler/Checking/infos.fsi index e091834e271..c8a2cdc5e8e 100644 --- a/src/Compiler/Checking/infos.fsi +++ b/src/Compiler/Checking/infos.fsi @@ -101,6 +101,7 @@ type CallerInfo = | CallerLineNumber | CallerMemberName | CallerFilePath + | CallerArgumentExpression of paramName: string [] type ReflectedArgInfo = diff --git a/src/Compiler/Driver/CompilerConfig.fs b/src/Compiler/Driver/CompilerConfig.fs index cccbcb15810..35cd81ce100 100644 --- a/src/Compiler/Driver/CompilerConfig.fs +++ b/src/Compiler/Driver/CompilerConfig.fs @@ -1539,3 +1539,14 @@ type TcConfigProvider = TcConfigProvider(fun _ctok -> TcConfig.Create(tcConfigB, validate = false)) let GetFSharpCoreLibraryName () = getFSharpCoreLibraryName + +/// Read and store the source file content for the `CallerArgumentExpression` feature. +/// This should only be called in `fsc` or `fsi` processing. +let readAndStoreFileContents (tcConfig: TcConfig) (sourceFiles: #seq) = + if + tcConfig.langVersion.SupportsFeature LanguageFeature.SupportCallerArgumentExpression + && (tcConfig.compilationMode.IsOneOff || tcConfig.isInteractive) + then + for fileName in sourceFiles do + if FSharpImplFileSuffixes |> List.exists (FileSystemUtils.checkSuffix fileName) then + FileContent.update fileName (FileContent.FileCacheType.NotYetRead tcConfig.inputCodePage) diff --git a/src/Compiler/Driver/CompilerConfig.fsi b/src/Compiler/Driver/CompilerConfig.fsi index 0e6c25727f8..13d234840dc 100644 --- a/src/Compiler/Driver/CompilerConfig.fsi +++ b/src/Compiler/Driver/CompilerConfig.fsi @@ -961,3 +961,7 @@ val FSharpMLCompatFileSuffixes: string list /// Indicates whether experimental features should be enabled automatically val FSharpExperimentalFeaturesEnabledAutomatically: bool + +/// Read and store the source file content for the `CallerArgumentExpression` feature. +/// This should only be called in `fsc` or `fsi` processing. +val readAndStoreFileContents: tcConfig: TcConfig -> sourceFiles: #seq -> unit diff --git a/src/Compiler/Driver/fsc.fs b/src/Compiler/Driver/fsc.fs index 3518d9d4884..bb338e2dccf 100644 --- a/src/Compiler/Driver/fsc.fs +++ b/src/Compiler/Driver/fsc.fs @@ -671,6 +671,9 @@ let main1 // Build the initial type checking environment ReportTime tcConfig "Typecheck" + // Read the source file content for the `CallerArgumentExpression` feature + readAndStoreFileContents tcConfig sourceFiles + use unwindParsePhase = UseBuildPhase BuildPhase.TypeCheck let tcEnv0, openDecls0 = diff --git a/src/Compiler/FSComp.txt b/src/Compiler/FSComp.txt index 9bfa12ce963..63a53e7dad3 100644 --- a/src/Compiler/FSComp.txt +++ b/src/Compiler/FSComp.txt @@ -1798,3 +1798,6 @@ featureDontWarnOnUppercaseIdentifiersInBindingPatterns,"Don't warn on uppercase featureDeprecatePlacesWhereSeqCanBeOmitted,"Deprecate places where 'seq' can be omitted" featureSupportValueOptionsAsOptionalParameters,"Support ValueOption as valid type for optional member parameters" featureSupportWarnWhenUnitPassedToObjArg,"Warn when unit is passed to a member accepting `obj` argument, e.g. `Method(o:obj)` will warn if called via `Method()`." +featureSupportCallerArgumentExpression,"Support `CallerArgumentExpression`" +3875,tcCallerArgumentExpressionSelfReferential,"The CallerArgumentExpression on this parameter will have no effect because it's self-referential." +3875,tcCallerArgumentExpressionHasInvalidParameterName,"The CallerArgumentExpression on this parameter will have no effect because it's applied with an invalid parameter name." diff --git a/src/Compiler/Facilities/LanguageFeatures.fs b/src/Compiler/Facilities/LanguageFeatures.fs index 7a9a14b8602..131bd35a16b 100644 --- a/src/Compiler/Facilities/LanguageFeatures.fs +++ b/src/Compiler/Facilities/LanguageFeatures.fs @@ -99,6 +99,7 @@ type LanguageFeature = | DeprecatePlacesWhereSeqCanBeOmitted | SupportValueOptionsAsOptionalParameters | WarnWhenUnitPassedToObjArg + | SupportCallerArgumentExpression /// LanguageVersion management type LanguageVersion(versionText) = @@ -229,6 +230,7 @@ type LanguageVersion(versionText) = LanguageFeature.DeprecatePlacesWhereSeqCanBeOmitted, previewVersion LanguageFeature.SupportValueOptionsAsOptionalParameters, previewVersion LanguageFeature.WarnWhenUnitPassedToObjArg, previewVersion + LanguageFeature.SupportCallerArgumentExpression, previewVersion ] static let defaultLanguageVersion = LanguageVersion("default") @@ -391,6 +393,7 @@ type LanguageVersion(versionText) = | LanguageFeature.DeprecatePlacesWhereSeqCanBeOmitted -> FSComp.SR.featureDeprecatePlacesWhereSeqCanBeOmitted () | LanguageFeature.SupportValueOptionsAsOptionalParameters -> FSComp.SR.featureSupportValueOptionsAsOptionalParameters () | LanguageFeature.WarnWhenUnitPassedToObjArg -> FSComp.SR.featureSupportWarnWhenUnitPassedToObjArg () + | LanguageFeature.SupportCallerArgumentExpression -> FSComp.SR.featureSupportCallerArgumentExpression () /// Get a version string associated with the given feature. static member GetFeatureVersionString feature = diff --git a/src/Compiler/Facilities/LanguageFeatures.fsi b/src/Compiler/Facilities/LanguageFeatures.fsi index 410a8b193c9..027ba9f9a43 100644 --- a/src/Compiler/Facilities/LanguageFeatures.fsi +++ b/src/Compiler/Facilities/LanguageFeatures.fsi @@ -90,6 +90,7 @@ type LanguageFeature = | DeprecatePlacesWhereSeqCanBeOmitted | SupportValueOptionsAsOptionalParameters | WarnWhenUnitPassedToObjArg + | SupportCallerArgumentExpression /// LanguageVersion management type LanguageVersion = diff --git a/src/Compiler/Interactive/fsi.fs b/src/Compiler/Interactive/fsi.fs index 78d5cb94dcd..e266647aee7 100644 --- a/src/Compiler/Interactive/fsi.fs +++ b/src/Compiler/Interactive/fsi.fs @@ -807,6 +807,9 @@ type internal FsiValuePrinter(fsi: FsiEvaluationSessionHostConfig, outWriter: Te type internal FsiStdinSyphon(errorWriter: TextWriter) = let syphonText = StringBuilder() + /// Get the current syphon text + member _.SyphonText = syphonText.ToString() + /// Clears the syphon text member _.Reset() = syphonText.Clear() |> ignore @@ -2899,6 +2902,9 @@ type internal FsiDynamicCompiler let istate = fsiDynamicCompiler.ProcessDelayedReferences(ctok, istate) + // Read the source file content for the `CallerArgumentExpression` feature + readAndStoreFileContents tcConfig sourceFiles + fsiDynamicCompiler.EvalParsedSourceFiles(ctok, diagnosticsLogger, istate, inputs, m) member _.GetBoundValues istate = @@ -3511,7 +3517,11 @@ type FsiStdinLexerProvider |> Option.iter (fun t -> match t with | Null -> () - | NonNull t -> fsiStdinSyphon.Add(t + "\n")) + | NonNull t -> + fsiStdinSyphon.Add(t + "\n") + // Update the stdin file content for the `CallerArgumentExpression` feature + FileContent.clear () + FileContent.update stdinMockFileName (FileContent.FileCacheType.FromString fsiStdinSyphon.SyphonText)) match inputOption with | Some Null @@ -4208,6 +4218,9 @@ type FsiInteractionProcessor ProcessStepStatus status None (fun _ istate -> run istate) + // Read the source file content for the `CallerArgumentExpression` feature + readAndStoreFileContents tcConfig [ sourceFile ] + run istate) /// Load the source files, one by one. Called on the main thread. @@ -4285,6 +4298,11 @@ type FsiInteractionProcessor currState |> InteractiveCatch diagnosticsLogger (fun istate -> let expr = ParseInteraction tokenizer + + // Update the file content for the `CallerArgumentExpression` feature + FileContent.clear () + FileContent.update scriptFileName (FileContent.FileCacheType.FromString sourceText) + ExecuteParsedInteractionOnMainThread(ctok, diagnosticsLogger, expr, istate, cancellationToken)) |> commitResult @@ -4319,6 +4337,10 @@ type FsiInteractionProcessor SynExprSequentialTrivia.Zero ) + // Update the file content for the `CallerArgumentExpression` feature + FileContent.clear () + FileContent.update scriptFileName (FileContent.FileCacheType.FromString sourceText) + ExecuteParsedExpressionOnMainThread(ctok, diagnosticsLogger, exprWithSeq, istate)) |> commitResult diff --git a/src/Compiler/TypedTree/TcGlobals.fs b/src/Compiler/TypedTree/TcGlobals.fs index 93dd8905553..6947f8df265 100644 --- a/src/Compiler/TypedTree/TcGlobals.fs +++ b/src/Compiler/TypedTree/TcGlobals.fs @@ -1092,7 +1092,6 @@ type TcGlobals( // Adding an unnecessary "let" instead of inlining into a multi-line pipelined compute-once "member val" that is too complex for @dsyme let v_attribs_Unsupported = [ tryFindSysAttrib "System.Runtime.CompilerServices.ModuleInitializerAttribute" - tryFindSysAttrib "System.Runtime.CompilerServices.CallerArgumentExpressionAttribute" tryFindSysAttrib "System.Runtime.InteropServices.UnmanagedCallersOnlyAttribute" tryFindSysAttrib "System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute" tryFindSysAttrib "System.Diagnostics.CodeAnalysis.SetsRequiredMembersAttribute" @@ -1503,6 +1502,7 @@ type TcGlobals( member val attrib_ExtensionAttribute = findSysAttrib "System.Runtime.CompilerServices.ExtensionAttribute" member val attrib_CallerLineNumberAttribute = findSysAttrib "System.Runtime.CompilerServices.CallerLineNumberAttribute" member val attrib_CallerFilePathAttribute = findSysAttrib "System.Runtime.CompilerServices.CallerFilePathAttribute" + member val attrib_CallerArgumentExpressionAttribute = tryFindSysAttrib "System.Runtime.CompilerServices.CallerArgumentExpressionAttribute" member val attrib_CallerMemberNameAttribute = findSysAttrib "System.Runtime.CompilerServices.CallerMemberNameAttribute" member val attrib_SkipLocalsInitAttribute = findSysAttrib "System.Runtime.CompilerServices.SkipLocalsInitAttribute" member val attrib_DecimalConstantAttribute = findSysAttrib "System.Runtime.CompilerServices.DecimalConstantAttribute" diff --git a/src/Compiler/TypedTree/TcGlobals.fsi b/src/Compiler/TypedTree/TcGlobals.fsi index b8c3610ef91..59a8f8ed2e2 100644 --- a/src/Compiler/TypedTree/TcGlobals.fsi +++ b/src/Compiler/TypedTree/TcGlobals.fsi @@ -336,6 +336,8 @@ type internal TcGlobals = member attrib_CallerLineNumberAttribute: BuiltinAttribInfo + member attrib_CallerArgumentExpressionAttribute: BuiltinAttribInfo option + member attrib_CallerMemberNameAttribute: BuiltinAttribInfo member attrib_ClassAttribute: BuiltinAttribInfo diff --git a/src/Compiler/TypedTree/TypedTreeOps.fs b/src/Compiler/TypedTree/TypedTreeOps.fs index 4b41db72349..911530a890c 100644 --- a/src/Compiler/TypedTree/TypedTreeOps.fs +++ b/src/Compiler/TypedTree/TypedTreeOps.fs @@ -3513,12 +3513,25 @@ let HasILAttribute tref (attrs: ILAttributes) = let TryDecodeILAttribute tref (attrs: ILAttributes) = attrs.AsArray() |> Array.tryPick (fun x -> if isILAttrib tref x then Some(decodeILAttribData x) else None) +let TryDecodeILAttributeByName nm (attrs: ILAttributes) = + attrs.AsArray() |> Array.tryPick (fun x -> if isILAttribByName ([], nm) x then Some(decodeILAttribData x) else None) + // F# view of attributes (these get converted to AbsIL attributes in ilxgen) let IsMatchingFSharpAttribute g (AttribInfo(_, tcref)) (Attrib(tcref2, _, _, _, _, _, _)) = tyconRefEq g tcref tcref2 let HasFSharpAttribute g tref attrs = List.exists (IsMatchingFSharpAttribute g tref) attrs let TryFindFSharpAttribute g tref attrs = List.tryFind (IsMatchingFSharpAttribute g tref) attrs let TryFindFSharpAttributeOpt g tref attrs = match tref with None -> None | Some tref -> List.tryFind (IsMatchingFSharpAttribute g tref) attrs +let TryFindFSharpAttributeByName nm attrs = + let path, typeName = splitILTypeName nm + attrs + |> List.tryFind (fun (Attrib(tcref2, _, _, _, _, _, _)) -> + match tcref2.TryDeref with + | ValueNone -> false + | ValueSome x -> + x.CompilationPath.MangledPath = path && + x.CompiledName = typeName) + let HasFSharpAttributeOpt g trefOpt attrs = match trefOpt with Some tref -> List.exists (IsMatchingFSharpAttribute g tref) attrs | _ -> false let IsMatchingFSharpAttributeOpt g attrOpt (Attrib(tcref2, _, _, _, _, _, _)) = match attrOpt with Some (AttribInfo(_, tcref)) -> tyconRefEq g tcref tcref2 | _ -> false diff --git a/src/Compiler/TypedTree/TypedTreeOps.fsi b/src/Compiler/TypedTree/TypedTreeOps.fsi index 06200be47f7..c4e8c29cc82 100755 --- a/src/Compiler/TypedTree/TypedTreeOps.fsi +++ b/src/Compiler/TypedTree/TypedTreeOps.fsi @@ -2317,6 +2317,8 @@ val mkLdelem: TcGlobals -> range -> TType -> Expr -> Expr -> Expr val TryDecodeILAttribute: ILTypeRef -> ILAttributes -> (ILAttribElem list * ILAttributeNamedArg list) option +val TryDecodeILAttributeByName: nm: string -> ILAttributes -> (ILAttribElem list * ILAttributeNamedArg list) option + val IsILAttrib: BuiltinAttribInfo -> ILAttribute -> bool val TryFindILAttribute: BuiltinAttribInfo -> ILAttributes -> bool @@ -2331,6 +2333,8 @@ val HasFSharpAttribute: TcGlobals -> BuiltinAttribInfo -> Attribs -> bool val HasFSharpAttributeOpt: TcGlobals -> BuiltinAttribInfo option -> Attribs -> bool +val TryFindFSharpAttributeByName: nm: string -> Attribs -> Attrib option + val TryFindFSharpAttribute: TcGlobals -> BuiltinAttribInfo -> Attribs -> Attrib option val TryFindFSharpAttributeOpt: TcGlobals -> BuiltinAttribInfo option -> Attribs -> Attrib option diff --git a/src/Compiler/Utilities/range.fs b/src/Compiler/Utilities/range.fs index 5e13752df0b..10734d0a77a 100755 --- a/src/Compiler/Utilities/range.fs +++ b/src/Compiler/Utilities/range.fs @@ -581,3 +581,83 @@ module Range = | None -> mkRange file (mkPos 1 0) (mkPos 1 80) with _ -> mkRange file (mkPos 1 0) (mkPos 1 80) + +module internal FileContent = + [] + type FileCacheType = + | AlreadyRead of lines: string array + | NotYetRead of codePage: int option + + static member FromString(s: string) = AlreadyRead(s.Split '\n') + + let private fileContentDict = ConcurrentDictionary() + + let update (fileName: string) (fileContent: FileCacheType) = + fileContentDict.AddOrUpdate(fileName, (fun _ -> fileContent), (fun _ _ -> fileContent)) + |> ignore + + let clear () = fileContentDict.Clear() + + /// Get the substring of the given range. + let private substring (input: string array) (range: range) = + let startLine, startCol = range.StartLine, range.StartColumn + let endLine, endCol = range.EndLine, range.EndColumn + + if + (startCol < 0 || endCol < 0) + || startLine < 1 + || startLine > endLine + || startLine > input.Length + || (startLine = endLine + && (startCol > endCol || startCol >= input.[startLine - 1].Length)) + then + System.String.Empty + elif startLine = endLine then + let line = input.[startLine - 1] + let endCol = min (endCol - 1) (line.Length - 1) + let result = line.Substring(startCol, endCol - startCol + 1) + + if endCol = line.Length - 1 && line[endCol] = '\r' then + result + "\n" + else + result + else + let appendNewLineMark sb = + (sb: System.Text.StringBuilder).Append '\n' |> ignore + + let startCol = min startCol (input.[startLine - 1].Length - 1) + let result = System.Text.StringBuilder() + result.Append(input.[startLine - 1].Substring(startCol)) |> ignore + appendNewLineMark result + + let upperBound = min (endLine - 2) (input.Length - 1) + + for i in startLine..upperBound do + result.Append(input.[i]) |> ignore + appendNewLineMark result + + if endLine < input.Length then + let line = input.[endLine - 1] + let endCol = min endCol line.Length + result.Append(line.Substring(0, endCol)) |> ignore + + if endCol = line.Length - 1 && line[endCol] = '\r' then + appendNewLineMark result + + result.ToString() + + let getCodeText (m: range) = + let fileName = m.FileName + + match fileContentDict.TryGetValue fileName with + | true, FileCacheType.AlreadyRead lines -> substring lines m + | true, FileCacheType.NotYetRead codePage -> + try + use fileStream = FileSystem.OpenFileForReadShim fileName + use reader = fileStream.GetReader(codePage) + let lines = reader.ReadToEnd().Split('\n') + update fileName (FileCacheType.AlreadyRead lines) + substring lines m + with _ -> + String.Empty + | _ -> String.Empty diff --git a/src/Compiler/Utilities/range.fsi b/src/Compiler/Utilities/range.fsi index 90deb76d976..f51c40f92c3 100755 --- a/src/Compiler/Utilities/range.fsi +++ b/src/Compiler/Utilities/range.fsi @@ -267,4 +267,23 @@ module Line = val fromZ: Line0 -> int /// Convert a line number from one-based line counting (used internally in the F# compiler and in F# error messages) to zero-based line counting (used by Visual Studio) - val toZ: int -> Line0 + val toZ: int -> Line0 + +/// Store code file content. Used to implement `CallerArgumentExpression` +module internal FileContent = + [] + type FileCacheType = + | AlreadyRead of lines: string array + | NotYetRead of codePage: int option + + static member FromString: s: string -> FileCacheType + + /// Update the file content. Should be called before the code file/expression is typechecked. + val update: fileName: string -> fileContent: FileCacheType -> unit + + /// Clean up all the file contents. + /// May be called in `fsi` processing, to avoid holding the source files which were compiled. + val clear: unit -> unit + + /// Get the code text of the specific `range` + val getCodeText: range -> string diff --git a/src/Compiler/xlf/FSComp.txt.cs.xlf b/src/Compiler/xlf/FSComp.txt.cs.xlf index 7d64601c303..4bfdfcd169a 100644 --- a/src/Compiler/xlf/FSComp.txt.cs.xlf +++ b/src/Compiler/xlf/FSComp.txt.cs.xlf @@ -632,6 +632,11 @@ reprezentace struktury aktivních vzorů + + Support `CallerArgumentExpression` + Support `CallerArgumentExpression` + + Support ValueOption as valid type for optional member parameters Support ValueOption as valid type for optional member parameters @@ -1362,6 +1367,16 @@ Atributy nejde použít pro rozšíření typů. + + The CallerArgumentExpression on this parameter will have no effect because it's applied with an invalid parameter name. + The CallerArgumentExpression on this parameter will have no effect because it's applied with an invalid parameter name. + + + + The CallerArgumentExpression on this parameter will have no effect because it's self-referential. + The CallerArgumentExpression on this parameter will have no effect because it's self-referential. + + This copy-and-update record expression changes all fields of record type '{0}'. Consider using the record construction syntax instead. Tento výraz záznamu kopírování a aktualizace mění všechna pole typu záznamu '{0}'. Zvažte použití syntaxe konstrukce záznamu. diff --git a/src/Compiler/xlf/FSComp.txt.de.xlf b/src/Compiler/xlf/FSComp.txt.de.xlf index 67f4270377e..f17ffc16cf5 100644 --- a/src/Compiler/xlf/FSComp.txt.de.xlf +++ b/src/Compiler/xlf/FSComp.txt.de.xlf @@ -632,6 +632,11 @@ Strukturdarstellung für aktive Muster + + Support `CallerArgumentExpression` + Support `CallerArgumentExpression` + + Support ValueOption as valid type for optional member parameters Support ValueOption as valid type for optional member parameters @@ -1362,6 +1367,16 @@ Attribute können nicht auf Typerweiterungen angewendet werden. + + The CallerArgumentExpression on this parameter will have no effect because it's applied with an invalid parameter name. + The CallerArgumentExpression on this parameter will have no effect because it's applied with an invalid parameter name. + + + + The CallerArgumentExpression on this parameter will have no effect because it's self-referential. + The CallerArgumentExpression on this parameter will have no effect because it's self-referential. + + This copy-and-update record expression changes all fields of record type '{0}'. Consider using the record construction syntax instead. Dieser Ausdruck zum Kopieren und Aktualisieren von Datensätzen ändert alle Felder des Datensatztyps "{0}". Erwägen Sie stattdessen die Verwendung der Datensatzerstellungssyntax. diff --git a/src/Compiler/xlf/FSComp.txt.es.xlf b/src/Compiler/xlf/FSComp.txt.es.xlf index 9478e3d2c55..481e70bcb61 100644 --- a/src/Compiler/xlf/FSComp.txt.es.xlf +++ b/src/Compiler/xlf/FSComp.txt.es.xlf @@ -632,6 +632,11 @@ representación de struct para modelos activos + + Support `CallerArgumentExpression` + Support `CallerArgumentExpression` + + Support ValueOption as valid type for optional member parameters Support ValueOption as valid type for optional member parameters @@ -1362,6 +1367,16 @@ Los atributos no se pueden aplicar a las extensiones de tipo. + + The CallerArgumentExpression on this parameter will have no effect because it's applied with an invalid parameter name. + The CallerArgumentExpression on this parameter will have no effect because it's applied with an invalid parameter name. + + + + The CallerArgumentExpression on this parameter will have no effect because it's self-referential. + The CallerArgumentExpression on this parameter will have no effect because it's self-referential. + + This copy-and-update record expression changes all fields of record type '{0}'. Consider using the record construction syntax instead. Esta expresión de copia y actualización de registros cambia todos los campos de tipo de registro "{0}". Es preferible utilizar la sintaxis de construcción de registros. diff --git a/src/Compiler/xlf/FSComp.txt.fr.xlf b/src/Compiler/xlf/FSComp.txt.fr.xlf index 57fade5d250..dc09b017ef6 100644 --- a/src/Compiler/xlf/FSComp.txt.fr.xlf +++ b/src/Compiler/xlf/FSComp.txt.fr.xlf @@ -632,6 +632,11 @@ représentation de structure pour les modèles actifs + + Support `CallerArgumentExpression` + Support `CallerArgumentExpression` + + Support ValueOption as valid type for optional member parameters Support ValueOption as valid type for optional member parameters @@ -1362,6 +1367,16 @@ Impossible d'appliquer des attributs aux extensions de type. + + The CallerArgumentExpression on this parameter will have no effect because it's applied with an invalid parameter name. + The CallerArgumentExpression on this parameter will have no effect because it's applied with an invalid parameter name. + + + + The CallerArgumentExpression on this parameter will have no effect because it's self-referential. + The CallerArgumentExpression on this parameter will have no effect because it's self-referential. + + This copy-and-update record expression changes all fields of record type '{0}'. Consider using the record construction syntax instead. Cette expression d'enregistrement de copie et de mise à jour modifie tous les champs du type d'enregistrement '{0}'. Envisagez d'utiliser la syntaxe de construction d'enregistrement à la place. diff --git a/src/Compiler/xlf/FSComp.txt.it.xlf b/src/Compiler/xlf/FSComp.txt.it.xlf index 14d670e8455..9871c03dd56 100644 --- a/src/Compiler/xlf/FSComp.txt.it.xlf +++ b/src/Compiler/xlf/FSComp.txt.it.xlf @@ -632,6 +632,11 @@ rappresentazione struct per criteri attivi + + Support `CallerArgumentExpression` + Support `CallerArgumentExpression` + + Support ValueOption as valid type for optional member parameters Support ValueOption as valid type for optional member parameters @@ -1362,6 +1367,16 @@ Gli attributi non possono essere applicati a estensioni di tipo. + + The CallerArgumentExpression on this parameter will have no effect because it's applied with an invalid parameter name. + The CallerArgumentExpression on this parameter will have no effect because it's applied with an invalid parameter name. + + + + The CallerArgumentExpression on this parameter will have no effect because it's self-referential. + The CallerArgumentExpression on this parameter will have no effect because it's self-referential. + + This copy-and-update record expression changes all fields of record type '{0}'. Consider using the record construction syntax instead. Questa espressione di record di copia e aggiornamento modifica tutti i campi del tipo di record '{0}'. Provare a usare la sintassi di costruzione dei record. diff --git a/src/Compiler/xlf/FSComp.txt.ja.xlf b/src/Compiler/xlf/FSComp.txt.ja.xlf index 78acb0fd944..fceebe13b2c 100644 --- a/src/Compiler/xlf/FSComp.txt.ja.xlf +++ b/src/Compiler/xlf/FSComp.txt.ja.xlf @@ -632,6 +632,11 @@ アクティブなパターンの構造体表現 + + Support `CallerArgumentExpression` + Support `CallerArgumentExpression` + + Support ValueOption as valid type for optional member parameters Support ValueOption as valid type for optional member parameters @@ -1362,6 +1367,16 @@ 属性を型拡張に適用することはできません。 + + The CallerArgumentExpression on this parameter will have no effect because it's applied with an invalid parameter name. + The CallerArgumentExpression on this parameter will have no effect because it's applied with an invalid parameter name. + + + + The CallerArgumentExpression on this parameter will have no effect because it's self-referential. + The CallerArgumentExpression on this parameter will have no effect because it's self-referential. + + This copy-and-update record expression changes all fields of record type '{0}'. Consider using the record construction syntax instead. この copy-and-update レコード式は、レコードの種類が '{0}' であるすべてのフィールドを変更します。代わりにレコード構築構文を使用することを検討してください。 diff --git a/src/Compiler/xlf/FSComp.txt.ko.xlf b/src/Compiler/xlf/FSComp.txt.ko.xlf index 604ac431e4a..0d063580dbc 100644 --- a/src/Compiler/xlf/FSComp.txt.ko.xlf +++ b/src/Compiler/xlf/FSComp.txt.ko.xlf @@ -632,6 +632,11 @@ 활성 패턴에 대한 구조체 표현 + + Support `CallerArgumentExpression` + Support `CallerArgumentExpression` + + Support ValueOption as valid type for optional member parameters Support ValueOption as valid type for optional member parameters @@ -1362,6 +1367,16 @@ 형식 확장에 특성을 적용할 수 없습니다. + + The CallerArgumentExpression on this parameter will have no effect because it's applied with an invalid parameter name. + The CallerArgumentExpression on this parameter will have no effect because it's applied with an invalid parameter name. + + + + The CallerArgumentExpression on this parameter will have no effect because it's self-referential. + The CallerArgumentExpression on this parameter will have no effect because it's self-referential. + + This copy-and-update record expression changes all fields of record type '{0}'. Consider using the record construction syntax instead. 이 레코드 복사 및 업데이트 식은 '{0}' 레코드 형식의 모든 필드를 변경합니다. 레코드 생성 구문을 대신 사용하는 것이 좋습니다. diff --git a/src/Compiler/xlf/FSComp.txt.pl.xlf b/src/Compiler/xlf/FSComp.txt.pl.xlf index fdee3d82f7d..d74c66459f0 100644 --- a/src/Compiler/xlf/FSComp.txt.pl.xlf +++ b/src/Compiler/xlf/FSComp.txt.pl.xlf @@ -632,6 +632,11 @@ reprezentacja struktury aktywnych wzorców + + Support `CallerArgumentExpression` + Support `CallerArgumentExpression` + + Support ValueOption as valid type for optional member parameters Support ValueOption as valid type for optional member parameters @@ -1362,6 +1367,16 @@ Atrybutów nie można stosować do rozszerzeń typu. + + The CallerArgumentExpression on this parameter will have no effect because it's applied with an invalid parameter name. + The CallerArgumentExpression on this parameter will have no effect because it's applied with an invalid parameter name. + + + + The CallerArgumentExpression on this parameter will have no effect because it's self-referential. + The CallerArgumentExpression on this parameter will have no effect because it's self-referential. + + This copy-and-update record expression changes all fields of record type '{0}'. Consider using the record construction syntax instead. To wyrażenie rekordu kopiowania i aktualizacji zmienia wszystkie pola typu rekordu „{0}”. Zamiast tego rozważ użycie składni konstrukcji rekordu. diff --git a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf index 2f86c57d960..88ee21f19d3 100644 --- a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf +++ b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf @@ -632,6 +632,11 @@ representação estrutural para padrões ativos + + Support `CallerArgumentExpression` + Support `CallerArgumentExpression` + + Support ValueOption as valid type for optional member parameters Support ValueOption as valid type for optional member parameters @@ -1362,6 +1367,16 @@ Os atributos não podem ser aplicados às extensões de tipo. + + The CallerArgumentExpression on this parameter will have no effect because it's applied with an invalid parameter name. + The CallerArgumentExpression on this parameter will have no effect because it's applied with an invalid parameter name. + + + + The CallerArgumentExpression on this parameter will have no effect because it's self-referential. + The CallerArgumentExpression on this parameter will have no effect because it's self-referential. + + This copy-and-update record expression changes all fields of record type '{0}'. Consider using the record construction syntax instead. Essa expressão de registro copiar e atualizar altera todos os campos do tipo de registro '{0}'. Considere usar a sintaxe de construção de registro em vez disso. diff --git a/src/Compiler/xlf/FSComp.txt.ru.xlf b/src/Compiler/xlf/FSComp.txt.ru.xlf index fefd5255a0b..0826b26c6c1 100644 --- a/src/Compiler/xlf/FSComp.txt.ru.xlf +++ b/src/Compiler/xlf/FSComp.txt.ru.xlf @@ -632,6 +632,11 @@ представление структуры для активных шаблонов + + Support `CallerArgumentExpression` + Support `CallerArgumentExpression` + + Support ValueOption as valid type for optional member parameters Support ValueOption as valid type for optional member parameters @@ -1362,6 +1367,16 @@ Атрибуты не могут быть применены к расширениям типа. + + The CallerArgumentExpression on this parameter will have no effect because it's applied with an invalid parameter name. + The CallerArgumentExpression on this parameter will have no effect because it's applied with an invalid parameter name. + + + + The CallerArgumentExpression on this parameter will have no effect because it's self-referential. + The CallerArgumentExpression on this parameter will have no effect because it's self-referential. + + This copy-and-update record expression changes all fields of record type '{0}'. Consider using the record construction syntax instead. Это выражение записи копирования и обновления изменяет все поля типа записи "{0}". Вместо этого можно использовать синтаксис конструкции записи. diff --git a/src/Compiler/xlf/FSComp.txt.tr.xlf b/src/Compiler/xlf/FSComp.txt.tr.xlf index 5325f0ab09f..6ce660c6191 100644 --- a/src/Compiler/xlf/FSComp.txt.tr.xlf +++ b/src/Compiler/xlf/FSComp.txt.tr.xlf @@ -632,6 +632,11 @@ etkin desenler için yapı gösterimi + + Support `CallerArgumentExpression` + Support `CallerArgumentExpression` + + Support ValueOption as valid type for optional member parameters Support ValueOption as valid type for optional member parameters @@ -1362,6 +1367,16 @@ Öznitelikler tür uzantılarına uygulanamaz. + + The CallerArgumentExpression on this parameter will have no effect because it's applied with an invalid parameter name. + The CallerArgumentExpression on this parameter will have no effect because it's applied with an invalid parameter name. + + + + The CallerArgumentExpression on this parameter will have no effect because it's self-referential. + The CallerArgumentExpression on this parameter will have no effect because it's self-referential. + + This copy-and-update record expression changes all fields of record type '{0}'. Consider using the record construction syntax instead. Bu kopyalama ve güncelleştirme kayıt ifadesi, '{0}' kayıt türündeki tüm alanları değiştirir. Bunun yerine kayıt oluşturma söz dizimini kullanmayı deneyin. diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf index 2e8b957d810..9c6d632af32 100644 --- a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf +++ b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf @@ -632,6 +632,11 @@ 活动模式的结构表示形式 + + Support `CallerArgumentExpression` + Support `CallerArgumentExpression` + + Support ValueOption as valid type for optional member parameters Support ValueOption as valid type for optional member parameters @@ -1362,6 +1367,16 @@ 属性不可应用于类型扩展。 + + The CallerArgumentExpression on this parameter will have no effect because it's applied with an invalid parameter name. + The CallerArgumentExpression on this parameter will have no effect because it's applied with an invalid parameter name. + + + + The CallerArgumentExpression on this parameter will have no effect because it's self-referential. + The CallerArgumentExpression on this parameter will have no effect because it's self-referential. + + This copy-and-update record expression changes all fields of record type '{0}'. Consider using the record construction syntax instead. 此复制和更新记录表达式更改记录类型“{0}”的所有字段。请考虑改用记录构造语法。 diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf index f0924b3d30f..68d7523eee5 100644 --- a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf +++ b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf @@ -632,6 +632,11 @@ 現用模式的結構表示法 + + Support `CallerArgumentExpression` + Support `CallerArgumentExpression` + + Support ValueOption as valid type for optional member parameters Support ValueOption as valid type for optional member parameters @@ -1362,6 +1367,16 @@ 屬性無法套用到類型延伸模組。 + + The CallerArgumentExpression on this parameter will have no effect because it's applied with an invalid parameter name. + The CallerArgumentExpression on this parameter will have no effect because it's applied with an invalid parameter name. + + + + The CallerArgumentExpression on this parameter will have no effect because it's self-referential. + The CallerArgumentExpression on this parameter will have no effect because it's self-referential. + + This copy-and-update record expression changes all fields of record type '{0}'. Consider using the record construction syntax instead. 此複製和更新記錄運算式將變更記錄類型為 '{0}' 的所有欄位。請考慮改用記錄建構語法。 diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/CallerArgumentExpression/CallerArgumentExpression.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/CallerArgumentExpression/CallerArgumentExpression.fs new file mode 100644 index 00000000000..81dec3701fa --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/CallerArgumentExpression/CallerArgumentExpression.fs @@ -0,0 +1,384 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. + +namespace Conformance.BasicGrammarElements + +open Xunit +open FSharp.Test.Compiler +open FSharp.Test + +module CustomAttributes_CallerArgumentExpression = + + [] + let ``Can consume CallerArgumentExpression in BCL methods`` () = + let path = __SOURCE_DIRECTORY__ ++ "test script.fsx" + FsFromPath path + |> withLangVersionPreview + |> asExe + |> compileAndRun + |> shouldSucceed + |> ignore + + [] + let ``Can define methods using CallerArgumentExpression with C#-style optional arguments`` () = + FSharp """let assertEqual a b = if a <> b then failwithf "not equal: %A and %A" a b +open System.Runtime.CompilerServices +open System.Runtime.InteropServices +type A() = + static member aa ( + a, + []b: string, + []c: int, + []e: string) = + a,b,c,e + +let stringABC = "abc" +assertEqual (A.aa(stringABC)) ("abc", ".cctor", 13, "stringABC") +assertEqual (A.aa(a = stringABC)) ("abc", ".cctor", 14, "stringABC") + """ + |> withLangVersionPreview + |> asExe + |> compileAndRun + |> shouldSucceed + |> ignore + + [] + let ``Can define methods using CallerArgumentExpression with F#-style optional arguments`` () = + FSharp """let assertEqual a b = if a <> b then failwithf "not equal: %A and %A" a b +open System.Runtime.CompilerServices +open System.Runtime.InteropServices +type A() = + static member aa ( + a, + [] ?b: string, + [] ?c: int, + [] ?e: string) = + let b = defaultArg b "no value" + let c = defaultArg c 0 + let e = defaultArg e "no value" + a,b,c,e + +let stringABC = "abc" +assertEqual (A.aa(stringABC)) ("abc", ".cctor", 16, "stringABC") +assertEqual (A.aa(a = stringABC)) ("abc", ".cctor", 17, "stringABC") + """ + |> withLangVersionPreview + |> asExe + |> compileAndRun + |> shouldSucceed + |> ignore + + [] + let ``Can define in F# - with #line`` () = + FSharp """let assertEqual a b = if a <> b then failwithf "not equal: %A and %A" a b +open System.Runtime.CompilerServices +open System.Runtime.InteropServices + +let path = System.IO.Path.Combine(__SOURCE_DIRECTORY__, "test.fs") + +# 1 "test.fs" +type A() = + static member aa ( + a, + []b: string, + []c: int, + []d: string, + []e: string) = + a,b,c,d,e + + static member B (``ab c``, []?n) = + defaultArg n "no value" + +let stringABC = "abc" +assertEqual (A.aa(stringABC)) ("abc", ".cctor", 11, path, "stringABC") +# 1 "test.fs" +assertEqual (A.aa(stringABC : string)) ("abc", ".cctor", 1, path, "stringABC : string") +# 1 "test.fs" +assertEqual (A.aa(a = (stringABC : string))) ("abc", ".cctor", 1, path, "(stringABC : string)") + + +A.B("abc" +#line 1 +: string) +|> assertEqual "\"abc\" +#line 1 +: string" + + +A.B((+) 1 +#line 1 + 123) +|> assertEqual "(+) 1 +#line 1 + 123" + + +A.B(#line 1 + (+) 1 + 123) +|> assertEqual "(+) 1 + 123" + """ + |> withLangVersionPreview + |> asExe + |> compileAndRun + |> shouldSucceed + |> ignore + + [] + let ``Can define methods using CallerArgumentExpression receiving special parameter names`` () = + FSharp """let assertEqual a b = if a <> b then failwithf "not equal: %A and %A" a b +open System.Runtime.CompilerServices + +type A() = + static member B (``ab c``, []?n) = + defaultArg n "no value" + +assertEqual (A.B("abc")) "\"abc\"" + """ + |> withLangVersionPreview + |> asExe + |> compileAndRun + |> shouldSucceed + |> ignore + + [] + let ``test Warns when cannot find the referenced parameter or self-referential`` () = + FSharp """let assertEqual a b = if a <> b then failwithf "not equal: %A and %A" a b +open System.Runtime.CompilerServices + +type A() = + static member A (``ab c``, []?n) = + defaultArg n "no value" + static member B (``ab c``, [] ?n) = + defaultArg n "no value" + """ + |> withLangVersionPreview + |> typecheck + |> shouldFail + |> withDiagnostics [ + (Warning 3875,Line 5, Col 65, Line 5, Col 66, "The CallerArgumentExpression on this parameter will have no effect because it's applied with an invalid parameter name.") + (Warning 3875,Line 7, Col 65 , Line 7, Col 66, "The CallerArgumentExpression on this parameter will have no effect because it's self-referential.") + ] + + [] + let ``test Errors`` () = + FSharp """let assertEqual a b = if a <> b then failwithf "not equal: %A and %A" a b +open System.Runtime.CompilerServices +open System.Runtime.InteropServices + +type A() = + static member A (``ab c``, [] n) = + defaultArg n "no value" + static member B (``ab c``, []?n) = + defaultArg n 123 + static member C (``ab c``, [] n: int) = + n + """ + |> withLangVersionPreview + |> typecheck + |> shouldFail + |> withDiagnostics [ + (Error 1247,Line 6, Col 66, Line 6, Col 67, "'CallerArgumentExpression \"ab c\"' can only be applied to optional arguments") + (Error 1246,Line 8, Col 66, Line 8, Col 67, "'CallerArgumentExpression \"ab c\"' must be applied to an argument of type 'string', but has been applied to an argument of type 'int'") + (Error 1246,Line 10, Col 101, Line 10, Col 102, "'CallerArgumentExpression \"ab c\"' must be applied to an argument of type 'string', but has been applied to an argument of type 'int'") + ] + + [] + let ``User can define the CallerArgumentExpression`` () = + FSharp """namespace System.Runtime.CompilerServices + +open System + +[] +type CallerArgumentExpressionAttribute(parameterName: string) = + inherit Attribute() + + member val ParameterName = parameterName + +namespace global +module A = + let assertEqual a b = if a <> b then failwithf "not equal: %A and %A" a b + open System.Runtime.CompilerServices + + type A() = + static member B (``ab c``, []?n) = + defaultArg n "no value" + + A.B "abc" |> assertEqual "\"abc\"" + A.B ("abc": string) |> assertEqual "\"abc\": string" + A.B ("abc": (* comments *) string) |> assertEqual "\"abc\": (* comments *) string" +""" + |> withLangVersionPreview + |> asExe + |> compileAndRun + |> shouldSucceed + |> ignore + + [] + let ``Can use with Computation Expression`` = + FSharp """let assertEqual a b = if a <> b then failwithf "not equal: %A and %A" a b +open System.Runtime.CompilerServices +open System.Runtime.InteropServices + +type Builder() = + member self.Bind( + x, f, + [] ?exp : string, + [] ?exp2 : string) = + (f x, $"f={exp2.Value}, x={exp.Value}") + + member self.Return(x, [] ?exp : string) = + (x, $"x={exp.Value}") + +let b = Builder() +b { do! () } |> assertEqual (((), "x=do!"), "f=do!, x=()") +b { let! a = 123 in return a } |> assertEqual ((123, "x=a"), "f=return a, x=123") + +b { + let! a = 123 + let! b = 456 + return a + b +} |> assertEqual + (((579, "x=a + b"), "f=return a + b, x=456"), + "f=let! b = 456 + return a + b, x=123") +""" + |> withLangVersionPreview + |> asExe + |> compileAndRun + |> shouldSucceed + |> ignore + + + [] + let ``Can use with Delegate and Quotation`` = + FSharp """let assertEqual a b = if a <> b then failwithf "not equal: %A and %A" a b +open System.Runtime.CompilerServices +open System.Runtime.InteropServices + +type A = + delegate of + a: int * + [] ?expr: string * + [] expr2: string + -> string * string option +let a = A (fun a expr expr2 -> expr2, expr) +a.Invoke(123 - 7) |> assertEqual ("123 - 7", Some "123 - 7") + +open Microsoft.FSharp.Quotations.Patterns +match <@ a.Invoke(123 - 7) @> with +| Call(_, _, [_; Value (:? (string * string option) as value, _)]) -> assertEqual ("123 - 7", Some "123 - 7") value +| _ -> failwith "fail" +""" + |> withLangVersionPreview + |> asExe + |> compileAndRun + |> shouldSucceed + |> ignore + + [] + let ``Can use with Interface and Object Expression`` = + FSharp """let assertEqual a b = if a <> b then failwithf "not equal: %A and %A" a b +open System.Runtime.CompilerServices +open System.Runtime.InteropServices + +type Interface1 = + abstract member M: + a: int * + [] ?expr: string * + [] expr2: string + -> string * string option + +{new Interface1 with + member this.M(a, expr, expr2) = expr2, expr}.M(123 - 7) |> assertEqual ("123 - 7", Some "123 - 7") +""" + |> withLangVersionPreview + |> asExe + |> compileAndRun + |> shouldSucceed + |> ignore + + (* ------------ C# Interop tests ------------- *) + [] + let ``C# can consume methods using CallerArgumentExpression receiving special parameter names`` () = + let fs = + FSharp """module Lib +let assertEqual a b = if a <> b then failwithf "not equal: %A and %A" a b +open System.Runtime.CompilerServices +open System.Runtime.InteropServices + +type A() = + static member B (``ab c``, []n: string) = + n + """ + |> withLangVersionPreview + + CSharp """Lib.assertEqual(Lib.A.B("abc"), "\"abc\"");""" + |> withName "CSLib" + |> withReferences [fs] + |> asExe + |> compileAndRun + |> shouldSucceed + |> ignore + + [] + let ``Can recognize CallerArgumentExpression defined in C#`` () = + let cs = + CSharp """using System.Runtime.CompilerServices; +public class AInCs +{ + public static string B(int param, [CallerArgumentExpression("param")] string expr = null) => expr; +} + +namespace System.Runtime.CompilerServices +{ + [AttributeUsage(AttributeTargets.Parameter)] + public sealed class CallerArgumentExpressionAttribute : Attribute + { + public CallerArgumentExpressionAttribute(string param) + { + Param = param; + } + + public string Param { get; } + } +} +""" + + FSharp """let assertEqual a b = if a <> b then failwithf "not equal: %A and %A" a b +open System.Runtime.CompilerServices + +type A() = + static member B (``ab c``, []?n) = + defaultArg n "no value" + +A.B "abc" |> assertEqual "\"abc\"" +AInCs.B (123 - 7) |> assertEqual "123 - 7" + """ + |> withLangVersionPreview + |> withReferences [cs] + |> asExe + |> compileAndRun + |> shouldSucceed + |> ignore + + (* ------------ FSI tests ------------- *) + + [] + let ``Check in fsi`` () = + let path = __SOURCE_DIRECTORY__ ++ "test script.fsx" + FsxFromPath path + |> withLangVersionPreview + |> runFsi + |> shouldSucceed + |> ignore + + + [] + let ``Check fsi #load`` () = + let path = __SOURCE_DIRECTORY__ ++ "test script.fsx" + Fsx $"""#load @"{path}" """ + |> withLangVersionPreview + |> runFsi + |> shouldSucceed + |> ignore diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/CallerArgumentExpression/test script.fsx b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/CallerArgumentExpression/test script.fsx new file mode 100644 index 00000000000..c2152fa6b3b --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/CallerArgumentExpression/test script.fsx @@ -0,0 +1,17 @@ +let assertEqual a b = if a <> b then failwithf "not equal: %A and %A" a b +try System.ArgumentException.ThrowIfNullOrWhiteSpace(Seq.init 50 (fun _ -> " ") + (* comment *) + |> String.concat " ") +with :? System.ArgumentException as ex -> + assertEqual true (ex.Message.Contains("(Parameter 'Seq.init 50 (fun _ -> \" \") + (* comment *) + |> String.concat \" \"")) + + +try System.ArgumentException.ThrowIfNullOrWhiteSpace(argument = (Seq.init 11 (fun _ -> " ") + (* comment *) + |> String.concat " ")) +with :? System.ArgumentException as ex -> + assertEqual true (ex.Message.Contains("(Parameter '(Seq.init 11 (fun _ -> \" \") + (* comment *) + |> String.concat \" \")")) \ No newline at end of file diff --git a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/UnsupportedAttributes.fs b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/UnsupportedAttributes.fs index 3eb78de55b4..295e5115c49 100644 --- a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/UnsupportedAttributes.fs +++ b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/UnsupportedAttributes.fs @@ -15,7 +15,7 @@ open System.Runtime.CompilerServices let f (w, [] x : string) = () let [] g () = () type C() = - member _.F (w, [] x : string) = () + [] member _.G() = () """ @@ -23,13 +23,6 @@ type C() = |> typecheck |> shouldFail |> withResults [ - { Error = Warning 202 - Range = { StartLine = 3 - StartColumn = 13 - EndLine = 3 - EndColumn = 41 } - Message = - "This attribute is currently unsupported by the F# compiler. Applying it will not achieve its intended effect." } { Error = Warning 202 Range = { StartLine = 4 StartColumn = 7 @@ -37,13 +30,6 @@ type C() = EndColumn = 24 } Message = "This attribute is currently unsupported by the F# compiler. Applying it will not achieve its intended effect." } - { Error = Warning 202 - Range = { StartLine = 6 - StartColumn = 22 - EndLine = 6 - EndColumn = 82 } - Message = - "This attribute is currently unsupported by the F# compiler. Applying it will not achieve its intended effect." } { Error = Warning 202 Range = { StartLine = 7 StartColumn = 7 diff --git a/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj b/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj index 60b867c7815..a9af0d57eee 100644 --- a/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj +++ b/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj @@ -40,6 +40,7 @@ + @@ -352,6 +353,7 @@ + diff --git a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.release.bsl b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.release.bsl old mode 100755 new mode 100644 diff --git a/tests/ILVerify/ilverify_FSharp.Compiler.Service_Debug_net9.0.bsl b/tests/ILVerify/ilverify_FSharp.Compiler.Service_Debug_net9.0.bsl index 69842b9e059..9f826562576 100644 --- a/tests/ILVerify/ilverify_FSharp.Compiler.Service_Debug_net9.0.bsl +++ b/tests/ILVerify/ilverify_FSharp.Compiler.Service_Debug_net9.0.bsl @@ -21,7 +21,7 @@ [IL]: Error [StackUnexpected]: : FSharp.Compiler.CodeAnalysis.Hosted.CompilerHelpers::fscCompile([FSharp.Compiler.Service]FSharp.Compiler.CodeAnalysis.LegacyReferenceResolver, string, string[])][offset 0x00000082][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.CodeAnalysis.Hosted.CompilerHelpers::fscCompile([FSharp.Compiler.Service]FSharp.Compiler.CodeAnalysis.LegacyReferenceResolver, string, string[])][offset 0x0000008B][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+MagicAssemblyResolution::ResolveAssemblyCore([FSharp.Compiler.Service]Internal.Utilities.Library.CompilationThreadToken, [FSharp.Compiler.Service]FSharp.Compiler.Text.Range, [FSharp.Compiler.Service]FSharp.Compiler.CompilerConfig+TcConfigBuilder, [FSharp.Compiler.Service]FSharp.Compiler.CompilerImports+TcImports, [FSharp.Compiler.Service]FSharp.Compiler.Interactive.Shell+FsiDynamicCompiler, [FSharp.Compiler.Service]FSharp.Compiler.Interactive.Shell+FsiConsoleOutput, string)][offset 0x00000015][found Char] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+clo@3502-805::Invoke([S.P.CoreLib]System.Tuple`3)][offset 0x000001E5][found Char] Unexpected type on the stack. +[IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+clo@3508-805::Invoke([S.P.CoreLib]System.Tuple`3)][offset 0x00000209][found Char] Unexpected type on the stack. [IL]: Error [UnmanagedPointer]: : FSharp.Compiler.Interactive.Shell+Utilities+pointerToNativeInt@110::Invoke(object)][offset 0x00000007] Unmanaged pointers are not a verifiable type. [IL]: Error [StackUnexpected]: : .$FSharpCheckerResults+dataTipOfReferences@2225::Invoke([FSharp.Core]Microsoft.FSharp.Core.Unit)][offset 0x00000084][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : .$ServiceLexing+clo@921-509::Invoke([FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,Microsoft.FSharp.Core.Unit>)][offset 0x00000032][found Char] Unexpected type on the stack. diff --git a/tests/ILVerify/ilverify_FSharp.Compiler.Service_Debug_netstandard2.0.bsl b/tests/ILVerify/ilverify_FSharp.Compiler.Service_Debug_netstandard2.0.bsl index 6e41547cd11..8fc0c9a6716 100644 --- a/tests/ILVerify/ilverify_FSharp.Compiler.Service_Debug_netstandard2.0.bsl +++ b/tests/ILVerify/ilverify_FSharp.Compiler.Service_Debug_netstandard2.0.bsl @@ -28,7 +28,7 @@ [IL]: Error [StackUnexpected]: : FSharp.Compiler.CodeAnalysis.Hosted.CompilerHelpers::fscCompile([FSharp.Compiler.Service]FSharp.Compiler.CodeAnalysis.LegacyReferenceResolver, string, string[])][offset 0x0000008B][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+FsiStdinSyphon::GetLine(string, int32)][offset 0x00000039][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+MagicAssemblyResolution::ResolveAssemblyCore([FSharp.Compiler.Service]Internal.Utilities.Library.CompilationThreadToken, [FSharp.Compiler.Service]FSharp.Compiler.Text.Range, [FSharp.Compiler.Service]FSharp.Compiler.CompilerConfig+TcConfigBuilder, [FSharp.Compiler.Service]FSharp.Compiler.CompilerImports+TcImports, [FSharp.Compiler.Service]FSharp.Compiler.Interactive.Shell+FsiDynamicCompiler, [FSharp.Compiler.Service]FSharp.Compiler.Interactive.Shell+FsiConsoleOutput, string)][offset 0x00000015][found Char] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+clo@3502-805::Invoke([S.P.CoreLib]System.Tuple`3)][offset 0x000001E5][found Char] Unexpected type on the stack. +[IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+clo@3508-805::Invoke([S.P.CoreLib]System.Tuple`3)][offset 0x00000209][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+FsiInteractionProcessor::CompletionsForPartialLID([FSharp.Compiler.Service]FSharp.Compiler.Interactive.Shell+FsiDynamicCompilerState, string)][offset 0x0000001B][found Char] Unexpected type on the stack. [IL]: Error [UnmanagedPointer]: : FSharp.Compiler.Interactive.Shell+Utilities+pointerToNativeInt@110::Invoke(object)][offset 0x00000007] Unmanaged pointers are not a verifiable type. [IL]: Error [StackUnexpected]: : .$FSharpCheckerResults+dataTipOfReferences@2225::Invoke([FSharp.Core]Microsoft.FSharp.Core.Unit)][offset 0x00000084][found Char] Unexpected type on the stack. @@ -84,6 +84,8 @@ [IL]: Error [StackUnexpected]: : Internal.Utilities.FSharpEnvironment+probePathForDotnetHost@316::Invoke([FSharp.Core]Microsoft.FSharp.Core.Unit)][offset 0x00000028][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.CodeAnalysis.SimulatedMSBuildReferenceResolver+Pipe #6 input at line 68@68::FSharp.Compiler.CodeAnalysis.ILegacyReferenceResolver.Resolve([FSharp.Compiler.Service]FSharp.Compiler.CodeAnalysis.LegacyResolutionEnvironment, [S.P.CoreLib]System.Tuple`2[], string, [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1, string, string, [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1, string, [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2, [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2>>)][offset 0x0000034D][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : .$FSharp.Compiler.DiagnosticsLogger::.cctor()][offset 0x000000CD][found Char] Unexpected type on the stack. +[IL]: Error [StackUnexpected]: : FSharp.Compiler.Text.FileContent::getCodeText([FSharp.Compiler.Service]FSharp.Compiler.Text.Range)][offset 0x00000098][found Char] Unexpected type on the stack. +[IL]: Error [StackUnexpected]: : FSharp.Compiler.Text.FileContent+FileCacheType::FromString(string)][offset 0x0000000B][found Char] Unexpected type on the stack. [IL]: Error [CallVirtOnValueType]: : FSharp.Compiler.Text.RangeModule+comparer@558::System.Collections.Generic.IEqualityComparer.GetHashCode([FSharp.Compiler.Service]FSharp.Compiler.Text.Range)][offset 0x00000002] Callvirt on a value type method. [IL]: Error [StackUnexpected]: : Internal.Utilities.PathMapModule::applyDir([FSharp.Compiler.Service]Internal.Utilities.PathMap, string)][offset 0x00000037][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : Internal.Utilities.PathMapModule::applyDir([FSharp.Compiler.Service]Internal.Utilities.PathMap, string)][offset 0x00000043][found Char] Unexpected type on the stack. diff --git a/tests/ILVerify/ilverify_FSharp.Compiler.Service_Release_net9.0.bsl b/tests/ILVerify/ilverify_FSharp.Compiler.Service_Release_net9.0.bsl index 4e7b5396676..0102fb45ec5 100644 --- a/tests/ILVerify/ilverify_FSharp.Compiler.Service_Release_net9.0.bsl +++ b/tests/ILVerify/ilverify_FSharp.Compiler.Service_Release_net9.0.bsl @@ -21,7 +21,7 @@ [IL]: Error [StackUnexpected]: : FSharp.Compiler.CodeAnalysis.Hosted.CompilerHelpers::fscCompile([FSharp.Compiler.Service]FSharp.Compiler.CodeAnalysis.LegacyReferenceResolver, string, string[])][offset 0x00000082][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.CodeAnalysis.Hosted.CompilerHelpers::fscCompile([FSharp.Compiler.Service]FSharp.Compiler.CodeAnalysis.LegacyReferenceResolver, string, string[])][offset 0x0000008B][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+MagicAssemblyResolution::ResolveAssemblyCore([FSharp.Compiler.Service]Internal.Utilities.Library.CompilationThreadToken, [FSharp.Compiler.Service]FSharp.Compiler.Text.Range, [FSharp.Compiler.Service]FSharp.Compiler.CompilerConfig+TcConfigBuilder, [FSharp.Compiler.Service]FSharp.Compiler.CompilerImports+TcImports, [FSharp.Compiler.Service]FSharp.Compiler.Interactive.Shell+FsiDynamicCompiler, [FSharp.Compiler.Service]FSharp.Compiler.Interactive.Shell+FsiConsoleOutput, string)][offset 0x00000015][found Char] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+clo@3502-849::Invoke([S.P.CoreLib]System.Tuple`3)][offset 0x000001C7][found Char] Unexpected type on the stack. +[IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+clo@3508-849::Invoke([S.P.CoreLib]System.Tuple`3)][offset 0x000001FC][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : .$FSharpCheckerResults+GetReferenceResolutionStructuredToolTipText@2225::Invoke([FSharp.Core]Microsoft.FSharp.Core.Unit)][offset 0x00000076][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : .$ServiceLexing+clo@921-530::Invoke([FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,Microsoft.FSharp.Core.Unit>)][offset 0x00000032][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : .$ServiceLexing+clo@921-530::Invoke([FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,Microsoft.FSharp.Core.Unit>)][offset 0x0000003B][found Char] Unexpected type on the stack. diff --git a/tests/ILVerify/ilverify_FSharp.Compiler.Service_Release_netstandard2.0.bsl b/tests/ILVerify/ilverify_FSharp.Compiler.Service_Release_netstandard2.0.bsl index 431d4e5512a..c951966e07f 100644 --- a/tests/ILVerify/ilverify_FSharp.Compiler.Service_Release_netstandard2.0.bsl +++ b/tests/ILVerify/ilverify_FSharp.Compiler.Service_Release_netstandard2.0.bsl @@ -28,8 +28,11 @@ [IL]: Error [StackUnexpected]: : FSharp.Compiler.CodeAnalysis.Hosted.CompilerHelpers::fscCompile([FSharp.Compiler.Service]FSharp.Compiler.CodeAnalysis.LegacyReferenceResolver, string, string[])][offset 0x0000008B][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+FsiStdinSyphon::GetLine(string, int32)][offset 0x00000032][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+MagicAssemblyResolution::ResolveAssemblyCore([FSharp.Compiler.Service]Internal.Utilities.Library.CompilationThreadToken, [FSharp.Compiler.Service]FSharp.Compiler.Text.Range, [FSharp.Compiler.Service]FSharp.Compiler.CompilerConfig+TcConfigBuilder, [FSharp.Compiler.Service]FSharp.Compiler.CompilerImports+TcImports, [FSharp.Compiler.Service]FSharp.Compiler.Interactive.Shell+FsiDynamicCompiler, [FSharp.Compiler.Service]FSharp.Compiler.Interactive.Shell+FsiConsoleOutput, string)][offset 0x00000015][found Char] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+clo@3502-849::Invoke([S.P.CoreLib]System.Tuple`3)][offset 0x000001C7][found Char] Unexpected type on the stack. +[IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+clo@3508-849::Invoke([S.P.CoreLib]System.Tuple`3)][offset 0x00000107][found Char] Unexpected type on the stack. +[IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+clo@3508-849::Invoke([S.P.CoreLib]System.Tuple`3)][offset 0x00000208][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+FsiInteractionProcessor::CompletionsForPartialLID([FSharp.Compiler.Service]FSharp.Compiler.Interactive.Shell+FsiDynamicCompilerState, string)][offset 0x00000024][found Char] Unexpected type on the stack. +[IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+EvalInteraction@4299::Invoke([FSharp.Compiler.Service]FSharp.Compiler.Interactive.Shell+FsiDynamicCompilerState)][offset 0x0000002E][found Char] Unexpected type on the stack. +[IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+EvalExpression@4326::Invoke([FSharp.Compiler.Service]FSharp.Compiler.Interactive.Shell+FsiDynamicCompilerState)][offset 0x00000059][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : .$FSharpCheckerResults+GetReferenceResolutionStructuredToolTipText@2225::Invoke([FSharp.Core]Microsoft.FSharp.Core.Unit)][offset 0x00000076][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.EditorServices.AssemblyContent+traverseMemberFunctionAndValues@176::Invoke([FSharp.Compiler.Service]FSharp.Compiler.Symbols.FSharpMemberOrFunctionOrValue)][offset 0x0000002B][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.EditorServices.AssemblyContent+traverseEntity@218::GenerateNext([S.P.CoreLib]System.Collections.Generic.IEnumerable`1&)][offset 0x000000BB][found Char] Unexpected type on the stack. @@ -111,6 +114,8 @@ [IL]: Error [StackUnexpected]: : Internal.Utilities.FSharpEnvironment::probePathForDotnetHost@315([FSharp.Core]Microsoft.FSharp.Core.Unit)][offset 0x0000002A][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.CodeAnalysis.SimulatedMSBuildReferenceResolver+SimulatedMSBuildResolver@68::FSharp.Compiler.CodeAnalysis.ILegacyReferenceResolver.Resolve([FSharp.Compiler.Service]FSharp.Compiler.CodeAnalysis.LegacyResolutionEnvironment, [S.P.CoreLib]System.Tuple`2[], string, [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1, string, string, [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1, string, [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2, [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2>>)][offset 0x000002F5][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : .$FSharp.Compiler.DiagnosticsLogger::.cctor()][offset 0x000000B6][found Char] Unexpected type on the stack. +[IL]: Error [StackUnexpected]: : FSharp.Compiler.Text.FileContent::getCodeText([FSharp.Compiler.Service]FSharp.Compiler.Text.Range)][offset 0x00000089][found Char] Unexpected type on the stack. +[IL]: Error [StackUnexpected]: : FSharp.Compiler.Text.FileContent+FileCacheType::FromString(string)][offset 0x0000000B][found Char] Unexpected type on the stack. [IL]: Error [CallVirtOnValueType]: : FSharp.Compiler.Text.RangeModule+comparer@558::System.Collections.Generic.IEqualityComparer.GetHashCode([FSharp.Compiler.Service]FSharp.Compiler.Text.Range)][offset 0x00000002] Callvirt on a value type method. [IL]: Error [StackUnexpected]: : Internal.Utilities.PathMapModule::applyDir([FSharp.Compiler.Service]Internal.Utilities.PathMap, string)][offset 0x00000035][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : Internal.Utilities.PathMapModule::applyDir([FSharp.Compiler.Service]Internal.Utilities.PathMap, string)][offset 0x00000041][found Char] Unexpected type on the stack.