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 16f5721e22a..9d997c8ef32 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md +++ b/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md @@ -38,6 +38,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/CheckBasics.fs b/src/Compiler/Checking/CheckBasics.fs index 7cbca970cc3..401c39791f0 100644 --- a/src/Compiler/Checking/CheckBasics.fs +++ b/src/Compiler/Checking/CheckBasics.fs @@ -335,6 +335,8 @@ type TcFileState = // forward call TcComputationExpression: TcFileState -> TcEnv -> OverallTy -> UnscopedTyparEnv -> range * Expr * TType * SynExpr -> Expr * UnscopedTyparEnv + + SourceText: ISourceText option } /// Create a new compilation environment @@ -344,7 +346,8 @@ type TcFileState = tcSimplePats, tcSequenceExpressionEntry, tcArrayOrListSequenceExpression, - tcComputationExpression) = + tcComputationExpression, + sourceText: ISourceText option) = let niceNameGen = NiceNameGenerator() let infoReader = InfoReader(g, amap) @@ -376,6 +379,7 @@ type TcFileState = TcSequenceExpressionEntry = tcSequenceExpressionEntry TcArrayOrListComputedExpression = tcArrayOrListSequenceExpression TcComputationExpression = tcComputationExpression + SourceText = sourceText } override _.ToString() = "" diff --git a/src/Compiler/Checking/CheckBasics.fsi b/src/Compiler/Checking/CheckBasics.fsi index 179752c394c..cda5f9c646e 100644 --- a/src/Compiler/Checking/CheckBasics.fsi +++ b/src/Compiler/Checking/CheckBasics.fsi @@ -313,6 +313,9 @@ type TcFileState = -> UnscopedTyparEnv -> range * Expr * TType * SynExpr -> Expr * UnscopedTyparEnv + + /// The impl file content. Used to support `CallerArgumentExpression` feature. + SourceText: ISourceText option } static member Create: @@ -356,5 +359,6 @@ type TcFileState = -> OverallTy -> UnscopedTyparEnv -> range * Expr * TType * SynExpr - -> Expr * UnscopedTyparEnv) -> + -> Expr * UnscopedTyparEnv) * + sourceText: ISourceText option -> TcFileState diff --git a/src/Compiler/Checking/CheckDeclarations.fs b/src/Compiler/Checking/CheckDeclarations.fs index 78acf62bb98..21673c0302c 100644 --- a/src/Compiler/Checking/CheckDeclarations.fs +++ b/src/Compiler/Checking/CheckDeclarations.fs @@ -5751,7 +5751,8 @@ let CheckOneImplFile env, rootSigOpt: ModuleOrNamespaceType option, synImplFile, - diagnosticOptions) = + diagnosticOptions, + sourceText: ISourceText option) = let (ParsedImplFileInput (fileName, isScript, qualNameOfFile, scopedPragmas, _, implFileFrags, isLastCompiland, _, _)) = synImplFile let infoReader = InfoReader(g, amap) @@ -5774,7 +5775,8 @@ let CheckOneImplFile tcSimplePats=TcSimplePats, tcSequenceExpressionEntry=TcSequenceExpressionEntry, tcArrayOrListSequenceExpression=TcArrayOrListComputedExpression, - tcComputationExpression=TcComputationExpression) + tcComputationExpression=TcComputationExpression, + sourceText=sourceText) let envinner, moduleTyAcc = MakeInitialEnv env @@ -5919,7 +5921,8 @@ let CheckOneSigFile (g, amap, thisCcu, checkForErrors, conditionalDefines, tcSin tcSimplePats=TcSimplePats, tcSequenceExpressionEntry=TcSequenceExpressionEntry, tcArrayOrListSequenceExpression=TcArrayOrListComputedExpression, - tcComputationExpression=TcComputationExpression) + tcComputationExpression=TcComputationExpression, + sourceText=None) let envinner, moduleTyAcc = MakeInitialEnv tcEnv let m = sigFile.QualifiedName.Range diff --git a/src/Compiler/Checking/CheckDeclarations.fsi b/src/Compiler/Checking/CheckDeclarations.fsi index fb4679f2438..47ad46b0b5a 100644 --- a/src/Compiler/Checking/CheckDeclarations.fsi +++ b/src/Compiler/Checking/CheckDeclarations.fsi @@ -60,7 +60,8 @@ val CheckOneImplFile: TcEnv * ModuleOrNamespaceType option * ParsedImplFileInput * - FSharpDiagnosticOptions -> + FSharpDiagnosticOptions * + ISourceText option -> Cancellable val CheckOneSigFile: diff --git a/src/Compiler/Checking/Expressions/CheckExpressions.fs b/src/Compiler/Checking/Expressions/CheckExpressions.fs index 5f390038e35..78752f066ca 100644 --- a/src/Compiler/Checking/Expressions/CheckExpressions.fs +++ b/src/Compiler/Checking/Expressions/CheckExpressions.fs @@ -10282,7 +10282,7 @@ and TcMethodApplication let objArgPreBinder, objArgs, allArgsPreBinders, allArgs, allArgsCoerced, optArgPreBinder, paramArrayPreBinders, outArgExprs, outArgTmpBinds = let tcVal = LightweightTcValForUsingInBuildMethodCall g - AdjustCallerArgs tcVal TcFieldInit env.eCallerMemberName cenv.infoReader ad finalCalledMeth objArgs lambdaVars mItem mMethExpr + AdjustCallerArgs tcVal TcFieldInit env.eCallerMemberName cenv.SourceText cenv.infoReader ad finalCalledMeth objArgs lambdaVars mItem mMethExpr // Record the resolution of the named argument for the Language Service allArgs |> List.iter (fun assignedArg -> diff --git a/src/Compiler/Checking/MethodCalls.fs b/src/Compiler/Checking/MethodCalls.fs index 19b91dcf0b1..a9ab05ad65d 100644 --- a/src/Compiler/Checking/MethodCalls.fs +++ b/src/Compiler/Checking/MethodCalls.fs @@ -1443,9 +1443,22 @@ 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 (sourceText: ISourceText option) assignedArgs paramName = + assignedArgs + |> List.tryPick (fun { CalledArg=called; CallerArg=caller } -> + match called.NameOpt with + | Some x when x.idText = paramName -> + sourceText + |> Option.bind (fun sourceText -> + let code = sourceText.GetSubTextFromRange 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 sourceText 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 +1475,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 sourceText mMethExpr assignedArgs | _ -> match calledArg.CallerInfo, eCallerMemberName with | CallerLineNumber, _ when typeEquiv g currCalledArgTy g.int_ty -> @@ -1472,6 +1485,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 sourceText 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 +1516,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 sourceText 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 sourceText (mMethExpr: range) assignedArgs = let calledArgTy = calledArg.CalledArgumentType let calledNonOptTy = tryDestOptionalTy g calledArgTy @@ -1516,13 +1537,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 sourceText 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 sourceText mItem (mMethExpr: range) assignedArgs = let calledArgTy = calledArg.CalledArgumentType let preBinder, expr = match calledArg.OptArgInfo with @@ -1530,17 +1559,17 @@ 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 sourceText mMethExpr assignedArgs | CalleeSide -> - emptyPreBinder, GetDefaultExpressionForCalleeSideOptionalArg g calledArg eCallerMemberName mMethExpr + emptyPreBinder, GetDefaultExpressionForCalleeSideOptionalArg g calledArg eCallerMemberName sourceText mMethExpr assignedArgs // Combine the variable allocators (if any) let callerArg = CallerArg(calledArgTy, mMethExpr, false, expr) preBinder, { NamedArgIdOpt = None; CalledArg = calledArg; CallerArg = callerArg } // Adjust all the optional arguments, filling in values for defaults, -let AdjustCallerArgForOptional tcVal tcFieldInit eCallerMemberName (infoReader: InfoReader) ad (assignedArg: AssignedCalledArg<_>) = +let AdjustCallerArgForOptional tcVal tcFieldInit eCallerMemberName sourceText (infoReader: InfoReader) ad (assignedArg: AssignedCalledArg<_>) = let g = infoReader.g let amap = infoReader.amap let callerArg = assignedArg.CallerArg @@ -1587,7 +1616,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 sourceText m [assignedArg] let ty = destOptionTy g callerArgTy mkOptionDefaultValue g m ty defaultExpr callerArgExpr else @@ -1637,7 +1666,7 @@ let AdjustCallerArgForOptional tcVal tcFieldInit eCallerMemberName (infoReader: // - VB also allows you to pass intrinsic values as optional values to parameters // typed as Object. What we do in this case is we box the intrinsic value." // -let AdjustCallerArgsForOptionals tcVal tcFieldInit eCallerMemberName (infoReader: InfoReader) ad (calledMeth: CalledMeth<_>) mItem mMethExpr = +let AdjustCallerArgsForOptionals tcVal tcFieldInit eCallerMemberName (infoReader: InfoReader) ad (calledMeth: CalledMeth<_>) mItem mMethExpr sourceText = let g = infoReader.g let assignedNamedArgs = calledMeth.ArgSets |> List.collect (fun argSet -> argSet.AssignedNamedArgs) @@ -1651,11 +1680,11 @@ 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 sourceText mItem mMethExpr (assignedNamedArgs @ unnamedArgs) arg, (preBinder >> preBinder2)) - let adjustedNormalUnnamedArgs = List.map (AdjustCallerArgForOptional tcVal tcFieldInit eCallerMemberName infoReader ad) unnamedArgs - let adjustedAssignedNamedArgs = List.map (AdjustCallerArgForOptional tcVal tcFieldInit eCallerMemberName infoReader ad) assignedNamedArgs + let adjustedNormalUnnamedArgs = List.map (AdjustCallerArgForOptional tcVal tcFieldInit eCallerMemberName sourceText infoReader ad) unnamedArgs + let adjustedAssignedNamedArgs = List.map (AdjustCallerArgForOptional tcVal tcFieldInit eCallerMemberName sourceText infoReader ad) assignedNamedArgs optArgs, optArgPreBinder, adjustedNormalUnnamedArgs, adjustedAssignedNamedArgs @@ -1703,7 +1732,7 @@ let AdjustParamArrayCallerArgs tcVal g amap infoReader ad (calledMeth: CalledMet /// Build the argument list for a method call. Adjust for param array, optional arguments, byref arguments and coercions. /// For example, if you pass an F# reference cell to a byref then we must get the address of the /// contents of the ref. Likewise lots of adjustments are made for optional arguments etc. -let AdjustCallerArgs tcVal tcFieldInit eCallerMemberName (infoReader: InfoReader) ad (calledMeth: CalledMeth<_>) objArgs lambdaVars mItem mMethExpr = +let AdjustCallerArgs tcVal tcFieldInit eCallerMemberName sourceText (infoReader: InfoReader) ad (calledMeth: CalledMeth<_>) objArgs lambdaVars mItem mMethExpr = let g = infoReader.g let amap = infoReader.amap let calledMethInfo = calledMeth.Method @@ -1725,7 +1754,7 @@ let AdjustCallerArgs tcVal tcFieldInit eCallerMemberName (infoReader: InfoReader AdjustParamArrayCallerArgs tcVal g amap infoReader ad calledMeth mMethExpr let optArgs, optArgPreBinder, adjustedNormalUnnamedArgs, adjustedFinalAssignedNamedArgs = - AdjustCallerArgsForOptionals tcVal tcFieldInit eCallerMemberName infoReader ad calledMeth mItem mMethExpr + AdjustCallerArgsForOptionals tcVal tcFieldInit eCallerMemberName infoReader ad calledMeth mItem mMethExpr sourceText let outArgs, outArgExprs, outArgTmpBinds = AdjustOutCallerArgs g calledMeth mMethExpr diff --git a/src/Compiler/Checking/MethodCalls.fsi b/src/Compiler/Checking/MethodCalls.fsi index f167fbe3b03..71e8fe8ca71 100644 --- a/src/Compiler/Checking/MethodCalls.fsi +++ b/src/Compiler/Checking/MethodCalls.fsi @@ -434,6 +434,7 @@ val AdjustCallerArgs: tcVal: (ValRef -> ValUseFlag -> TType list -> range -> Expr * TType) -> tcFieldInit: (range -> AbstractIL.IL.ILFieldInit -> Const) -> eCallerMemberName: string option -> + sourceText: ISourceText option -> infoReader: InfoReader -> ad: AccessorDomain -> calledMeth: CalledMeth -> 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/ParseAndCheckInputs.fs b/src/Compiler/Driver/ParseAndCheckInputs.fs index 6b7171b5697..feab0b62d09 100644 --- a/src/Compiler/Driver/ParseAndCheckInputs.fs +++ b/src/Compiler/Driver/ParseAndCheckInputs.fs @@ -452,7 +452,7 @@ let ParseInput let mutable scopedPragmas = [] try - let input = + let input, sourceTextOpt = let identStore = HashSet() let lexer = @@ -491,20 +491,21 @@ let ParseInput let tripleSlashComments = XmlDocStore.ReportInvalidXmlDocPositions(lexbuf) - PostParseModuleImpls(defaultNamespace, fileName, isLastCompiland, impl, lexbuf, tripleSlashComments, Set identStore) + PostParseModuleImpls(defaultNamespace, fileName, isLastCompiland, impl, lexbuf, tripleSlashComments, Set identStore), + Some lexbuf.SourceText elif FSharpSigFileSuffixes |> List.exists (FileSystemUtils.checkSuffix fileName) then let intfs = Parser.signatureFile lexer lexbuf let tripleSlashComments = XmlDocStore.ReportInvalidXmlDocPositions(lexbuf) - PostParseModuleSpecs(defaultNamespace, fileName, isLastCompiland, intfs, lexbuf, tripleSlashComments, Set identStore) + PostParseModuleSpecs(defaultNamespace, fileName, isLastCompiland, intfs, lexbuf, tripleSlashComments, Set identStore), None else if lexbuf.SupportsFeature LanguageFeature.MLCompatRevisions then error (Error(FSComp.SR.buildInvalidSourceFileExtensionUpdated fileName, rangeStartup)) else error (Error(FSComp.SR.buildInvalidSourceFileExtension fileName, rangeStartup)) scopedPragmas <- input.ScopedPragmas - input + input, sourceTextOpt finally // OK, now commit the errors, since the ScopedPragmas will (hopefully) have been scraped let filteringDiagnosticsLogger = @@ -668,7 +669,7 @@ let ParseOneInputLexbuf (tcConfig: TcConfig, lexResourceManager, lexbuf, fileNam TestInteractionParserAndExit(tokenizer, lexbuf, tcConfig.exiter) // Parse the input - let res = + let res, sourceTextOpt = ParseInput( (fun _ -> tokenizer ()), tcConfig.diagnosticsOptions, @@ -685,13 +686,13 @@ let ParseOneInputLexbuf (tcConfig: TcConfig, lexResourceManager, lexbuf, fileNam if tcConfig.reportNumDecls then ReportParsingStatistics res - res) + res, sourceTextOpt) input with RecoverableException exn -> errorRecovery exn rangeStartup - EmptyParsedInput(fileName, isLastCompiland) + EmptyParsedInput(fileName, isLastCompiland), None let ValidSuffixes = FSharpSigFileSuffixes @ FSharpImplFileSuffixes @@ -713,6 +714,7 @@ let parseInputStreamAux // Parse the file drawing tokens from the lexbuf ParseOneInputLexbuf(tcConfig, lexResourceManager, lexbuf, fileName, isLastCompiland, diagnosticsLogger) + |> fst let parseInputSourceTextAux (tcConfig: TcConfig, lexResourceManager, fileName, isLastCompiland, diagnosticsLogger, sourceText: ISourceText) @@ -723,6 +725,7 @@ let parseInputSourceTextAux // Parse the file drawing tokens from the lexbuf ParseOneInputLexbuf(tcConfig, lexResourceManager, lexbuf, fileName, isLastCompiland, diagnosticsLogger) + |> fst let parseInputFileAux (tcConfig: TcConfig, lexResourceManager, fileName, isLastCompiland, diagnosticsLogger, retryLocked) = // Get a stream reader for the file @@ -763,7 +766,7 @@ let ParseOneInputFile (tcConfig: TcConfig, lexResourceManager, fileName, isLastC parseInputFileAux (tcConfig, lexResourceManager, fileName, isLastCompiland, diagnosticsLogger, retryLocked) with RecoverableException exn -> errorRecovery exn rangeStartup - EmptyParsedInput(fileName, isLastCompiland) + EmptyParsedInput(fileName, isLastCompiland), None /// Prepare to process inputs independently, e.g. partially in parallel. /// @@ -1287,7 +1290,8 @@ let CheckOneInput prefixPathOpt: LongIdent option, tcSink: TcResultsSink, tcState: TcState, - input: ParsedInput + input: ParsedInput, + sourceTextOpt: ISourceText option ) : Cancellable = cancellable { try @@ -1380,7 +1384,8 @@ let CheckOneInput tcState.tcsTcImplEnv, rootSigOpt, file, - tcConfig.diagnosticsOptions + tcConfig.diagnosticsOptions, + sourceTextOpt ) let tcState = @@ -1406,7 +1411,7 @@ let DiagnosticsLoggerForInput (tcConfig: TcConfig, input: ParsedInput, oldLogger GetDiagnosticsLoggerFilteringByScopedPragmas(false, input.ScopedPragmas, tcConfig.diagnosticsOptions, oldLogger) /// Typecheck a single file (or interactive entry into F# Interactive) -let CheckOneInputEntry (ctok, checkForErrors, tcConfig: TcConfig, tcImports, tcGlobals, prefixPathOpt) tcState input = +let CheckOneInputEntry (ctok, checkForErrors, tcConfig: TcConfig, tcImports, tcGlobals, prefixPathOpt) tcState (input, sourceTextOpt) = cancellable { // Equip loggers to locally filter w.r.t. scope pragmas in each input use _ = @@ -1416,7 +1421,18 @@ let CheckOneInputEntry (ctok, checkForErrors, tcConfig: TcConfig, tcImports, tcG RequireCompilationThread ctok - return! CheckOneInput(checkForErrors, tcConfig, tcImports, tcGlobals, prefixPathOpt, TcResultsSink.NoSink, tcState, input) + return! + CheckOneInput( + checkForErrors, + tcConfig, + tcImports, + tcGlobals, + prefixPathOpt, + TcResultsSink.NoSink, + tcState, + input, + sourceTextOpt + ) } |> Cancellable.runWithoutCancellation @@ -1435,7 +1451,7 @@ let CheckMultipleInputsFinish (results, tcState: TcState) = let CheckOneInputAndFinish (checkForErrors, tcConfig: TcConfig, tcImports, tcGlobals, prefixPathOpt, tcSink, tcState, input) = cancellable { - let! result, tcState = CheckOneInput(checkForErrors, tcConfig, tcImports, tcGlobals, prefixPathOpt, tcSink, tcState, input) + let! result, tcState = CheckOneInput(checkForErrors, tcConfig, tcImports, tcGlobals, prefixPathOpt, tcSink, tcState, input, None) let finishedResult = CheckMultipleInputsFinish([ result ], tcState) return finishedResult } @@ -1505,8 +1521,18 @@ let CheckOneInputWithCallback tcSink, tcState: TcState, input: ParsedInput, - _skipImplIfSigExists: bool): - (unit -> bool) * TcConfig * TcImports * TcGlobals * LongIdent option * TcResultsSink * TcState * ParsedInput * bool + _skipImplIfSigExists: bool, + sourceTextOpt: ISourceText option): + (unit -> bool) * + TcConfig * + TcImports * + TcGlobals * + LongIdent option * + TcResultsSink * + TcState * + ParsedInput * + bool * + ISourceText option ) : Cancellable> = cancellable { @@ -1601,7 +1627,8 @@ let CheckOneInputWithCallback tcState.tcsTcImplEnv, rootSigOpt, file, - tcConfig.diagnosticsOptions + tcConfig.diagnosticsOptions, + sourceTextOpt ) return @@ -1811,7 +1838,7 @@ let CheckMultipleInputsUsingGraphMode LongIdent option * TcState * (PhasedDiagnostic -> PhasedDiagnostic) * - ParsedInput list + (ParsedInput * ISourceText option) list ) : FinalFileResult list * TcState = use cts = new CancellationTokenSource() @@ -1819,7 +1846,7 @@ let CheckMultipleInputsUsingGraphMode let sourceFiles: FileInProject array = inputs |> List.toArray - |> Array.mapi (fun idx (input: ParsedInput) -> + |> Array.mapi (fun idx (input: ParsedInput, _) -> { Idx = idx FileName = input.FileName @@ -1878,7 +1905,7 @@ let CheckMultipleInputsUsingGraphMode let processFile (node: NodeToTypeCheck) - ((input, logger): ParsedInput * DiagnosticsLogger) + ((input, logger, sourceTextOpt): ParsedInput * DiagnosticsLogger * ISourceText option) ((currentTcState, _currentPriorErrors): State) : Finisher = @@ -1894,7 +1921,7 @@ let CheckMultipleInputsUsingGraphMode return! CheckOneInputWithCallback node - (checkForErrors2, tcConfig, tcImports, tcGlobals, prefixPathOpt, tcSink, currentTcState, input, false) + (checkForErrors2, tcConfig, tcImports, tcGlobals, prefixPathOpt, tcSink, currentTcState, input, false, sourceTextOpt) } |> Cancellable.runWithoutCancellation @@ -1914,18 +1941,18 @@ let CheckMultipleInputsUsingGraphMode let inputsWithLoggers = inputsWithLoggers |> List.toArray - |> Array.map (fun (input, oldLogger) -> + |> Array.map (fun ((input, sourceTextOpt), oldLogger) -> let logger = DiagnosticsLoggerForInput(tcConfig, input, oldLogger) - input, logger) + input, sourceTextOpt, logger) let processFile (node: NodeToTypeCheck) (state: State) : Finisher = match node with | NodeToTypeCheck.ArtificialImplFile idx -> - let parsedInput, _ = inputsWithLoggers[idx] + let parsedInput, _, _ = inputsWithLoggers[idx] processArtificialImplFile node parsedInput state | NodeToTypeCheck.PhysicalFile idx -> - let parsedInput, logger = inputsWithLoggers[idx] - processFile node (parsedInput, logger) state + let parsedInput, sourceTextOpt, logger = inputsWithLoggers[idx] + processFile node (parsedInput, logger, sourceTextOpt) state let state: State = tcState, priorErrors diff --git a/src/Compiler/Driver/ParseAndCheckInputs.fsi b/src/Compiler/Driver/ParseAndCheckInputs.fsi index fb32a4557cd..8503f692630 100644 --- a/src/Compiler/Driver/ParseAndCheckInputs.fsi +++ b/src/Compiler/Driver/ParseAndCheckInputs.fsi @@ -74,7 +74,7 @@ val ParseInput: isLastCompiland: (bool * bool) * identCapture: bool * userOpName: string option -> - ParsedInput + ParsedInput * ISourceText option /// A general routine to process hash directives val ProcessMetaCommandsFromInput: @@ -117,7 +117,7 @@ val ParseOneInputFile: isLastCompiland: (bool * bool) * diagnosticsLogger: DiagnosticsLogger * retryLocked: bool -> - ParsedInput + ParsedInput * ISourceText option val ParseOneInputLexbuf: tcConfig: TcConfig * @@ -126,7 +126,7 @@ val ParseOneInputLexbuf: fileName: string * isLastCompiland: (bool * bool) * diagnosticsLogger: DiagnosticsLogger -> - ParsedInput + ParsedInput * ISourceText option val EmptyParsedInput: fileName: string * isLastCompiland: (bool * bool) -> ParsedInput @@ -137,7 +137,7 @@ val ParseInputFiles: sourceFiles: string list * diagnosticsLogger: DiagnosticsLogger * retryLocked: bool -> - (ParsedInput * string) list + ((ParsedInput * ISourceText option) * string) list /// Get the initial type checking environment including the loading of mscorlib/System.Core, FSharp.Core /// applying the InternalsVisibleTo in referenced assemblies and opening 'Checked' if requested. @@ -182,7 +182,8 @@ val CheckOneInput: prefixPathOpt: LongIdent option * tcSink: NameResolution.TcResultsSink * tcState: TcState * - input: ParsedInput -> + input: ParsedInput * + sourceTextOpt: ISourceText option -> Cancellable<(TcEnv * TopAttribs * CheckedImplFile option * ModuleOrNamespaceType) * TcState> val CheckOneInputWithCallback: @@ -195,7 +196,8 @@ val CheckOneInputWithCallback: tcSink: TcResultsSink * tcState: TcState * input: ParsedInput * - _skipImplIfSigExists: bool -> + _skipImplIfSigExists: bool * + sourceTextOptOpt: ISourceText option -> Cancellable> val AddCheckResultsToTcState: @@ -238,7 +240,7 @@ val CheckClosedInputSet: prefixPathOpt: LongIdent option * tcState: TcState * eagerFormat: (PhasedDiagnostic -> PhasedDiagnostic) * - inputs: ParsedInput list -> + inputs: (ParsedInput * ISourceText option) list -> TcState * TopAttribs * CheckedImplFile list * TcEnv /// Check a single input and finish the checking diff --git a/src/Compiler/Driver/ScriptClosure.fs b/src/Compiler/Driver/ScriptClosure.fs index b45049627cf..708d6008947 100644 --- a/src/Compiler/Driver/ScriptClosure.fs +++ b/src/Compiler/Driver/ScriptClosure.fs @@ -31,6 +31,7 @@ type LoadClosureInput = SyntaxTree: ParsedInput option ParseDiagnostics: (PhasedDiagnostic * FSharpDiagnosticSeverity) list MetaCommandDiagnostics: (PhasedDiagnostic * FSharpDiagnosticSeverity) list + SourceText: ISourceText option } [] @@ -96,7 +97,8 @@ module ScriptPreprocessClosure = parsedInput: ParsedInput option * parseDiagnostics: (PhasedDiagnostic * FSharpDiagnosticSeverity) list * metaDiagnostics: (PhasedDiagnostic * FSharpDiagnosticSeverity) list * - nowarns: (string * range) list + nowarns: (string * range) list * + sourceText: ISourceText option type Observed() = let seen = Dictionary<_, bool>() @@ -143,7 +145,9 @@ module ScriptPreprocessClosure = // The root compiland is last in the list of compilands. let isLastCompiland = (IsScript fileName, tcConfig.target.IsExe) + ParseOneInputLexbuf(tcConfig, lexResourceManager, lexbuf, fileName, isLastCompiland, diagnosticsLogger) + |> fst /// Create a TcConfig for load closure starting from a single .fsx file let CreateScriptTextTcConfig @@ -501,14 +505,22 @@ module ScriptPreprocessClosure = for subSource in ClosureSourceOfFilename(subFile, m, tcConfigResult.inputCodePage, false) do yield! processClosureSource subSource else - ClosureFile(subFile, m, None, [], [], []) - - ClosureFile(fileName, m, Some parseResult, parseDiagnostics, diagnosticsLogger.Diagnostics, noWarns) + ClosureFile(subFile, m, None, [], [], [], None) + + ClosureFile( + fileName, + m, + Some parseResult, + parseDiagnostics, + diagnosticsLogger.Diagnostics, + noWarns, + Some sourceText + ) else // Don't traverse into .fs leafs. printfn "yielding non-script source %s" fileName - ClosureFile(fileName, m, None, [], [], []) + ClosureFile(fileName, m, None, [], [], [], None) ] let sources = closureSources |> List.collect processClosureSource @@ -520,7 +532,7 @@ module ScriptPreprocessClosure = /// Mark the last file as isLastCompiland. let MarkLastCompiland (tcConfig: TcConfig, lastClosureFile) = - let (ClosureFile(fileName, m, lastParsedInput, parseDiagnostics, metaDiagnostics, nowarns)) = + let (ClosureFile(fileName, m, lastParsedInput, parseDiagnostics, metaDiagnostics, nowarns, sourceText)) = lastClosureFile match lastParsedInput with @@ -545,7 +557,15 @@ module ScriptPreprocessClosure = ) let lastClosureFileR = - ClosureFile(fileName, m, Some(ParsedInput.ImplFile lastParsedImplFileR), parseDiagnostics, metaDiagnostics, nowarns) + ClosureFile( + fileName, + m, + Some(ParsedInput.ImplFile lastParsedImplFileR), + parseDiagnostics, + metaDiagnostics, + nowarns, + sourceText + ) lastClosureFileR | _ -> lastClosureFile @@ -563,12 +583,12 @@ module ScriptPreprocessClosure = // Get all source files. let sourceFiles = - [ for ClosureFile(fileName, m, _, _, _, _) in closureFiles -> (fileName, m) ] + [ for ClosureFile(fileName, m, _, _, _, _, _) in closureFiles -> (fileName, m) ] let sourceInputs = [ for closureFile in closureFiles -> - let (ClosureFile(fileName, _, input, parseDiagnostics, metaDiagnostics, _nowarns)) = + let (ClosureFile(fileName, _, input, parseDiagnostics, metaDiagnostics, _nowarns, sourceText)) = closureFile let closureInput: LoadClosureInput = @@ -577,6 +597,7 @@ module ScriptPreprocessClosure = SyntaxTree = input ParseDiagnostics = parseDiagnostics MetaCommandDiagnostics = metaDiagnostics + SourceText = sourceText } closureInput @@ -584,7 +605,7 @@ module ScriptPreprocessClosure = let globalNoWarns = closureFiles - |> List.collect (fun (ClosureFile(_, _, _, _, _, noWarns)) -> noWarns) + |> List.collect (fun (ClosureFile(_, _, _, _, _, noWarns, _)) -> noWarns) // Resolve all references. let references, unresolvedReferences, resolutionDiagnostics = @@ -601,7 +622,7 @@ module ScriptPreprocessClosure = // Root errors and warnings - look at the last item in the closureFiles list let loadClosureRootDiagnostics, allRootDiagnostics = match List.rev closureFiles with - | ClosureFile(_, _, _, parseDiagnostics, metaDiagnostics, _) :: _ -> + | ClosureFile(_, _, _, parseDiagnostics, metaDiagnostics, _, _) :: _ -> (earlierDiagnostics @ metaDiagnostics @ resolutionDiagnostics), (parseDiagnostics @ earlierDiagnostics @ metaDiagnostics @ resolutionDiagnostics) | _ -> [], [] // When no file existed. diff --git a/src/Compiler/Driver/ScriptClosure.fsi b/src/Compiler/Driver/ScriptClosure.fsi index 249885036cd..4215c6ae7c3 100644 --- a/src/Compiler/Driver/ScriptClosure.fsi +++ b/src/Compiler/Driver/ScriptClosure.fsi @@ -28,7 +28,9 @@ type LoadClosureInput = ParseDiagnostics: (PhasedDiagnostic * FSharpDiagnosticSeverity) list - MetaCommandDiagnostics: (PhasedDiagnostic * FSharpDiagnosticSeverity) list } + MetaCommandDiagnostics: (PhasedDiagnostic * FSharpDiagnosticSeverity) list + + SourceText: ISourceText option } [] type LoadClosure = diff --git a/src/Compiler/Driver/fsc.fs b/src/Compiler/Driver/fsc.fs index 3518d9d4884..e7c059c4e53 100644 --- a/src/Compiler/Driver/fsc.fs +++ b/src/Compiler/Driver/fsc.fs @@ -627,9 +627,9 @@ let main1 let inputs, _ = (Map.empty, inputs) - ||> List.mapFold (fun state (input, x) -> + ||> List.mapFold (fun state ((input, sourceTextOpt), x) -> let inputT, stateT = DeduplicateParsedInputModuleName state input - (inputT, x), stateT) + ((inputT, sourceTextOpt), x), stateT) // Print the AST if requested if tcConfig.printAst then @@ -647,7 +647,7 @@ let main1 // Apply any nowarn flags let tcConfig = (tcConfig, inputs) - ||> List.fold (fun z (input, sourceFileDirectory) -> + ||> List.fold (fun z ((input, _), sourceFileDirectory) -> ApplyMetaCommandsFromInputToTcConfig(z, input, sourceFileDirectory, dependencyProvider)) let tcConfigP = TcConfigProvider.Constant tcConfig 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/Facilities/prim-lexing.fs b/src/Compiler/Facilities/prim-lexing.fs index 381e11eaa3a..7b085fc8302 100644 --- a/src/Compiler/Facilities/prim-lexing.fs +++ b/src/Compiler/Facilities/prim-lexing.fs @@ -325,6 +325,9 @@ and [] internal LexBuffer<'Char> with get () = bufferAcceptAction and set v = bufferAcceptAction <- v + member val private SourceTextBuilder = System.Text.StringBuilder() + member lexbuf.SourceText = lexbuf.SourceTextBuilder.ToString() |> SourceText.ofString + member lexbuf.RefillBuffer() = filler lexbuf static member LexemeString(lexbuf: LexBuffer) = @@ -359,6 +362,7 @@ and [] internal LexBuffer<'Char> (reportLibraryOnlyFeatures, langVersion, strictIndentation, f: 'Char[] * int * int -> int) : LexBuffer<'Char> = let extension = Array.zeroCreate 4096 + let isCharTy = typeof<'Char> = typeof let filler (lexBuffer: LexBuffer<'Char>) = let n = f (extension, 0, extension.Length) @@ -366,6 +370,10 @@ and [] internal LexBuffer<'Char> Array.blit extension 0 lexBuffer.Buffer lexBuffer.BufferScanPos n lexBuffer.BufferMaxScanLength <- lexBuffer.BufferScanLength + n + if isCharTy then + lexBuffer.SourceTextBuilder.Append(Unchecked.unbox extension, 0, n) + |> ignore + new LexBuffer<'Char>(filler, reportLibraryOnlyFeatures, langVersion, strictIndentation) // Important: This method takes ownership of the array @@ -375,6 +383,11 @@ and [] internal LexBuffer<'Char> lexBuffer.Buffer <- buffer lexBuffer.BufferMaxScanLength <- buffer.Length + + if typeof<'Char> = typeof then + lexBuffer.SourceTextBuilder.Append(Unchecked.unbox buffer, 0, buffer.Length) + |> ignore + lexBuffer // Important: this method does copy the array diff --git a/src/Compiler/Facilities/prim-lexing.fsi b/src/Compiler/Facilities/prim-lexing.fsi index ff13f96c9e1..d9b1b653494 100644 --- a/src/Compiler/Facilities/prim-lexing.fsi +++ b/src/Compiler/Facilities/prim-lexing.fsi @@ -150,6 +150,8 @@ type internal LexBuffer<'Char> = member StrictIndentation: bool option + member SourceText: ISourceText + /// Logs a recoverable error if a language feature is unsupported, at the specified range. member CheckLanguageFeatureAndRecover: LanguageFeature -> range -> unit diff --git a/src/Compiler/Interactive/fsi.fs b/src/Compiler/Interactive/fsi.fs index 78d5cb94dcd..59b3e59d60e 100644 --- a/src/Compiler/Interactive/fsi.fs +++ b/src/Compiler/Interactive/fsi.fs @@ -2184,7 +2184,7 @@ type internal FsiDynamicCompiler ctok, diagnosticsLogger: DiagnosticsLogger, istate: FsiDynamicCompilerState, - inputs: ParsedInput list, + inputs: (ParsedInput * ISourceText option) list, showTypes: bool, isIncrementalFragment: bool, isInteractiveItExpr: bool, @@ -2428,7 +2428,10 @@ type internal FsiDynamicCompiler member _.EvalParsedSourceFiles(ctok, diagnosticsLogger, istate, inputs, m) = let prefix = mkFragmentPath m nextFragmentId // Ensure the path includes the qualifying name - let inputs = inputs |> List.map (PrependPathToInput prefix) + let inputs = + inputs + |> List.map (fun (input, sourceTextOpt) -> PrependPathToInput prefix input, sourceTextOpt) + let isIncrementalFragment = false let istate, _, _ = @@ -2438,8 +2441,15 @@ type internal FsiDynamicCompiler /// Evaluate the given definitions and produce a new interactive state. member _.EvalParsedDefinitions - (ctok, diagnosticsLogger: DiagnosticsLogger, istate, showTypes, isInteractiveItExpr, defs: SynModuleDecl list) - = + ( + ctok, + diagnosticsLogger: DiagnosticsLogger, + istate, + showTypes, + isInteractiveItExpr, + defs: SynModuleDecl list, + ?sourceTextOpt: ISourceText + ) = let fileName = stdinMockFileName let m = @@ -2489,7 +2499,17 @@ type internal FsiDynamicCompiler let isIncrementalFragment = true let istate, tcEnvAtEndOfLastInput, declaredImpls = - ProcessInputs(ctok, diagnosticsLogger, istate, [ input ], showTypes, isIncrementalFragment, isInteractiveItExpr, prefix, m) + ProcessInputs( + ctok, + diagnosticsLogger, + istate, + [ input, sourceTextOpt ], + showTypes, + isIncrementalFragment, + isInteractiveItExpr, + prefix, + m + ) let tcState = istate.tcState @@ -2501,7 +2521,9 @@ type internal FsiDynamicCompiler processContents newState declaredImpls /// Evaluate the given expression and produce a new interactive state. - member fsiDynamicCompiler.EvalParsedExpression(ctok, diagnosticsLogger: DiagnosticsLogger, istate, expr: SynExpr, suppressItPrint) = + member fsiDynamicCompiler.EvalParsedExpression + (ctok, diagnosticsLogger: DiagnosticsLogger, istate, expr: SynExpr, suppressItPrint, sourceText) + = let tcConfig = TcConfig.Create(tcConfigB, validate = false) let itName = "it" @@ -2510,7 +2532,7 @@ type internal FsiDynamicCompiler // Evaluate the overall definitions. let istate = - fsiDynamicCompiler.EvalParsedDefinitions(ctok, diagnosticsLogger, istate, false, true, defs) + fsiDynamicCompiler.EvalParsedDefinitions(ctok, diagnosticsLogger, istate, false, true, defs, sourceText) |> fst // Snarf the type for 'it' via the binding match istate.tcState.TcEnvFromImpls.NameEnv.FindUnqualifiedItem itName with @@ -2884,17 +2906,19 @@ type internal FsiDynamicCompiler let parsedInput = match input.SyntaxTree with - | None -> ParseOneInputFile(tcConfig, lexResourceManager, input.FileName, (true, false), diagnosticsLogger, false) + | None -> + ParseOneInputFile(tcConfig, lexResourceManager, input.FileName, (true, false), diagnosticsLogger, false) + |> fst | Some parseTree -> parseTree - input.FileName, parsedInput) + input.FileName, (parsedInput, input.SourceText)) |> List.unzip diagnosticsLogger.AbortOnError(fsiConsoleOutput) let istate = (istate, sourceFiles, inputs) - |||> List.fold2 (fun istate sourceFile input -> + |||> List.fold2 (fun istate sourceFile (input, _) -> fsiDynamicCompiler.ProcessMetaCommandsFromParsedInputAsInteractiveCommands(ctok, istate, sourceFile, input)) let istate = fsiDynamicCompiler.ProcessDelayedReferences(ctok, istate) @@ -3610,7 +3634,7 @@ type FsiStdinLexerProvider [] type InteractionGroup = - | Definitions of defns: SynModuleDecl list * range: range + | Definitions of defns: SynModuleDecl list * range: range * sourceText: ISourceText | HashDirectives of hashDirective: ParsedHashDirective list @@ -3729,7 +3753,7 @@ type FsiInteractionProcessor | Some(ParsedScriptInteraction.Definitions([ SynModuleDecl.Expr(e, _) ], _)) -> let _state, status = - fsiDynamicCompiler.EvalParsedExpression(ctok, diagnosticsLogger, istate, e, true) + fsiDynamicCompiler.EvalParsedExpression(ctok, diagnosticsLogger, istate, e, true, lexbuf.SourceText) match status with | Completed(Some compStatus) -> @@ -3914,14 +3938,14 @@ type FsiInteractionProcessor loop istate action else match action with - | InteractionGroup.Definitions([], _) + | InteractionGroup.Definitions([], _, _) | InteractionGroup.HashDirectives [] -> istate, Completed None - | InteractionGroup.Definitions([ SynModuleDecl.Expr(expr, _) ], _) -> - fsiDynamicCompiler.EvalParsedExpression(ctok, diagnosticsLogger, istate, expr, false) + | InteractionGroup.Definitions([ SynModuleDecl.Expr(expr, _) ], _, sourceText) -> + fsiDynamicCompiler.EvalParsedExpression(ctok, diagnosticsLogger, istate, expr, false, sourceText) - | InteractionGroup.Definitions(defs, _) -> - fsiDynamicCompiler.EvalParsedDefinitions(ctok, diagnosticsLogger, istate, true, false, defs) + | InteractionGroup.Definitions(defs, _, sourceText) -> + fsiDynamicCompiler.EvalParsedDefinitions(ctok, diagnosticsLogger, istate, true, false, defs, sourceText) | InteractionGroup.HashDirectives(hash :: rest) -> let status = PartiallyProcessHashDirective(ctok, istate, hash, diagnosticsLogger) @@ -3957,7 +3981,8 @@ type FsiInteractionProcessor synInteraction, diagnosticsLogger: DiagnosticsLogger, lastResult: FsiValue option, - cancellationToken: CancellationToken + cancellationToken: CancellationToken, + sourceText ) = cancellationToken.ThrowIfCancellationRequested() @@ -4017,7 +4042,7 @@ type FsiInteractionProcessor | SynModuleDecl.Expr(expr, _) :: rest -> (rest |> List.rev) @ (fsiDynamicCompiler.BuildItBinding expr) | _ -> defsA - let group = InteractionGroup.Definitions(defsA, m) + let group = InteractionGroup.Definitions(defsA, m, sourceText) let others = ParsedScriptInteraction.Definitions(defsB, m) Some group, Some others, istate @@ -4027,7 +4052,7 @@ type FsiInteractionProcessor let status = ExecuteInteractionGroup(ctok, istate, group, diagnosticsLogger) ProcessStepStatus status lastResult (fun lastResult istate -> - ExecuteParsedInteractionInGroups(ctok, istate, others, diagnosticsLogger, lastResult, cancellationToken)) + ExecuteParsedInteractionInGroups(ctok, istate, others, diagnosticsLogger, lastResult, cancellationToken, sourceText)) /// Execute a single parsed interaction which may contain multiple items to be executed /// independently @@ -4038,10 +4063,11 @@ type FsiInteractionProcessor synInteraction, diagnosticsLogger: DiagnosticsLogger, lastResult: FsiValue option, - cancellationToken: CancellationToken + cancellationToken: CancellationToken, + sourceText ) = let status = - ExecuteParsedInteractionInGroups(ctok, istate, synInteraction, diagnosticsLogger, lastResult, cancellationToken) + ExecuteParsedInteractionInGroups(ctok, istate, synInteraction, diagnosticsLogger, lastResult, cancellationToken, sourceText) ProcessStepStatus status lastResult (fun lastResult istate -> let rec loop istate = @@ -4098,21 +4124,21 @@ type FsiInteractionProcessor stopProcessingRecovery e range0 istate, CompletedWithReportedError e - let ExecuteParsedInteractionOnMainThread (ctok, diagnosticsLogger, synInteraction, istate, cancellationToken) = + let ExecuteParsedInteractionOnMainThread (ctok, diagnosticsLogger, synInteraction, istate, cancellationToken, sourceText) = istate |> mainThreadProcessAction ctok (fun ctok istate -> - ExecuteParsedInteraction(ctok, istate, synInteraction, diagnosticsLogger, None, cancellationToken)) + ExecuteParsedInteraction(ctok, istate, synInteraction, diagnosticsLogger, None, cancellationToken, sourceText)) let ParseExpression (tokenizer: LexFilter.LexFilter) = reusingLexbufForParsing tokenizer.LexBuffer (fun () -> Parser.typedSequentialExprEOF (fun _ -> tokenizer.GetToken()) tokenizer.LexBuffer) - let ExecuteParsedExpressionOnMainThread (ctok, diagnosticsLogger, expr, istate) = + let ExecuteParsedExpressionOnMainThread (ctok, diagnosticsLogger, expr, istate, sourceText) = istate |> InteractiveCatch diagnosticsLogger (fun istate -> istate |> mainThreadProcessAction ctok (fun ctok istate -> - fsiDynamicCompiler.EvalParsedExpression(ctok, diagnosticsLogger, istate, expr, false))) + fsiDynamicCompiler.EvalParsedExpression(ctok, diagnosticsLogger, istate, expr, false, sourceText))) let commitResult (istate, result) = match result with @@ -4176,7 +4202,14 @@ type FsiInteractionProcessor let res = istate |> runCodeOnMainThread (fun ctok istate -> - ExecuteParsedInteractionOnMainThread(ctok, diagnosticsLogger, action, istate, cancellationToken)) + ExecuteParsedInteractionOnMainThread( + ctok, + diagnosticsLogger, + action, + istate, + cancellationToken, + tokenizer.LexBuffer.SourceText + )) if progress then fprintfn fsiConsoleOutput.Out "Just called runCodeOnMainThread, res = %O..." res @@ -4285,7 +4318,7 @@ type FsiInteractionProcessor currState |> InteractiveCatch diagnosticsLogger (fun istate -> let expr = ParseInteraction tokenizer - ExecuteParsedInteractionOnMainThread(ctok, diagnosticsLogger, expr, istate, cancellationToken)) + ExecuteParsedInteractionOnMainThread(ctok, diagnosticsLogger, expr, istate, cancellationToken, lexbuf.SourceText)) |> commitResult member this.EvalScript(ctok, scriptPath, diagnosticsLogger) = @@ -4319,7 +4352,7 @@ type FsiInteractionProcessor SynExprSequentialTrivia.Zero ) - ExecuteParsedExpressionOnMainThread(ctok, diagnosticsLogger, exprWithSeq, istate)) + ExecuteParsedExpressionOnMainThread(ctok, diagnosticsLogger, exprWithSeq, istate, lexbuf.SourceText)) |> commitResult member _.AddBoundValue(ctok, diagnosticsLogger, name, value: obj) = diff --git a/src/Compiler/Service/FSharpCheckerResults.fs b/src/Compiler/Service/FSharpCheckerResults.fs index 57d322c81a8..a3779f6bd55 100644 --- a/src/Compiler/Service/FSharpCheckerResults.fs +++ b/src/Compiler/Service/FSharpCheckerResults.fs @@ -3093,6 +3093,7 @@ module internal ParseAndCheckFile = identCapture, Some userOpName ) + |> fst with | :? OperationCanceledException -> reraise () | e -> diff --git a/src/Compiler/Service/IncrementalBuild.fs b/src/Compiler/Service/IncrementalBuild.fs index 0cdc4b9235e..15ecca3b6ac 100644 --- a/src/Compiler/Service/IncrementalBuild.fs +++ b/src/Compiler/Service/IncrementalBuild.fs @@ -158,6 +158,7 @@ module IncrementalBuildSyntaxTree = ParseOneInputSourceText(tcConfig, lexResourceManager, fileName, isLastCompiland, diagnosticsLogger, sourceText) | TextContainer.OnDisk -> ParseOneInputFile(tcConfig, lexResourceManager, fileName, isLastCompiland, diagnosticsLogger, true) + |> fst fileParsed.Trigger fileName @@ -271,7 +272,7 @@ type BoundModel private ( tcGlobals, None, TcResultsSink.WithSink sink, - prevTcInfo.tcState, input ) + prevTcInfo.tcState, input, None ) |> Cancellable.toAsync fileChecked.Trigger fileName diff --git a/src/Compiler/Service/TransparentCompiler.fs b/src/Compiler/Service/TransparentCompiler.fs index 4385ca4f1e3..f7546c34123 100644 --- a/src/Compiler/Service/TransparentCompiler.fs +++ b/src/Compiler/Service/TransparentCompiler.fs @@ -1433,7 +1433,8 @@ type internal TransparentCompiler TcResultsSink.WithSink sink, prevTcInfo.tcState, input, - true) + true, + None) |> Cancellable.toAsync //fileChecked.Trigger fileName 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/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..590c3fce387 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@3526-805::Invoke([S.P.CoreLib]System.Tuple`3)][offset 0x000001E5][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. @@ -37,8 +37,8 @@ [IL]: Error [StackUnexpected]: : FSharp.Compiler.CompilerOptions+getOptionArgList@307::Invoke([FSharp.Compiler.Service]FSharp.Compiler.CompilerOptions+CompilerOption, string)][offset 0x0000003E][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.CompilerOptions+getSwitch@325::Invoke(string)][offset 0x0000000B][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.CompilerOptions+attempt@373::Invoke([FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1)][offset 0x00000E9F][found Char] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : FSharp.Compiler.ParseAndCheckInputs+Pipe #1 stage #1 at line 1845@1845::Invoke(int32)][offset 0x00000030][found Char] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : FSharp.Compiler.ParseAndCheckInputs+Pipe #1 stage #1 at line 1845@1845::Invoke(int32)][offset 0x00000039][found Char] Unexpected type on the stack. +[IL]: Error [StackUnexpected]: : FSharp.Compiler.ParseAndCheckInputs+Pipe #1 stage #1 at line 1872@1872::Invoke(int32)][offset 0x00000030][found Char] Unexpected type on the stack. +[IL]: Error [StackUnexpected]: : FSharp.Compiler.ParseAndCheckInputs+Pipe #1 stage #1 at line 1872@1872::Invoke(int32)][offset 0x00000039][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.CompilerConfig+TcConfig::.ctor([FSharp.Compiler.Service]FSharp.Compiler.CompilerConfig+TcConfigBuilder, bool)][offset 0x0000062B][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.CompilerConfig+TcConfig::.ctor([FSharp.Compiler.Service]FSharp.Compiler.CompilerConfig+TcConfigBuilder, bool)][offset 0x00000634][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.PatternMatchCompilation::isProblematicClause([FSharp.Compiler.Service]FSharp.Compiler.PatternMatchCompilation+MatchClause)][offset 0x00000065][found Byte] 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..6334bda1e5b 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@3526-805::Invoke([S.P.CoreLib]System.Tuple`3)][offset 0x000001E5][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. @@ -53,8 +53,8 @@ [IL]: Error [StackUnexpected]: : FSharp.Compiler.CompilerOptions+attempt@373::Invoke([FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1)][offset 0x00000E9F][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.CompilerOptions+processArg@333::Invoke([FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1)][offset 0x0000004D][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.CompilerOptions+ResponseFile+parseLine@239::Invoke(string)][offset 0x00000031][found Char] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : FSharp.Compiler.ParseAndCheckInputs+Pipe #1 stage #1 at line 1845@1845::Invoke(int32)][offset 0x00000030][found Char] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : FSharp.Compiler.ParseAndCheckInputs+Pipe #1 stage #1 at line 1845@1845::Invoke(int32)][offset 0x00000039][found Char] Unexpected type on the stack. +[IL]: Error [StackUnexpected]: : FSharp.Compiler.ParseAndCheckInputs+Pipe #1 stage #1 at line 1872@1872::Invoke(int32)][offset 0x00000030][found Char] Unexpected type on the stack. +[IL]: Error [StackUnexpected]: : FSharp.Compiler.ParseAndCheckInputs+Pipe #1 stage #1 at line 1872@1872::Invoke(int32)][offset 0x00000039][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.CompilerImports+line@570-1::Invoke(string)][offset 0x0000000B][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.CompilerConfig+TcConfig::.ctor([FSharp.Compiler.Service]FSharp.Compiler.CompilerConfig+TcConfigBuilder, bool)][offset 0x0000062B][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.CompilerConfig+TcConfig::.ctor([FSharp.Compiler.Service]FSharp.Compiler.CompilerConfig+TcConfigBuilder, bool)][offset 0x00000634][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..5a068a68833 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@3526-849::Invoke([S.P.CoreLib]System.Tuple`3)][offset 0x000001C7][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. @@ -39,8 +39,8 @@ [IL]: Error [StackUnexpected]: : FSharp.Compiler.CompilerOptions::attempt@372([FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2, [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1, [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1, [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1, string, string, string, string, [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1)][offset 0x00000A99][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.CompilerOptions::AddPathMapping([FSharp.Compiler.Service]FSharp.Compiler.CompilerConfig+TcConfigBuilder, string)][offset 0x0000000B][found Char] Unexpected type on the stack. [IL]: Error [StackUnderflow]: : FSharp.Compiler.CompilerOptions::DoWithColor([System.Console]System.ConsoleColor, [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2)][offset 0x0000005E] Stack underflow. -[IL]: Error [StackUnexpected]: : FSharp.Compiler.ParseAndCheckInputs+CheckMultipleInputsUsingGraphMode@1845::Invoke(int32)][offset 0x00000031][found Char] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : FSharp.Compiler.ParseAndCheckInputs+CheckMultipleInputsUsingGraphMode@1845::Invoke(int32)][offset 0x0000003A][found Char] Unexpected type on the stack. +[IL]: Error [StackUnexpected]: : FSharp.Compiler.ParseAndCheckInputs+CheckMultipleInputsUsingGraphMode@1872::Invoke(int32)][offset 0x00000031][found Char] Unexpected type on the stack. +[IL]: Error [StackUnexpected]: : FSharp.Compiler.ParseAndCheckInputs+CheckMultipleInputsUsingGraphMode@1872::Invoke(int32)][offset 0x0000003A][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.CompilerConfig+TcConfig::.ctor([FSharp.Compiler.Service]FSharp.Compiler.CompilerConfig+TcConfigBuilder, bool)][offset 0x0000059C][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.CompilerConfig+TcConfig::.ctor([FSharp.Compiler.Service]FSharp.Compiler.CompilerConfig+TcConfigBuilder, bool)][offset 0x000005A5][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.IlxGen::HashRangeSorted([S.P.CoreLib]System.Collections.Generic.IDictionary`2>)][offset 0x00000011][found ref '[FSharp.Compiler.Service]FSharp.Compiler.IlxGen+HashRangeSorted@1873-1'][expected ref '[FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,int32>'] 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..bb9fddb7c79 100644 --- a/tests/ILVerify/ilverify_FSharp.Compiler.Service_Release_netstandard2.0.bsl +++ b/tests/ILVerify/ilverify_FSharp.Compiler.Service_Release_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 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@3526-849::Invoke([S.P.CoreLib]System.Tuple`3)][offset 0x000001C7][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]: : .$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. @@ -55,8 +55,8 @@ [IL]: Error [StackUnexpected]: : FSharp.Compiler.CompilerOptions::subSystemVersionSwitch$cont@656([FSharp.Compiler.Service]FSharp.Compiler.CompilerConfig+TcConfigBuilder, string, [FSharp.Core]Microsoft.FSharp.Core.Unit)][offset 0x0000000B][found Char] Unexpected type on the stack. [IL]: Error [StackUnderflow]: : FSharp.Compiler.CompilerOptions::DoWithColor([System.Console]System.ConsoleColor, [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2)][offset 0x0000005E] Stack underflow. [IL]: Error [StackUnexpected]: : FSharp.Compiler.CompilerOptions+ResponseFile+parseLine@239::Invoke(string)][offset 0x00000026][found Char] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : FSharp.Compiler.ParseAndCheckInputs+CheckMultipleInputsUsingGraphMode@1845::Invoke(int32)][offset 0x00000031][found Char] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : FSharp.Compiler.ParseAndCheckInputs+CheckMultipleInputsUsingGraphMode@1845::Invoke(int32)][offset 0x0000003A][found Char] Unexpected type on the stack. +[IL]: Error [StackUnexpected]: : FSharp.Compiler.ParseAndCheckInputs+CheckMultipleInputsUsingGraphMode@1872::Invoke(int32)][offset 0x00000031][found Char] Unexpected type on the stack. +[IL]: Error [StackUnexpected]: : FSharp.Compiler.ParseAndCheckInputs+CheckMultipleInputsUsingGraphMode@1872::Invoke(int32)][offset 0x0000003A][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.CompilerImports+TcConfig-TryResolveLibWithDirectories@568-1::Invoke([FSharp.Core]Microsoft.FSharp.Core.Unit)][offset 0x00000021][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.CompilerImports+TcConfig-TryResolveLibWithDirectories@568-1::Invoke([FSharp.Core]Microsoft.FSharp.Core.Unit)][offset 0x0000003B][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.CompilerConfig+TcConfig::.ctor([FSharp.Compiler.Service]FSharp.Compiler.CompilerConfig+TcConfigBuilder, bool)][offset 0x0000059C][found Char] Unexpected type on the stack.