From cc60ed6fca25126b856db939afc43c4ca3cfe48d Mon Sep 17 00:00:00 2001 From: Don Syme Date: Sat, 27 Jul 2019 19:25:06 +0100 Subject: [PATCH 1/7] code cleanup prior to optional interop improvements (#7276) * add test cases we need to make work * cleanup method call argument processing --- src/fsharp/ConstraintSolver.fs | 2 +- src/fsharp/MethodCalls.fs | 451 +++++++++++--- src/fsharp/TastOps.fs | 35 +- src/fsharp/TastOps.fsi | 11 +- src/fsharp/TypeChecker.fs | 553 +++++------------- src/fsharp/xlf/FSComp.txt.es.xlf | 2 +- tests/fsharp/core/fsfromfsviacs/lib3.cs | 26 + tests/fsharp/core/fsfromfsviacs/test.fsx | 63 +- ...osoft.VisualStudio.Editors.Designer.cs.xlf | 3 +- ...osoft.VisualStudio.Editors.Designer.de.xlf | 3 +- ...osoft.VisualStudio.Editors.Designer.es.xlf | 3 +- ...osoft.VisualStudio.Editors.Designer.fr.xlf | 3 +- ...osoft.VisualStudio.Editors.Designer.it.xlf | 3 +- ...osoft.VisualStudio.Editors.Designer.ja.xlf | 3 +- ...osoft.VisualStudio.Editors.Designer.ko.xlf | 3 +- ...osoft.VisualStudio.Editors.Designer.pl.xlf | 3 +- ...ft.VisualStudio.Editors.Designer.pt-BR.xlf | 3 +- ...osoft.VisualStudio.Editors.Designer.ru.xlf | 3 +- ...osoft.VisualStudio.Editors.Designer.tr.xlf | 3 +- ....VisualStudio.Editors.Designer.zh-Hans.xlf | 3 +- ....VisualStudio.Editors.Designer.zh-Hant.xlf | 3 +- 21 files changed, 664 insertions(+), 518 deletions(-) diff --git a/src/fsharp/ConstraintSolver.fs b/src/fsharp/ConstraintSolver.fs index 586b91c41b0..4f00fd73ed2 100644 --- a/src/fsharp/ConstraintSolver.fs +++ b/src/fsharp/ConstraintSolver.fs @@ -1931,7 +1931,7 @@ and SolveTypeIsNonNullableValueType (csenv: ConstraintSolverEnv) ndeep m2 trace | _ -> let underlyingTy = stripTyEqnsAndMeasureEqns g ty if isStructTy g underlyingTy then - if isAppTy g underlyingTy && tyconRefEq g g.system_Nullable_tcref (tcrefOfAppTy g underlyingTy) then + if isNullableTy g underlyingTy then return! ErrorD (ConstraintSolverError(FSComp.SR.csTypeParameterCannotBeNullable(), m, m)) else return! ErrorD (ConstraintSolverError(FSComp.SR.csGenericConstructRequiresStructType(NicePrint.minimalStringOfType denv ty), m, m2)) diff --git a/src/fsharp/MethodCalls.fs b/src/fsharp/MethodCalls.fs index 5a8d66c875b..895f2d1f729 100644 --- a/src/fsharp/MethodCalls.fs +++ b/src/fsharp/MethodCalls.fs @@ -20,6 +20,7 @@ open FSharp.Compiler.Tastops.DebugPrint open FSharp.Compiler.TcGlobals open FSharp.Compiler.TypeRelations open FSharp.Compiler.AttributeChecking +open Internal.Utilities #if !NO_EXTENSIONTYPING open FSharp.Compiler.ExtensionTyping @@ -151,7 +152,9 @@ let AdjustCalledArgType (infoReader: InfoReader) isConstraint (calledArg: Called mkRefCellTy g (destByrefTy g calledArgTy) else - // If the called method argument is a delegate type, then the caller may provide a function + // If the called method argument is a delegate type, and the caller is known to be a function type, then the caller may provide a function + // If the called method argument is an Expression type, and the caller is known to be a function type, then the caller may provide a T + // If the called method argument is an [] Quotations.Expr, and the caller is not known to be a quoted expression type, then the caller may provide a T let calledArgTy = let adjustDelegateTy calledTy = let (SigOfFunctionForDelegate(_, delArgTys, _, fty)) = GetSigOfFunctionForDelegate infoReader calledTy m AccessibleFromSomewhere @@ -178,14 +181,18 @@ let AdjustCalledArgType (infoReader: InfoReader) isConstraint (calledArg: Called else calledArgTy // Adjust the called argument type to take into account whether the caller's argument is M(?arg=Some(3)) or M(arg=1) - // If the called method argument is optional with type Option, then the caller may provide a T, unless their argument is propagating-optional (i.e. isOptCallerArg) + // If the called method argument is Callee-side optional with type Option, and the caller argument is not explicitly optional (callerArg.IsOptional), then the caller may provide a T + // If the called method argument is Caller-side optional with type Nullable, and the caller argument is not explicitly optional (callerArg.IsOptional), then the caller may provide a T let calledArgTy = match calledArg.OptArgInfo with - | NotOptional -> calledArgTy + | NotOptional -> calledArgTy | CalleeSide when not callerArg.IsOptional && isOptionTy g calledArgTy -> destOptionTy g calledArgTy - | CalleeSide | CallerSide _ -> calledArgTy - calledArgTy - + // This will be added in https://github.com/dotnet/fsharp/pull/7276 + //| CallerSide _ when not callerArg.IsOptional && isNullableTy g calledArgTy -> destNullableTy g calledArgTy + | CalleeSide + | CallerSide _ -> calledArgTy + + calledArgTy //------------------------------------------------------------------------- // CalledMeth @@ -540,6 +547,351 @@ let ExamineMethodForLambdaPropagation (x: CalledMeth) = else None +//------------------------------------------------------------------------- +// Adjust caller arguments as part of building a method call +//------------------------------------------------------------------------- + +/// Build a call to the System.Object constructor taking no arguments, +let BuildObjCtorCall (g: TcGlobals) m = + let ilMethRef = (mkILCtorMethSpecForTy(g.ilg.typ_Object, [])).MethodRef + Expr.Op (TOp.ILCall (false, false, false, false, CtorValUsedAsSuperInit, false, true, ilMethRef, [], [], [g.obj_ty]), [], [], m) + +/// Implements the elaborated form of adhoc conversions from functions to delegates at member callsites +let BuildNewDelegateExpr (eventInfoOpt: EventInfo option, g, amap, delegateTy, invokeMethInfo: MethInfo, delArgTys, f, fty, m) = + let slotsig = invokeMethInfo.GetSlotSig(amap, m) + let delArgVals, expr = + let topValInfo = ValReprInfo([], List.replicate (max 1 (List.length delArgTys)) ValReprInfo.unnamedTopArg, ValReprInfo.unnamedRetVal) + + // Try to pull apart an explicit lambda and use it directly + // Don't do this in the case where we're adjusting the arguments of a function used to build a .NET-compatible event handler + let lambdaContents = + if Option.isSome eventInfoOpt then + None + else + tryDestTopLambda g amap topValInfo (f, fty) + + match lambdaContents with + | None -> + + if List.exists (isByrefTy g) delArgTys then + error(Error(FSComp.SR.tcFunctionRequiresExplicitLambda(List.length delArgTys), m)) + + let delArgVals = delArgTys |> List.mapi (fun i argty -> fst (mkCompGenLocal m ("delegateArg" + string i) argty)) + let expr = + let args = + match eventInfoOpt with + | Some einfo -> + match delArgVals with + | [] -> error(nonStandardEventError einfo.EventName m) + | h :: _ when not (isObjTy g h.Type) -> error(nonStandardEventError einfo.EventName m) + | h :: t -> [exprForVal m h; mkRefTupledVars g m t] + | None -> + if isNil delArgTys then [mkUnit g m] else List.map (exprForVal m) delArgVals + mkApps g ((f, fty), [], args, m) + delArgVals, expr + + | Some _ -> + let _, _, _, vsl, body, _ = IteratedAdjustArityOfLambda g amap topValInfo f + List.concat vsl, body + + let meth = TObjExprMethod(slotsig, [], [], [delArgVals], expr, m) + mkObjExpr(delegateTy, None, BuildObjCtorCall g m, [meth], [], m) + +let CoerceFromFSharpFuncToDelegate g amap infoReader ad callerArgTy m callerArgExpr delegateTy = + let (SigOfFunctionForDelegate(invokeMethInfo, delArgTys, _, _)) = GetSigOfFunctionForDelegate infoReader delegateTy m ad + BuildNewDelegateExpr (None, g, amap, delegateTy, invokeMethInfo, delArgTys, callerArgExpr, callerArgTy, m) + +// Handle adhoc argument conversions +let AdjustCallerArgExprForCoercions (g: TcGlobals) amap infoReader ad isOutArg calledArgTy (reflArgInfo: ReflectedArgInfo) callerArgTy m callerArgExpr = + + if isByrefTy g calledArgTy && isRefCellTy g callerArgTy then + None, Expr.Op (TOp.RefAddrGet false, [destRefCellTy g callerArgTy], [callerArgExpr], m) + +#if IMPLICIT_ADDRESS_OF + elif isInByrefTy g calledArgTy && not (isByrefTy g callerArgTy) then + let wrap, callerArgExprAddress, _readonly, _writeonly = mkExprAddrOfExpr g true false NeverMutates callerArgExpr None m + Some wrap, callerArgExprAddress +#endif + + elif isDelegateTy g calledArgTy && isFunTy g callerArgTy then + None, CoerceFromFSharpFuncToDelegate g amap infoReader ad callerArgTy m callerArgExpr calledArgTy + + elif isLinqExpressionTy g calledArgTy && isDelegateTy g (destLinqExpressionTy g calledArgTy) && isFunTy g callerArgTy then + let delegateTy = destLinqExpressionTy g calledArgTy + let expr = CoerceFromFSharpFuncToDelegate g amap infoReader ad callerArgTy m callerArgExpr delegateTy + None, mkCallQuoteToLinqLambdaExpression g m delegateTy (Expr.Quote (expr, ref None, false, m, mkQuotedExprTy g delegateTy)) + + // auto conversions to quotations (to match auto conversions to LINQ expressions) + elif reflArgInfo.AutoQuote && isQuotedExprTy g calledArgTy && not (isQuotedExprTy g callerArgTy) then + match reflArgInfo with + | ReflectedArgInfo.Quote true -> + None, mkCallLiftValueWithDefn g m calledArgTy callerArgExpr + | ReflectedArgInfo.Quote false -> + None, Expr.Quote (callerArgExpr, ref None, false, m, calledArgTy) + | ReflectedArgInfo.None -> failwith "unreachable" // unreachable due to reflArgInfo.AutoQuote condition + + // Note: out args do not need to be coerced + elif isOutArg then + None, callerArgExpr + + // Note: not all these casts are reported in quotations + else + None, mkCoerceIfNeeded g calledArgTy callerArgTy callerArgExpr + +// Handle CallerSide optional arguments. +// +// CallerSide optional arguments are largely for COM interop, e.g. to PIA assemblies for Word etc. +// As a result we follow the VB and C# behavior here. +// +// "1. If the parameter is statically typed as System.Object and does not have a value, then there are four cases: +// a. The parameter is marked with MarshalAs(IUnknown), MarshalAs(Interface), or MarshalAs(IDispatch). In this case we pass null. +// b. Else if the parameter is marked with IUnknownConstantAttribute. In this case we pass new System.Runtime.InteropServices.UnknownWrapper(null) +// c. Else if the parameter is marked with IDispatchConstantAttribute. In this case we pass new System.Runtime.InteropServices.DispatchWrapper(null) +// d. Else, we will pass Missing.Value. +// 2. Otherwise, if there is a value attribute, then emit the default value. +// 3. Otherwise, we emit default(T). +// 4. Finally, we apply conversions from the value to the parameter type. This is where the nullable conversions take place for VB. +// - VB allows you to mark ref parameters as optional. The semantics of this is that we create a temporary +// with type = type of parameter, load the optional value to it, and call the method. +// - VB also allows you to mark arrays with Nothing as the optional value. +// - 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 AdjustOptionalCallerArgExprs tcFieldInit eCallerMemberName g (calledMeth: CalledMeth<_>) mItem mMethExpr = + + let assignedNamedArgs = calledMeth.ArgSets |> List.collect (fun argSet -> argSet.AssignedNamedArgs) + let unnamedCalledArgs = calledMeth.ArgSets |> List.collect (fun argSet -> argSet.UnnamedCalledArgs) + let unnamedCallerArgs = calledMeth.ArgSets |> List.collect (fun argSet -> argSet.UnnamedCallerArgs) + let unnamedArgs = + (unnamedCalledArgs, unnamedCallerArgs) ||> List.map2 (fun called caller -> + { NamedArgIdOpt = None; CalledArg=called; CallerArg=caller }) + + let emptyPreBinder (e: Expr) = e + + // Adjust all the optional arguments that require a default value to be inserted into the call + let optArgs, optArgPreBinder = + (emptyPreBinder, calledMeth.UnnamedCalledOptArgs) ||> List.mapFold (fun wrapper calledArg -> + let calledArgTy = calledArg.CalledArgumentType + let wrapper2, expr = + match calledArg.OptArgInfo with + | NotOptional -> + error(InternalError("Unexpected NotOptional", mItem)) + + | CallerSide dfltVal -> + + let rec build currCalledArgTy currDfltVal = + 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. + emptyPreBinder, mkAsmExpr ([ mkNormalLdsfld (fspec_Missing_Value g); AI_nop ], [], [], [currCalledArgTy], mMethExpr) + + | DefaultValue -> + emptyPreBinder, mkDefault(mMethExpr, currCalledArgTy) + + | Constant fieldInit -> + match currCalledArgTy with + | NullableTy g inst when fieldInit <> ILFieldInit.Null -> + let nullableTy = mkILNonGenericBoxedTy(g.FindSysILTypeRef "System.Nullable`1") + let ctor = mkILCtorMethSpecForTy(nullableTy, [ILType.TypeVar 0us]).MethodRef + 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 -> + build inst (PassByRef(inst, currDfltVal)) + | _ -> + match calledArg.CallerInfo, eCallerMemberName with + | CallerLineNumber, _ when typeEquiv g currCalledArgTy g.int_ty -> + emptyPreBinder, Expr.Const (Const.Int32(mMethExpr.StartLine), mMethExpr, currCalledArgTy) + | CallerFilePath, _ when typeEquiv g currCalledArgTy g.string_ty -> + let fileName = mMethExpr.FileName |> FileSystem.GetFullPathShim |> PathMap.apply g.pathMap + 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) + | _ -> + emptyPreBinder, Expr.Const (tcFieldInit mMethExpr fieldInit, mMethExpr, currCalledArgTy) + + | WrapperForIDispatch -> + match g.TryFindSysILTypeRef "System.Runtime.InteropServices.DispatchWrapper" with + | None -> error(Error(FSComp.SR.fscSystemRuntimeInteropServicesIsRequired(), mMethExpr)) + | Some tref -> + let ty = mkILNonGenericBoxedTy tref + let mref = mkILCtorMethSpecForTy(ty, [g.ilg.typ_Object]).MethodRef + let expr = Expr.Op (TOp.ILCall (false, false, false, true, NormalValUse, false, false, mref, [], [], [g.obj_ty]), [], [mkDefault(mMethExpr, currCalledArgTy)], mMethExpr) + emptyPreBinder, expr + + | WrapperForIUnknown -> + match g.TryFindSysILTypeRef "System.Runtime.InteropServices.UnknownWrapper" with + | None -> error(Error(FSComp.SR.fscSystemRuntimeInteropServicesIsRequired(), mMethExpr)) + | Some tref -> + let ty = mkILNonGenericBoxedTy tref + let mref = mkILCtorMethSpecForTy(ty, [g.ilg.typ_Object]).MethodRef + let expr = Expr.Op (TOp.ILCall (false, false, false, true, NormalValUse, false, false, mref, [], [], [g.obj_ty]), [], [mkDefault(mMethExpr, currCalledArgTy)], mMethExpr) + emptyPreBinder, expr + + | PassByRef (ty, dfltVal2) -> + let v, _ = mkCompGenLocal mMethExpr "defaultByrefArg" ty + let wrapper2, rhs = build currCalledArgTy dfltVal2 + (wrapper2 >> mkCompGenLet mMethExpr v rhs), mkValAddr mMethExpr false (mkLocalValRef v) + build calledArgTy dfltVal + + | CalleeSide -> + let calledNonOptTy = + if isOptionTy g calledArgTy then + destOptionTy g calledArgTy + else + calledArgTy // should be unreachable + + match calledArg.CallerInfo, eCallerMemberName with + | CallerLineNumber, _ when typeEquiv g calledNonOptTy g.int_ty -> + let lineExpr = Expr.Const(Const.Int32 mMethExpr.StartLine, mMethExpr, calledNonOptTy) + emptyPreBinder, mkSome g calledNonOptTy lineExpr mMethExpr + | CallerFilePath, _ when typeEquiv g calledNonOptTy g.string_ty -> + let fileName = mMethExpr.FileName |> FileSystem.GetFullPathShim |> PathMap.apply g.pathMap + let filePathExpr = Expr.Const (Const.String(fileName), mMethExpr, calledNonOptTy) + emptyPreBinder, mkSome g calledNonOptTy filePathExpr mMethExpr + | CallerMemberName, Some(callerName) when typeEquiv g calledNonOptTy g.string_ty -> + let memberNameExpr = Expr.Const (Const.String callerName, mMethExpr, calledNonOptTy) + emptyPreBinder, mkSome g calledNonOptTy memberNameExpr mMethExpr + | _ -> + emptyPreBinder, mkNone g calledNonOptTy mMethExpr + + // Combine the variable allocators (if any) + let wrapper = (wrapper >> wrapper2) + let callerArg = CallerArg(calledArgTy, mMethExpr, false, expr) + { NamedArgIdOpt = None; CalledArg = calledArg; CallerArg = callerArg }, wrapper) + + // Adjust all the optional arguments + let wrapOptionalArg (assignedArg: AssignedCalledArg<_>) = + let (CallerArg(callerArgTy, m, isOptCallerArg, callerArgExpr)) = assignedArg.CallerArg + match assignedArg.CalledArg.OptArgInfo with + | NotOptional -> + if isOptCallerArg then errorR(Error(FSComp.SR.tcFormalArgumentIsNotOptional(), m)) + assignedArg + | _ -> + let callerArgExpr2 = + match assignedArg.CalledArg.OptArgInfo with + | CallerSide _ -> + if isOptCallerArg then + // M(?x=bopt) when M(A) --> M(?x=bopt.Value) for caller-side + // STRUCT OPTIONS: if we allow struct options as optional arguments then we should take + // the address correctly. + mkUnionCaseFieldGetUnprovenViaExprAddr (callerArgExpr, mkSomeCase g, [destOptionTy g callerArgTy], 0, m) + else + // M(x=b) when M(A) --> M(?x=b) for caller-side + callerArgExpr + + | CalleeSide -> + if isOptCallerArg then + // M(?x=bopt) when M(A) --> M(?x=Some(bopt.Value)) + callerArgExpr + else + // M(x=b) when M(A) --> M(?x=Some(b :> A)) + let calledArgTy = assignedArg.CalledArg.CalledArgumentType + if isOptionTy g calledArgTy then + let calledNonOptTy = destOptionTy g calledArgTy + mkSome g calledNonOptTy (mkCoerceIfNeeded g calledNonOptTy callerArgTy callerArgExpr) m + else + callerArgExpr // should be unreachable + + | _ -> failwith "Unreachable" + { assignedArg with CallerArg=CallerArg(tyOfExpr g callerArgExpr2, m, isOptCallerArg, callerArgExpr2) } + + let adjustedNormalUnnamedArgs = List.map wrapOptionalArg unnamedArgs + let adjustedAssignedNamedArgs = List.map wrapOptionalArg assignedNamedArgs + + optArgs, optArgPreBinder, adjustedNormalUnnamedArgs, adjustedAssignedNamedArgs + +/// Adjust any 'out' arguments, passing in the address of a mutable local +let AdjustOutCallerArgExprs g (calledMeth: CalledMeth<_>) mMethExpr = + calledMeth.UnnamedCalledOutArgs |> List.map (fun calledArg -> + let calledArgTy = calledArg.CalledArgumentType + let outArgTy = destByrefTy g calledArgTy + let outv, outArgExpr = mkMutableCompGenLocal mMethExpr PrettyNaming.outArgCompilerGeneratedName outArgTy // mutable! + let expr = mkDefault (mMethExpr, outArgTy) + let callerArg = CallerArg (calledArgTy, mMethExpr, false, mkValAddr mMethExpr false (mkLocalValRef outv)) + let outArg = { NamedArgIdOpt=None;CalledArg=calledArg;CallerArg=callerArg } + outArg, outArgExpr, mkCompGenBind outv expr) + |> List.unzip3 + +let AdjustParamArrayCallerArgExprs g amap infoReader ad (calledMeth: CalledMeth<_>) mMethExpr = + let argSets = calledMeth.ArgSets + + let paramArrayCallerArgs = argSets |> List.collect (fun argSet -> argSet.ParamArrayCallerArgs) + match calledMeth.ParamArrayCalledArgOpt with + | None -> + [], [] + | Some paramArrayCalledArg -> + let paramArrayCalledArgElementType = destArrayTy g paramArrayCalledArg.CalledArgumentType + + let paramArrayPreBinders, es = + paramArrayCallerArgs + |> List.map (fun callerArg -> + let (CallerArg(callerArgTy, m, isOutArg, callerArgExpr)) = callerArg + AdjustCallerArgExprForCoercions g amap infoReader ad isOutArg paramArrayCalledArgElementType paramArrayCalledArg.ReflArgInfo callerArgTy m callerArgExpr) + |> List.unzip + + let arg = + [ { NamedArgIdOpt = None + CalledArg=paramArrayCalledArg + CallerArg=CallerArg(paramArrayCalledArg.CalledArgumentType, mMethExpr, false, Expr.Op (TOp.Array, [paramArrayCalledArgElementType], es, mMethExpr)) } ] + paramArrayPreBinders, arg + +/// 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 AdjustCallerArgExprs tcFieldInit eCallerMemberName g amap infoReader ad (calledMeth: CalledMeth<_>) objArgs lambdaVars mItem mMethExpr = + let calledMethInfo = calledMeth.Method + + // Some of the code below must allocate temporary variables or bind other variables to particular values. + // As usual we represent variable allocators by expr -> expr functions + // which we then use to wrap the whole expression. These will either do nothing or pre-bind a variable. It doesn't + // matter what order they are applied in as long as they are all composed together. + let emptyPreBinder (e: Expr) = e + + // For unapplied 'e.M' we first evaluate 'e' outside the lambda, i.e. 'let v = e in (fun arg -> v.M(arg))' + let objArgPreBinder, objArgs = + match objArgs, lambdaVars with + | [objArg], Some _ -> + if calledMethInfo.IsExtensionMember && calledMethInfo.ObjArgNeedsAddress(amap, mMethExpr) then + error(Error(FSComp.SR.tcCannotPartiallyApplyExtensionMethodForByref(calledMethInfo.DisplayName), mMethExpr)) + let objArgTy = tyOfExpr g objArg + let v, ve = mkCompGenLocal mMethExpr "objectArg" objArgTy + (fun body -> mkCompGenLet mMethExpr v objArg body), [ve] + | _ -> + emptyPreBinder, objArgs + + // Handle param array and optional arguments + let paramArrayPreBinders, paramArrayArgs = + AdjustParamArrayCallerArgExprs g amap infoReader ad calledMeth mMethExpr + + let optArgs, optArgPreBinder, adjustedNormalUnnamedArgs, adjustedFinalAssignedNamedArgs = + AdjustOptionalCallerArgExprs tcFieldInit eCallerMemberName g calledMeth mItem mMethExpr + + let outArgs, outArgExprs, outArgTmpBinds = + AdjustOutCallerArgExprs g calledMeth mMethExpr + + let allArgs = + adjustedNormalUnnamedArgs @ + adjustedFinalAssignedNamedArgs @ + paramArrayArgs @ + optArgs @ + outArgs + + let allArgs = + allArgs |> List.sortBy (fun x -> x.Position) + + let allArgsPreBinders, allArgsCoerced = + allArgs + |> List.map (fun assignedArg -> + let isOutArg = assignedArg.CalledArg.IsOutArg + let reflArgInfo = assignedArg.CalledArg.ReflArgInfo + let calledArgTy = assignedArg.CalledArg.CalledArgumentType + let (CallerArg(callerArgTy, m, _, e)) = assignedArg.CallerArg + + AdjustCallerArgExprForCoercions g amap infoReader ad isOutArg calledArgTy reflArgInfo callerArgTy m e) + |> List.unzip + + objArgPreBinder, objArgs, allArgsPreBinders, allArgs, allArgsCoerced, optArgPreBinder, paramArrayPreBinders, outArgExprs, outArgTmpBinds + //------------------------------------------------------------------------- // Additional helpers for building method calls and doing TAST generation //------------------------------------------------------------------------- @@ -573,27 +925,30 @@ let ComputeConstrainedCallInfo g amap m (objArgs, minfo: MethInfo) = | _ -> None - /// Adjust the 'this' pointer before making a call /// Take the address of a struct, and coerce to an interface/base/constraint type if necessary let TakeObjAddrForMethodCall g amap (minfo: MethInfo) isMutable m objArgs f = let ccallInfo = ComputeConstrainedCallInfo g amap m (objArgs, minfo) let wrap, objArgs = + match objArgs with | [objArgExpr] -> + let hasCallInfo = ccallInfo.IsSome let mustTakeAddress = hasCallInfo || minfo.ObjArgNeedsAddress(amap, m) let objArgTy = tyOfExpr g objArgExpr - let wrap, objArgExpr', isReadOnly, _isWriteOnly = mkExprAddrOfExpr g mustTakeAddress hasCallInfo isMutable objArgExpr None m + + let wrap, objArgExprAddr, isReadOnly, _isWriteOnly = + mkExprAddrOfExpr g mustTakeAddress hasCallInfo isMutable objArgExpr None m // Extension members and calls to class constraints may need a coercion for their object argument - let objArgExpr' = + let objArgExprCoerced = if not hasCallInfo && not (TypeDefinitelySubsumesTypeNoCoercion 0 g amap m minfo.ApparentEnclosingType objArgTy) then - mkCoerceExpr(objArgExpr', minfo.ApparentEnclosingType, m, objArgTy) + mkCoerceExpr(objArgExprAddr, minfo.ApparentEnclosingType, m, objArgTy) else - objArgExpr' + objArgExprAddr // Check to see if the extension member uses the extending type as a byref. // If so, make sure we don't allow readonly/immutable values to be passed byref from an extension member. @@ -605,7 +960,7 @@ let TakeObjAddrForMethodCall g amap (minfo: MethInfo) isMutable m objArgs f = errorR(Error(FSComp.SR.tcCannotCallExtensionMethodInrefToByref(minfo.DisplayName), m))) - wrap, [objArgExpr'] + wrap, [objArgExprCoerced] | _ -> id, objArgs @@ -616,11 +971,6 @@ let TakeObjAddrForMethodCall g amap (minfo: MethInfo) isMutable m objArgs f = // Build method calls. //------------------------------------------------------------------------- -//------------------------------------------------------------------------- -// Build calls -//------------------------------------------------------------------------- - - /// Build an expression node that is a call to a .NET method. let BuildILMethInfoCall g amap m isProp (minfo: ILMethInfo) valUseFlags minst direct args = let valu = isStructTy g minfo.ApparentEnclosingType @@ -638,11 +988,6 @@ let BuildILMethInfoCall g amap m isProp (minfo: ILMethInfo) valUseFlags minst di Expr.Op (TOp.ILCall (useCallvirt, isProtected, valu, newobj, valUseFlags, isProp, isDllImport, ilMethRef, minfo.DeclaringTypeInst, minst, retTy), [], args, m), exprTy -/// Build a call to the System.Object constructor taking no arguments, -let BuildObjCtorCall (g: TcGlobals) m = - let ilMethRef = (mkILCtorMethSpecForTy(g.ilg.typ_Object, [])).MethodRef - Expr.Op (TOp.ILCall (false, false, false, false, CtorValUsedAsSuperInit, false, true, ilMethRef, [], [], [g.obj_ty]), [], [], m) - /// Build a call to an F# method. /// @@ -825,55 +1170,6 @@ let BuildMethodCall tcVal g amap isMutable m isProp minfo valUseFlags minst objA errorR(Error(FSComp.SR.tcDefaultStructConstructorCall(), m)) mkDefault (m, ty), ty) -//------------------------------------------------------------------------- -// Build delegate constructions (lambdas/functions to delegates) -//------------------------------------------------------------------------- - -/// Implements the elaborated form of adhoc conversions from functions to delegates at member callsites -let BuildNewDelegateExpr (eventInfoOpt: EventInfo option, g, amap, delegateTy, invokeMethInfo: MethInfo, delArgTys, f, fty, m) = - let slotsig = invokeMethInfo.GetSlotSig(amap, m) - let delArgVals, expr = - let topValInfo = ValReprInfo([], List.replicate (max 1 (List.length delArgTys)) ValReprInfo.unnamedTopArg, ValReprInfo.unnamedRetVal) - - // Try to pull apart an explicit lambda and use it directly - // Don't do this in the case where we're adjusting the arguments of a function used to build a .NET-compatible event handler - let lambdaContents = - if Option.isSome eventInfoOpt then - None - else - tryDestTopLambda g amap topValInfo (f, fty) - - match lambdaContents with - | None -> - - if List.exists (isByrefTy g) delArgTys then - error(Error(FSComp.SR.tcFunctionRequiresExplicitLambda(List.length delArgTys), m)) - - let delArgVals = delArgTys |> List.mapi (fun i argty -> fst (mkCompGenLocal m ("delegateArg" + string i) argty)) - let expr = - let args = - match eventInfoOpt with - | Some einfo -> - match delArgVals with - | [] -> error(nonStandardEventError einfo.EventName m) - | h :: _ when not (isObjTy g h.Type) -> error(nonStandardEventError einfo.EventName m) - | h :: t -> [exprForVal m h; mkRefTupledVars g m t] - | None -> - if isNil delArgTys then [mkUnit g m] else List.map (exprForVal m) delArgVals - mkApps g ((f, fty), [], args, m) - delArgVals, expr - - | Some _ -> - let _, _, _, vsl, body, _ = IteratedAdjustArityOfLambda g amap topValInfo f - List.concat vsl, body - - let meth = TObjExprMethod(slotsig, [], [], [delArgVals], expr, m) - mkObjExpr(delegateTy, None, BuildObjCtorCall g m, [meth], [], m) - -let CoerceFromFSharpFuncToDelegate g amap infoReader ad callerArgTy m callerArgExpr delegateTy = - let (SigOfFunctionForDelegate(invokeMethInfo, delArgTys, _, _)) = GetSigOfFunctionForDelegate infoReader delegateTy m ad - BuildNewDelegateExpr (None, g, amap, delegateTy, invokeMethInfo, delArgTys, callerArgExpr, callerArgTy, m) - //------------------------------------------------------------------------- // Import provided expressions @@ -972,11 +1268,14 @@ module ProvidedMethodCalls = st loop inputType - let convertProvidedExpressionToExprAndWitness tcVal (thisArg: Expr option, - allArgs: Exprs, - paramVars: Tainted[], - g, amap, mut, isProp, isSuperInit, m, - expr: Tainted) = + let convertProvidedExpressionToExprAndWitness + tcVal + (thisArg: Expr option, + allArgs: Exprs, + paramVars: Tainted[], + g, amap, mut, isProp, isSuperInit, m, + expr: Tainted) = + let varConv = // note: using paramVars.Length as assumed initial size, but this might not // be the optimal value; this wasn't checked before obsoleting Dictionary.ofList diff --git a/src/fsharp/TastOps.fs b/src/fsharp/TastOps.fs index 00fb9a08278..c638d9a864e 100644 --- a/src/fsharp/TastOps.fs +++ b/src/fsharp/TastOps.fs @@ -839,16 +839,6 @@ let tryNiceEntityRefOfTyOption ty = | TType_app (tcref, _) -> Some tcref | TType_measure (Measure.Con tcref) -> Some tcref | _ -> None - -let (|NullableTy|_|) g ty = - match tryAppTy g ty with - | ValueSome (tcref, [tyarg]) when tyconRefEq g tcref g.system_Nullable_tcref -> Some tyarg - | _ -> None - -let (|StripNullableTy|) g ty = - match tryAppTy g ty with - | ValueSome (tcref, [tyarg]) when tyconRefEq g tcref g.system_Nullable_tcref -> tyarg - | _ -> ty let mkInstForAppTy g ty = match tryAppTy g ty with @@ -3125,6 +3115,31 @@ let destOptionTy g ty = | ValueSome ty -> ty | ValueNone -> failwith "destOptionTy: not an option type" +let isNullableTy (g: TcGlobals) ty = + match tryDestAppTy g ty with + | ValueNone -> false + | ValueSome tcref -> tyconRefEq g g.system_Nullable_tcref tcref + +let tryDestNullableTy g ty = + match argsOfAppTy g ty with + | [ty1] when isNullableTy g ty -> ValueSome ty1 + | _ -> ValueNone + +let destNullableTy g ty = + match tryDestNullableTy g ty with + | ValueSome ty -> ty + | ValueNone -> failwith "destNullableTy: not a Nullable type" + +let (|NullableTy|_|) g ty = + match tryAppTy g ty with + | ValueSome (tcref, [tyarg]) when tyconRefEq g tcref g.system_Nullable_tcref -> Some tyarg + | _ -> None + +let (|StripNullableTy|) g ty = + match tryDestNullableTy g ty with + | ValueSome tyarg -> tyarg + | _ -> ty + let isLinqExpressionTy g ty = match tryDestAppTy g ty with | ValueNone -> false diff --git a/src/fsharp/TastOps.fsi b/src/fsharp/TastOps.fsi index 8c71736a844..b0743de8536 100755 --- a/src/fsharp/TastOps.fsi +++ b/src/fsharp/TastOps.fsi @@ -1388,7 +1388,7 @@ val mkVoidPtrTy : TcGlobals -> TType /// Build a single-dimensional array type val mkArrayType : TcGlobals -> TType -> TType -/// Determine is a type is an option type +/// Determine if a type is an option type val isOptionTy : TcGlobals -> TType -> bool /// Take apart an option type @@ -1397,6 +1397,15 @@ val destOptionTy : TcGlobals -> TType -> TType /// Try to take apart an option type val tryDestOptionTy : TcGlobals -> TType -> ValueOption +/// Determine is a type is a System.Nullable type +val isNullableTy : TcGlobals -> TType -> bool + +/// Try to take apart a System.Nullable type +val tryDestNullableTy: TcGlobals -> TType -> ValueOption + +/// Take apart a System.Nullable type +val destNullableTy: TcGlobals -> TType -> TType + /// Determine if a type is a System.Linq.Expression type val isLinqExpressionTy : TcGlobals -> TType -> bool diff --git a/src/fsharp/TypeChecker.fs b/src/fsharp/TypeChecker.fs index ae464f15758..70bb0f6b212 100644 --- a/src/fsharp/TypeChecker.fs +++ b/src/fsharp/TypeChecker.fs @@ -9671,75 +9671,74 @@ and TcMethodApplication // In one case (the second "single named item" rule) we delay the application of a // argument until we've produced a lambda that detuples an input tuple let curriedCallerArgsOpt, unnamedDelayedCallerArgExprOpt, exprTy = - match curriedCallerArgs with - | [] -> - None, None, exprTy - | _ -> - let unnamedCurriedCallerArgs, namedCurriedCallerArgs = curriedCallerArgs |> List.map GetMethodArgs |> List.unzip + match curriedCallerArgs with + | [] -> + None, None, exprTy + | _ -> + let unnamedCurriedCallerArgs, namedCurriedCallerArgs = curriedCallerArgs |> List.map GetMethodArgs |> List.unzip - // There is an mismatch when _uses_ of indexed property setters in the tc.fs code that calls this function. - // The arguments are passed as if they are curried with arity [numberOfIndexParameters;1], however in the TAST, indexed property setters - // are uncurried and have arity [numberOfIndexParameters+1]. - // - // Here we work around this mismatch by crunching all property argument lists to uncirred form. - // Ideally the problem needs to be solved at its root cause at the callsites to this function - let unnamedCurriedCallerArgs, namedCurriedCallerArgs = - if isProp then - [List.concat unnamedCurriedCallerArgs], [List.concat namedCurriedCallerArgs] - else - unnamedCurriedCallerArgs, namedCurriedCallerArgs + // There is an mismatch when _uses_ of indexed property setters in the tc.fs code that calls this function. + // The arguments are passed as if they are curried with arity [numberOfIndexParameters;1], however in the TAST, indexed property setters + // are uncurried and have arity [numberOfIndexParameters+1]. + // + // Here we work around this mismatch by crunching all property argument lists to uncirred form. + // Ideally the problem needs to be solved at its root cause at the callsites to this function + let unnamedCurriedCallerArgs, namedCurriedCallerArgs = + if isProp then + [List.concat unnamedCurriedCallerArgs], [List.concat namedCurriedCallerArgs] + else + unnamedCurriedCallerArgs, namedCurriedCallerArgs - let MakeUnnamedCallerArgInfo x = (x, GetNewInferenceTypeForMethodArg cenv env tpenv x, x.Range) - - // "single named item" rule. This is where we have a single accessible method - // member x.M(arg1) - // being used with - // x.M (x, y) - // Without this rule this requires - // x.M ((x, y)) - match candidates with - | [calledMeth] - when (namedCurriedCallerArgs |> List.forall isNil && - let curriedCalledArgs = calledMeth.GetParamAttribs(cenv.amap, mItem) - curriedCalledArgs.Length = 1 && - curriedCalledArgs.Head.Length = 1 && - curriedCalledArgs.Head.Head |> isSimpleFormalArg) -> - let unnamedCurriedCallerArgs = curriedCallerArgs |> List.map (MakeUnnamedCallerArgInfo >> List.singleton) - let namedCurriedCallerArgs = namedCurriedCallerArgs |> List.map (fun _ -> []) - (Some (unnamedCurriedCallerArgs, namedCurriedCallerArgs), None, exprTy) - - // "single named item" rule. This is where we have a single accessible method - // member x.M(arg1, arg2) - // being used with - // x.M p - // We typecheck this as if it has been written "(fun (v1, v2) -> x.M(v1, v2)) p" - // Without this rule this requires - // x.M (fst p, snd p) - | [calledMeth] - when (namedCurriedCallerArgs |> List.forall isNil && - unnamedCurriedCallerArgs.Length = 1 && - unnamedCurriedCallerArgs.Head.Length = 1 && - let curriedCalledArgs = calledMeth.GetParamAttribs(cenv.amap, mItem) - curriedCalledArgs.Length = 1 && - curriedCalledArgs.Head.Length > 1 && - curriedCalledArgs.Head |> List.forall isSimpleFormalArg) -> - - // The call lambda has function type - let exprTy = mkFunTy (NewInferenceType ()) exprTy + let MakeUnnamedCallerArgInfo x = (x, GetNewInferenceTypeForMethodArg cenv env tpenv x, x.Range) + + // "single named item" rule. This is where we have a single accessible method + // member x.M(arg1) + // being used with + // x.M (x, y) + // Without this rule this requires + // x.M ((x, y)) + match candidates with + | [calledMeth] + when (namedCurriedCallerArgs |> List.forall isNil && + let curriedCalledArgs = calledMeth.GetParamAttribs(cenv.amap, mItem) + curriedCalledArgs.Length = 1 && + curriedCalledArgs.Head.Length = 1 && + curriedCalledArgs.Head.Head |> isSimpleFormalArg) -> + let unnamedCurriedCallerArgs = curriedCallerArgs |> List.map (MakeUnnamedCallerArgInfo >> List.singleton) + let namedCurriedCallerArgs = namedCurriedCallerArgs |> List.map (fun _ -> []) + (Some (unnamedCurriedCallerArgs, namedCurriedCallerArgs), None, exprTy) + + // "single named item" rule. This is where we have a single accessible method + // member x.M(arg1, arg2) + // being used with + // x.M p + // We typecheck this as if it has been written "(fun (v1, v2) -> x.M(v1, v2)) p" + // Without this rule this requires + // x.M (fst p, snd p) + | [calledMeth] + when (namedCurriedCallerArgs |> List.forall isNil && + unnamedCurriedCallerArgs.Length = 1 && + unnamedCurriedCallerArgs.Head.Length = 1 && + let curriedCalledArgs = calledMeth.GetParamAttribs(cenv.amap, mItem) + curriedCalledArgs.Length = 1 && + curriedCalledArgs.Head.Length > 1 && + curriedCalledArgs.Head |> List.forall isSimpleFormalArg) -> + + // The call lambda has function type + let exprTy = mkFunTy (NewInferenceType ()) exprTy - (None, Some unnamedCurriedCallerArgs.Head.Head, exprTy) + (None, Some unnamedCurriedCallerArgs.Head.Head, exprTy) - | _ -> - let unnamedCurriedCallerArgs = unnamedCurriedCallerArgs |> List.mapSquared MakeUnnamedCallerArgInfo - let namedCurriedCallerArgs = namedCurriedCallerArgs |> List.mapSquared (fun (isOpt, nm, x) -> - let ty = GetNewInferenceTypeForMethodArg cenv env tpenv x - // #435263: compiler crash with .net optional parameters and F# optional syntax - // named optional arguments should always have option type - let ty = if isOpt then mkOptionTy denv.g ty else ty - nm, isOpt, x, ty, x.Range - ) - - (Some (unnamedCurriedCallerArgs, namedCurriedCallerArgs), None, exprTy) + | _ -> + let unnamedCurriedCallerArgs = unnamedCurriedCallerArgs |> List.mapSquared MakeUnnamedCallerArgInfo + let namedCurriedCallerArgs = namedCurriedCallerArgs |> List.mapSquared (fun (isOpt, nm, x) -> + let ty = GetNewInferenceTypeForMethodArg cenv env tpenv x + // #435263: compiler crash with .net optional parameters and F# optional syntax + // named optional arguments should always have option type + let ty = if isOpt then mkOptionTy denv.g ty else ty + nm, isOpt, x, ty, x.Range) + + (Some (unnamedCurriedCallerArgs, namedCurriedCallerArgs), None, exprTy) let CalledMethHasSingleArgumentGroupOfThisLength n (calledMeth: MethInfo) = @@ -9983,21 +9982,12 @@ and TcMethodApplication let finalCalledMethInfo = finalCalledMeth.Method let finalCalledMethInst = finalCalledMeth.CalledTyArgs - let finalArgSets = finalCalledMeth.ArgSets let finalAssignedItemSetters = finalCalledMeth.AssignedItemSetters - let finalCalledPropInfoOpt = finalCalledMeth.AssociatedPropertyInfo let finalAttributeAssignedNamedItems = finalCalledMeth.AttributeAssignedNamedArgs - let finalUnnamedCalledOptArgs = finalCalledMeth.UnnamedCalledOptArgs - let finalUnnamedCalledOutArgs = finalCalledMeth.UnnamedCalledOutArgs - let finalAssignedNamedArgs = finalArgSets |> List.collect (fun argSet -> argSet.AssignedNamedArgs) - let finalParamArrayCallerArgs = finalArgSets |> List.collect (fun argSet -> argSet.ParamArrayCallerArgs) - let finalUnnamedCalledArgs = finalArgSets |> List.collect (fun argSet -> argSet.UnnamedCalledArgs) - let finalUnnamedCallerArgs = finalArgSets |> List.collect (fun argSet -> argSet.UnnamedCallerArgs) - // STEP 4. Check the attributes on the method and the corresponding event/property, if any - finalCalledPropInfoOpt |> Option.iter (fun pinfo -> CheckPropInfoAttributes pinfo mItem |> CommitOperationResult) + finalCalledMeth.AssociatedPropertyInfo |> Option.iter (fun pinfo -> CheckPropInfoAttributes pinfo mItem |> CommitOperationResult) let isInstance = not (isNil objArgs) MethInfoChecks cenv.g cenv.amap isInstance tyargsOpt objArgs ad mItem finalCalledMethInfo @@ -10026,266 +10016,13 @@ and TcMethodApplication | _ -> () end - if (finalArgSets |> List.existsi (fun i argSet -> argSet.UnnamedCalledArgs |> List.existsi (fun j ca -> ca.Position <> (i, j)))) then + if (finalCalledMeth.ArgSets |> List.existsi (fun i argSet -> argSet.UnnamedCalledArgs |> List.existsi (fun j ca -> ca.Position <> (i, j)))) then errorR(Deprecated(FSComp.SR.tcUnnamedArgumentsDoNotFormPrefix(), mMethExpr)) + /// STEP 5. Build the argument list. Adjust for optional arguments, byref arguments and coercions. - // STEP 5. Build the argument list. Adjust for 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. - - // Some of the code below must allocate temporary variables or bind other variables to particular values. - // As usual we represent variable allocators by expr -> expr functions - // which we then use to wrap the whole expression. These will either do nothing or pre-bind a variable. It doesn't - // matter what order they are applied in as long as they are all composed together. - let emptyPreBinder (e: Expr) = e - - // For unapplied 'e.M' we first evaluate 'e' outside the lambda, i.e. 'let v = e in (fun arg -> v.M(arg))' - let objArgPreBinder, objArgs = - match objArgs, lambdaVars with - | [objArg], Some _ -> - if finalCalledMethInfo.IsExtensionMember && finalCalledMethInfo.ObjArgNeedsAddress(cenv.amap, mMethExpr) then - error(Error(FSComp.SR.tcCannotPartiallyApplyExtensionMethodForByref(finalCalledMethInfo.DisplayName), mMethExpr)) - let objArgTy = tyOfExpr cenv.g objArg - let v, ve = mkCompGenLocal mMethExpr "objectArg" objArgTy - (fun body -> mkCompGenLet mMethExpr v objArg body), [ve] - | _ -> - emptyPreBinder, objArgs - - // Handle adhoc argument conversions - let coerceExpr isOutArg calledArgTy (reflArgInfo: ReflectedArgInfo) callerArgTy m callerArgExpr = - let g = cenv.g - - if isByrefTy g calledArgTy && isRefCellTy g callerArgTy then - None, Expr.Op (TOp.RefAddrGet false, [destRefCellTy g callerArgTy], [callerArgExpr], m) - -#if IMPLICIT_ADDRESS_OF - elif isInByrefTy g calledArgTy && not (isByrefTy cenv.g callerArgTy) then - let wrap, callerArgExprAddress, _readonly, _writeonly = mkExprAddrOfExpr g true false NeverMutates callerArgExpr None m - Some wrap, callerArgExprAddress -#endif - - elif isDelegateTy cenv.g calledArgTy && isFunTy cenv.g callerArgTy then - None, CoerceFromFSharpFuncToDelegate cenv.g cenv.amap cenv.infoReader ad callerArgTy m callerArgExpr calledArgTy - - elif isLinqExpressionTy cenv.g calledArgTy && isDelegateTy cenv.g (destLinqExpressionTy cenv.g calledArgTy) && isFunTy cenv.g callerArgTy then - let delegateTy = destLinqExpressionTy cenv.g calledArgTy - let expr = CoerceFromFSharpFuncToDelegate cenv.g cenv.amap cenv.infoReader ad callerArgTy m callerArgExpr delegateTy - None, mkCallQuoteToLinqLambdaExpression cenv.g m delegateTy (Expr.Quote (expr, ref None, false, m, mkQuotedExprTy cenv.g delegateTy)) - - // auto conversions to quotations (to match auto conversions to LINQ expressions) - elif reflArgInfo.AutoQuote && isQuotedExprTy cenv.g calledArgTy && not (isQuotedExprTy cenv.g callerArgTy) then - match reflArgInfo with - | ReflectedArgInfo.Quote true -> - None, mkCallLiftValueWithDefn cenv.g m calledArgTy callerArgExpr - | ReflectedArgInfo.Quote false -> - None, Expr.Quote (callerArgExpr, ref None, false, m, calledArgTy) - | ReflectedArgInfo.None -> failwith "unreachable" // unreachable due to reflArgInfo.AutoQuote condition - - // Note: out args do not need to be coerced - elif isOutArg then - None, callerArgExpr - - // Note: not all these casts are reported in quotations - else - None, mkCoerceIfNeeded cenv.g calledArgTy callerArgTy callerArgExpr - - // Handle param array and optional arguments - let optArgPreBinder, paramArrayPreBinders, allArgs, outArgExprs, outArgTmpBinds = - - let normalUnnamedArgs = - (finalUnnamedCalledArgs, finalUnnamedCallerArgs) ||> List.map2 (fun called caller -> { NamedArgIdOpt = None; CalledArg=called; CallerArg=caller }) - - let paramArrayPreBinders, paramArrayArgs = - match finalCalledMeth.ParamArrayCalledArgOpt with - | None -> - [], [] - | Some paramArrayCalledArg -> - let paramArrayCalledArgElementType = destArrayTy cenv.g paramArrayCalledArg.CalledArgumentType - - let paramArrayPreBinders, es = - finalParamArrayCallerArgs - |> List.map (fun callerArg -> - let (CallerArg(callerArgTy, m, isOutArg, callerArgExpr)) = callerArg - coerceExpr isOutArg paramArrayCalledArgElementType paramArrayCalledArg.ReflArgInfo callerArgTy m callerArgExpr) - |> List.unzip - - let arg = - [ { NamedArgIdOpt = None - CalledArg=paramArrayCalledArg - CallerArg=CallerArg(paramArrayCalledArg.CalledArgumentType, mMethExpr, false, Expr.Op (TOp.Array, [paramArrayCalledArgElementType], es, mMethExpr)) } ] - paramArrayPreBinders, arg - - // CLEANUP: Move all this code into some isolated file, e.g. "optional.fs" - // - // Handle CallerSide optional arguments. - // - // CallerSide optional arguments are largely for COM interop, e.g. to PIA assemblies for Word etc. - // As a result we follow the VB and C# behavior here. - // - // "1. If the parameter is statically typed as System.Object and does not have a value, then there are four cases: - // a. The parameter is marked with MarshalAs(IUnknown), MarshalAs(Interface), or MarshalAs(IDispatch). In this case we pass null. - // b. Else if the parameter is marked with IUnknownConstantAttribute. In this case we pass new System.Runtime.InteropServices.UnknownWrapper(null) - // c. Else if the parameter is marked with IDispatchConstantAttribute. In this case we pass new System.Runtime.InteropServices.DispatchWrapper(null) - // d. Else, we will pass Missing.Value. - // 2. Otherwise, if there is a value attribute, then emit the default value. - // 3. Otherwise, we emit default(T). - // 4. Finally, we apply conversions from the value to the parameter type. This is where the nullable conversions take place for VB. - // - VB allows you to mark ref parameters as optional. The semantics of this is that we create a temporary - // with type = type of parameter, load the optional value to it, and call the method. - // - VB also allows you to mark arrays with Nothing as the optional value. - // - 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 optArgs, optArgPreBinder = - (emptyPreBinder, finalUnnamedCalledOptArgs) ||> List.mapFold (fun wrapper calledArg -> - let calledArgTy = calledArg.CalledArgumentType - let wrapper2, expr = - match calledArg.OptArgInfo with - | NotOptional -> - error(InternalError("Unexpected NotOptional", mItem)) - | CallerSide dfltVal -> - let rec build currCalledArgTy currDfltVal = - 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. - emptyPreBinder, mkAsmExpr ([ mkNormalLdsfld (fspec_Missing_Value cenv.g); AI_nop ], [], [], [currCalledArgTy], mMethExpr) - | DefaultValue -> - emptyPreBinder, mkDefault(mMethExpr, currCalledArgTy) - | Constant fieldInit -> - match currCalledArgTy with - | NullableTy cenv.g inst when fieldInit <> ILFieldInit.Null -> - let nullableTy = mkILNonGenericBoxedTy(cenv.g.FindSysILTypeRef "System.Nullable`1") - let ctor = mkILCtorMethSpecForTy(nullableTy, [ILType.TypeVar 0us]).MethodRef - 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 cenv.g inst -> - build inst (PassByRef(inst, currDfltVal)) - | _ -> - match calledArg.CallerInfo, env.eCallerMemberName with - | CallerLineNumber, _ when typeEquiv cenv.g currCalledArgTy cenv.g.int_ty -> - emptyPreBinder, Expr.Const (Const.Int32(mMethExpr.StartLine), mMethExpr, currCalledArgTy) - | CallerFilePath, _ when typeEquiv cenv.g currCalledArgTy cenv.g.string_ty -> - let fileName = mMethExpr.FileName |> FileSystem.GetFullPathShim |> PathMap.apply cenv.g.pathMap - emptyPreBinder, Expr.Const (Const.String fileName, mMethExpr, currCalledArgTy) - | CallerMemberName, Some callerName when (typeEquiv cenv.g currCalledArgTy cenv.g.string_ty) -> - emptyPreBinder, Expr.Const (Const.String callerName, mMethExpr, currCalledArgTy) - | _ -> - emptyPreBinder, Expr.Const (TcFieldInit mMethExpr fieldInit, mMethExpr, currCalledArgTy) - - | WrapperForIDispatch -> - match cenv.g.TryFindSysILTypeRef "System.Runtime.InteropServices.DispatchWrapper" with - | None -> error(Error(FSComp.SR.fscSystemRuntimeInteropServicesIsRequired(), mMethExpr)) - | Some tref -> - let ty = mkILNonGenericBoxedTy tref - let mref = mkILCtorMethSpecForTy(ty, [cenv.g.ilg.typ_Object]).MethodRef - let expr = Expr.Op (TOp.ILCall (false, false, false, true, NormalValUse, false, false, mref, [], [], [cenv.g.obj_ty]), [], [mkDefault(mMethExpr, currCalledArgTy)], mMethExpr) - emptyPreBinder, expr - | WrapperForIUnknown -> - match cenv.g.TryFindSysILTypeRef "System.Runtime.InteropServices.UnknownWrapper" with - | None -> error(Error(FSComp.SR.fscSystemRuntimeInteropServicesIsRequired(), mMethExpr)) - | Some tref -> - let ty = mkILNonGenericBoxedTy tref - let mref = mkILCtorMethSpecForTy(ty, [cenv.g.ilg.typ_Object]).MethodRef - let expr = Expr.Op (TOp.ILCall (false, false, false, true, NormalValUse, false, false, mref, [], [], [cenv.g.obj_ty]), [], [mkDefault(mMethExpr, currCalledArgTy)], mMethExpr) - emptyPreBinder, expr - | PassByRef (ty, dfltVal2) -> - let v, _ = mkCompGenLocal mMethExpr "defaultByrefArg" ty - let wrapper2, rhs = build currCalledArgTy dfltVal2 - (wrapper2 >> mkCompGenLet mMethExpr v rhs), mkValAddr mMethExpr false (mkLocalValRef v) - build calledArgTy dfltVal - | CalleeSide -> - let calledNonOptTy = - if isOptionTy cenv.g calledArgTy then - destOptionTy cenv.g calledArgTy - else - calledArgTy // should be unreachable - - match calledArg.CallerInfo, env.eCallerMemberName with - | CallerLineNumber, _ when typeEquiv cenv.g calledNonOptTy cenv.g.int_ty -> - let lineExpr = Expr.Const(Const.Int32 mMethExpr.StartLine, mMethExpr, calledNonOptTy) - emptyPreBinder, mkSome cenv.g calledNonOptTy lineExpr mMethExpr - | CallerFilePath, _ when typeEquiv cenv.g calledNonOptTy cenv.g.string_ty -> - let fileName = mMethExpr.FileName |> FileSystem.GetFullPathShim |> PathMap.apply cenv.g.pathMap - let filePathExpr = Expr.Const (Const.String(fileName), mMethExpr, calledNonOptTy) - emptyPreBinder, mkSome cenv.g calledNonOptTy filePathExpr mMethExpr - | CallerMemberName, Some(callerName) when typeEquiv cenv.g calledNonOptTy cenv.g.string_ty -> - let memberNameExpr = Expr.Const (Const.String callerName, mMethExpr, calledNonOptTy) - emptyPreBinder, mkSome cenv.g calledNonOptTy memberNameExpr mMethExpr - | _ -> - emptyPreBinder, mkNone cenv.g calledNonOptTy mMethExpr - - // Combine the variable allocators (if any) - let wrapper = (wrapper >> wrapper2) - let callerArg = CallerArg(calledArgTy, mMethExpr, false, expr) - { NamedArgIdOpt = None; CalledArg = calledArg; CallerArg = callerArg }, wrapper) - - - // Handle optional arguments - let wrapOptionalArg (assignedArg: AssignedCalledArg<_>) = - let (CallerArg(callerArgTy, m, isOptCallerArg, expr)) = assignedArg.CallerArg - match assignedArg.CalledArg.OptArgInfo with - | NotOptional -> - if isOptCallerArg then errorR(Error(FSComp.SR.tcFormalArgumentIsNotOptional(), m)) - assignedArg - | _ -> - let expr = - match assignedArg.CalledArg.OptArgInfo with - | CallerSide _ -> - if isOptCallerArg then - // STRUCT OPTIONS: if we allow struct options as optional arguments then we should take - // the address correctly. - mkUnionCaseFieldGetUnprovenViaExprAddr (expr, mkSomeCase cenv.g, [destOptionTy cenv.g callerArgTy], 0, m) - else - expr - | CalleeSide -> - if isOptCallerArg then - // M(?x=bopt) when M(A) --> M(?x=Some(b.Value)) - expr - else - // M(x=b) when M(A) --> M(?x=Some(b :> A)) - let calledArgTy = assignedArg.CalledArg.CalledArgumentType - if isOptionTy cenv.g calledArgTy then - let calledNonOptTy = destOptionTy cenv.g calledArgTy - mkSome cenv.g calledNonOptTy (mkCoerceIfNeeded cenv.g calledNonOptTy callerArgTy expr) m - else - expr // should be unreachable - - | _ -> failwith "Unreachable" - { assignedArg with CallerArg=CallerArg((tyOfExpr cenv.g expr), m, isOptCallerArg, expr) } - - let outArgsAndExprs, outArgTmpBinds = - finalUnnamedCalledOutArgs |> List.map (fun calledArg -> - let calledArgTy = calledArg.CalledArgumentType - let outArgTy = destByrefTy cenv.g calledArgTy - let outv, outArgExpr = mkMutableCompGenLocal mMethExpr PrettyNaming.outArgCompilerGeneratedName outArgTy // mutable! - let expr = mkDefault(mMethExpr, outArgTy) - let callerArg = CallerArg(calledArgTy, mMethExpr, false, mkValAddr mMethExpr false (mkLocalValRef outv)) - let outArg = { NamedArgIdOpt=None;CalledArg=calledArg;CallerArg=callerArg } - (outArg, outArgExpr), mkCompGenBind outv expr) - |> List.unzip - - let outArgs, outArgExprs = List.unzip outArgsAndExprs - - let allArgs = - List.map wrapOptionalArg normalUnnamedArgs @ - List.map wrapOptionalArg finalAssignedNamedArgs @ - paramArrayArgs @ - optArgs @ - outArgs - - let allArgs = - allArgs |> List.sortBy (fun x -> x.Position) - - optArgPreBinder, paramArrayPreBinders, allArgs, outArgExprs, outArgTmpBinds - - let coerce (assignedArg: AssignedCalledArg<_>) = - let isOutArg = assignedArg.CalledArg.IsOutArg - let reflArgInfo = assignedArg.CalledArg.ReflArgInfo - let calledArgTy = assignedArg.CalledArg.CalledArgumentType - let (CallerArg(callerArgTy, m, _, e)) = assignedArg.CallerArg - - coerceExpr isOutArg calledArgTy reflArgInfo callerArgTy m e + let objArgPreBinder, objArgs, allArgsPreBinders, allArgs, allArgsCoerced, optArgPreBinder, paramArrayPreBinders, outArgExprs, outArgTmpBinds = + AdjustCallerArgExprs TcFieldInit env.eCallerMemberName cenv.g cenv.amap cenv.infoReader ad finalCalledMeth objArgs lambdaVars mItem mMethExpr // Record the resolution of the named argument for the Language Service allArgs |> List.iter (fun assignedArg -> @@ -10295,84 +10032,61 @@ and TcMethodApplication let item = Item.ArgName (defaultArg assignedArg.CalledArg.NameOpt id, assignedArg.CalledArg.CalledArgumentType, Some(ArgumentContainer.Method finalCalledMethInfo)) CallNameResolutionSink cenv.tcSink (id.idRange, env.NameEnv, item, item, emptyTyparInst, ItemOccurence.Use, env.DisplayEnv, ad)) - let allArgsPreBinders, allArgsCoerced = List.map coerce allArgs |> List.unzip - // Make the call expression - let expr, exprty = + /// STEP 6. Build the call expression, then adjust for byref-returns, out-parameters-as-tuples, post-hoc property assignments, methods-as-first-class-value, + /// + + let callExpr0, exprty = BuildPossiblyConditionalMethodCall cenv env mut mMethExpr isProp finalCalledMethInfo isSuperInit finalCalledMethInst objArgs allArgsCoerced // Handle byref returns - let expr = + let callExpr1 = // byref-typed returns get implicitly dereferenced - let vty = tyOfExpr cenv.g expr + let vty = tyOfExpr cenv.g callExpr0 if isByrefTy cenv.g vty then let v, _ = mkCompGenLocal mMethExpr "byrefReturn" vty - mkCompGenLet mMethExpr v expr (mkAddrGet mMethExpr (mkLocalValRef v)) + mkCompGenLet mMethExpr v callExpr0 (mkAddrGet mMethExpr (mkLocalValRef v)) else - expr + callExpr0 // Bind "out" parameters as part of the result tuple - let expr, exprty = + let callExpr2, exprty = + let expr = callExpr1 if isNil outArgTmpBinds then expr, exprty else let outArgTys = outArgExprs |> List.map (tyOfExpr cenv.g) - let expr = if isUnitTy cenv.g exprty then mkCompGenSequential mMethExpr expr (mkRefTupled cenv.g mMethExpr outArgExprs outArgTys) - else mkRefTupled cenv.g mMethExpr (expr :: outArgExprs) (exprty :: outArgTys) + let expr = + if isUnitTy cenv.g exprty then + mkCompGenSequential mMethExpr expr (mkRefTupled cenv.g mMethExpr outArgExprs outArgTys) + else + mkRefTupled cenv.g mMethExpr (expr :: outArgExprs) (exprty :: outArgTys) let expr = mkLetsBind mMethExpr outArgTmpBinds expr expr, tyOfExpr cenv.g expr // Handle post-hoc property assignments - let setterExprPrebinders, expr = - if isCheckingAttributeCall then - [], expr - elif isNil finalAssignedItemSetters then - [], expr - else - // This holds the result of the call - let objv, objExpr = mkMutableCompGenLocal mMethExpr "returnVal" exprty // mutable in case it's a struct - // This expression mutates the properties on the result of the call - let setterExprPrebinders, propSetExpr = - (mkUnit cenv.g mMethExpr, finalAssignedItemSetters) ||> List.mapFold (fun acc (AssignedItemSetter(id, setter, CallerArg(callerArgTy, m, isOptCallerArg, argExpr))) -> - if isOptCallerArg then error(Error(FSComp.SR.tcInvalidOptionalAssignmentToPropertyOrField(), m)) - - let argExprPrebinder, action, defnItem = - match setter with - | AssignedPropSetter (pinfo, pminfo, pminst) -> - MethInfoChecks cenv.g cenv.amap true None [objExpr] ad m pminfo - let calledArgTy = List.head (List.head (pminfo.GetParamTypes(cenv.amap, m, pminst))) - let argExprPrebinder, argExpr = coerceExpr false calledArgTy ReflectedArgInfo.None callerArgTy m argExpr - let mut = (if isStructTy cenv.g (tyOfExpr cenv.g objExpr) then DefinitelyMutates else PossiblyMutates) - let action = BuildPossiblyConditionalMethodCall cenv env mut m true pminfo NormalValUse pminst [objExpr] [argExpr] |> fst - argExprPrebinder, action, Item.Property (pinfo.PropertyName, [pinfo]) - - | AssignedILFieldSetter finfo -> - // Get or set instance IL field - ILFieldInstanceChecks cenv.g cenv.amap ad m finfo - let calledArgTy = finfo.FieldType (cenv.amap, m) - let argExprPrebinder, argExpr = coerceExpr false calledArgTy ReflectedArgInfo.None callerArgTy m argExpr - let action = BuildILFieldSet cenv.g m objExpr finfo argExpr - argExprPrebinder, action, Item.ILField finfo - - | AssignedRecdFieldSetter rfinfo -> - RecdFieldInstanceChecks cenv.g cenv.amap ad m rfinfo - let calledArgTy = rfinfo.FieldType - CheckRecdFieldMutation m denv rfinfo - let argExprPrebinder, argExpr = coerceExpr false calledArgTy ReflectedArgInfo.None callerArgTy m argExpr - let action = BuildRecdFieldSet cenv.g m objExpr rfinfo argExpr - argExprPrebinder, action, Item.RecdField rfinfo - - // Record the resolution for the Language Service - let item = Item.SetterArg (id, defnItem) - CallNameResolutionSink cenv.tcSink (id.idRange, env.NameEnv, item, item, emptyTyparInst, ItemOccurence.Use, env.DisplayEnv, ad) - - argExprPrebinder, mkCompGenSequential m acc action) - - // now put them together - let expr = mkCompGenLet mMethExpr objv expr (mkCompGenSequential mMethExpr propSetExpr objExpr) - setterExprPrebinders, expr - - // Build the lambda expression if any - let expr = + let setterExprPrebinders, callExpr3 = + let expr = callExpr2 + if isCheckingAttributeCall then + [], expr + elif isNil finalAssignedItemSetters then + [], expr + else + // This holds the result of the call + let objv, objExpr = mkMutableCompGenLocal mMethExpr "returnVal" exprty // mutable in case it's a struct + + // Build the expression that mutates the properties on the result of the call + let setterExprPrebinders, propSetExpr = + (mkUnit cenv.g mMethExpr, finalAssignedItemSetters) ||> List.mapFold (fun acc assignedItemSetter -> + let argExprPrebinder, action, m = TcSetterArgExpr cenv env denv objExpr ad assignedItemSetter + argExprPrebinder, mkCompGenSequential m acc action) + + // now put them together + let expr = mkCompGenLet mMethExpr objv expr (mkCompGenSequential mMethExpr propSetExpr objExpr) + setterExprPrebinders, expr + + // Build the lambda expression if any, if the method is used as a first-class value + let callExpr4 = + let expr = callExpr3 match lambdaVars with | None -> expr | Some curriedLambdaVars -> @@ -10382,7 +10096,8 @@ and TcMethodApplication | _ -> mkMultiLambda mMethExpr vs (expr, tyOfExpr cenv.g expr) List.foldBack mkLambda curriedLambdaVars expr - let expr, tpenv = + let callExpr5, tpenv = + let expr = callExpr4 match unnamedDelayedCallerArgExprOpt with | Some synArgExpr -> match lambdaVars with @@ -10395,15 +10110,53 @@ and TcMethodApplication expr, tpenv // Apply the PreBinders, if any - let expr = (expr, setterExprPrebinders) ||> List.fold (fun expr argPreBinder -> match argPreBinder with None -> expr | Some f -> f expr) - let expr = (expr, paramArrayPreBinders) ||> List.fold (fun expr argPreBinder -> match argPreBinder with None -> expr | Some f -> f expr) - let expr = (expr, allArgsPreBinders) ||> List.fold (fun expr argPreBinder -> match argPreBinder with None -> expr | Some f -> f expr) + let callExpr6 = + let expr = callExpr5 + let expr = (expr, setterExprPrebinders) ||> List.fold (fun expr argPreBinder -> match argPreBinder with None -> expr | Some f -> f expr) + let expr = (expr, paramArrayPreBinders) ||> List.fold (fun expr argPreBinder -> match argPreBinder with None -> expr | Some f -> f expr) + let expr = (expr, allArgsPreBinders) ||> List.fold (fun expr argPreBinder -> match argPreBinder with None -> expr | Some f -> f expr) - let expr = optArgPreBinder expr - let expr = objArgPreBinder expr + let expr = optArgPreBinder expr + let expr = objArgPreBinder expr + expr - (expr, finalAttributeAssignedNamedItems, delayed), tpenv + (callExpr6, finalAttributeAssignedNamedItems, delayed), tpenv +and TcSetterArgExpr cenv env denv objExpr ad (AssignedItemSetter(id, setter, CallerArg(callerArgTy, m, isOptCallerArg, argExpr))) = + if isOptCallerArg then error(Error(FSComp.SR.tcInvalidOptionalAssignmentToPropertyOrField(), m)) + + let argExprPrebinder, action, defnItem = + match setter with + | AssignedPropSetter (pinfo, pminfo, pminst) -> + MethInfoChecks cenv.g cenv.amap true None [objExpr] ad m pminfo + let calledArgTy = List.head (List.head (pminfo.GetParamTypes(cenv.amap, m, pminst))) + let argExprPrebinder, argExpr = MethodCalls.AdjustCallerArgExprForCoercions cenv.g cenv.amap cenv.infoReader ad false calledArgTy ReflectedArgInfo.None callerArgTy m argExpr + let mut = (if isStructTy cenv.g (tyOfExpr cenv.g objExpr) then DefinitelyMutates else PossiblyMutates) + let action = BuildPossiblyConditionalMethodCall cenv env mut m true pminfo NormalValUse pminst [objExpr] [argExpr] |> fst + argExprPrebinder, action, Item.Property (pinfo.PropertyName, [pinfo]) + + | AssignedILFieldSetter finfo -> + // Get or set instance IL field + ILFieldInstanceChecks cenv.g cenv.amap ad m finfo + let calledArgTy = finfo.FieldType (cenv.amap, m) + let argExprPrebinder, argExpr = MethodCalls.AdjustCallerArgExprForCoercions cenv.g cenv.amap cenv.infoReader ad false calledArgTy ReflectedArgInfo.None callerArgTy m argExpr + let action = BuildILFieldSet cenv.g m objExpr finfo argExpr + argExprPrebinder, action, Item.ILField finfo + + | AssignedRecdFieldSetter rfinfo -> + RecdFieldInstanceChecks cenv.g cenv.amap ad m rfinfo + let calledArgTy = rfinfo.FieldType + CheckRecdFieldMutation m denv rfinfo + let argExprPrebinder, argExpr = MethodCalls.AdjustCallerArgExprForCoercions cenv.g cenv.amap cenv.infoReader ad false calledArgTy ReflectedArgInfo.None callerArgTy m argExpr + let action = BuildRecdFieldSet cenv.g m objExpr rfinfo argExpr + argExprPrebinder, action, Item.RecdField rfinfo + + // Record the resolution for the Language Service + let item = Item.SetterArg (id, defnItem) + CallNameResolutionSink cenv.tcSink (id.idRange, env.NameEnv, item, item, emptyTyparInst, ItemOccurence.Use, env.DisplayEnv, ad) + + argExprPrebinder, action, m + and TcUnnamedMethodArgs cenv env lambdaPropagationInfo tpenv args = List.mapiFoldSquared (TcUnnamedMethodArg cenv env) (lambdaPropagationInfo, tpenv) args diff --git a/src/fsharp/xlf/FSComp.txt.es.xlf b/src/fsharp/xlf/FSComp.txt.es.xlf index 56f087fb38d..279d16a7c90 100644 --- a/src/fsharp/xlf/FSComp.txt.es.xlf +++ b/src/fsharp/xlf/FSComp.txt.es.xlf @@ -124,7 +124,7 @@ All branches of a pattern match expression must return values of the same type as the first branch, which here is '{0}'. This branch returns a value of type '{1}'. - Todas las ramas de una expresión de coincidencia de patrón deben devolver valores del mismo tipo. La primera rama devolvió un valor de tipo "{0}", pero esta rama devolvió un valor de tipo "\{1 \}". + All branches of a pattern match expression must return values of the same type as the first branch, which here is '{0}'. This branch returns a value of type '{1}'. diff --git a/tests/fsharp/core/fsfromfsviacs/lib3.cs b/tests/fsharp/core/fsfromfsviacs/lib3.cs index b688b710bc2..91a3dffe4bb 100644 --- a/tests/fsharp/core/fsfromfsviacs/lib3.cs +++ b/tests/fsharp/core/fsfromfsviacs/lib3.cs @@ -24,3 +24,29 @@ public static void SomeMethod() { } } } +namespace CSharpOptionalParameters +{ + // This should be preferred over the same type in lib2.cs + public class SomeClass + { + public SomeClass() { } + public static int MethodTakingOptionals(int x = 3, string y = "abc", double d = 5.0) + { + return x + y.Length + (int) d; + } + public static int MethodTakingNullableOptionalsWithDefaults(int? x = 3, string y = "abc", double? d = 5.0) + { + return (x.HasValue ? x.Value : -100) + y.Length + (int) (d.HasValue ? d.Value : 0.0); + } + public static int MethodTakingNullableOptionals(int? x = null, string y = null, double? d = null) + { + int length; + if (y == null) + length = -1; + else + length = y.Length; + return (x.HasValue ? x.Value : -1) + length + (int) (d.HasValue ? d.Value : -1.0); + } + } + +} diff --git a/tests/fsharp/core/fsfromfsviacs/test.fsx b/tests/fsharp/core/fsfromfsviacs/test.fsx index 76ec203112f..072a896c1eb 100644 --- a/tests/fsharp/core/fsfromfsviacs/test.fsx +++ b/tests/fsharp/core/fsfromfsviacs/test.fsx @@ -71,22 +71,53 @@ let _ = test "structunion394b36" (Lib.NestedStructUnionsTests.testPattern3mut(u2 // F# option implicit converter tests -let testFsOpt() = - let testOpt (t : 'T option) = - test (sprintf "fsimplicitconv (%A)" t) (ApiWrapper.ConsumeOptionalParam<'T>(t) = t) - - testOpt(Option.None) - testOpt(Some 42) - - // check that implicit conversion of optionals does - // differentiate between 'null' and 'Some null' - testOpt(Option.None) - testOpt(Option.Some null) - testOpt(Some "") - testOpt(Some "test") - -testFsOpt() - +module TestConsumeOptionalParameter = + let testFsOpt() = + let testOpt (t : 'T option) = + test (sprintf "fsimplicitconv (%A)" t) (ApiWrapper.ConsumeOptionalParam<'T>(t) = t) + + testOpt(Option.None) + testOpt(Some 42) + + // check that implicit conversion of optionals does + // differentiate between 'null' and 'Some null' + testOpt(Option.None) + testOpt(Option.Some null) + testOpt(Some "") + testOpt(Some "test") + + testFsOpt() + +module TestConsumeCSharpOptionalParameter = + open System + open CSharpOptionalParameters + check "csoptional23982f31" (SomeClass.MethodTakingOptionals()) 11 + check "csoptional23982f32" (SomeClass.MethodTakingOptionals(x = 6)) 14 + check "csoptional23982f33" (SomeClass.MethodTakingOptionals(y = "aaaaaa")) 14 + check "csoptional23982f34" (SomeClass.MethodTakingOptionals(d = 8.0)) 14 + + check "csoptional23982f41" (SomeClass.MethodTakingNullableOptionalsWithDefaults()) 11 + check "csoptional23982f42" (SomeClass.MethodTakingNullableOptionalsWithDefaults(x = Nullable 6)) 14 + check "csoptional23982f43" (SomeClass.MethodTakingNullableOptionalsWithDefaults(y = "aaaaaa")) 14 + check "csoptional23982f44" (SomeClass.MethodTakingNullableOptionalsWithDefaults(d = Nullable 8.0)) 14 + + check "csoptional23982f51" (SomeClass.MethodTakingNullableOptionals()) -3 + check "csoptional23982f52" (SomeClass.MethodTakingNullableOptionals(x = Nullable 6)) 4 + check "csoptional23982f53" (SomeClass.MethodTakingNullableOptionals(y = "aaaaaa")) 4 + check "csoptional23982f54" (SomeClass.MethodTakingNullableOptionals(d = Nullable 8.0)) 6 + + // These require https://github.com/fsharp/fslang-suggestions/issues/774 to be implemented + //check "csoptional23982f3no" (SomeClass.SomeMethod(?x = Some 6)) 14 + //check "csoptional23982f3no" (SomeClass.SomeMethod(?y = Some "aaaaaa")) 14 + //check "csoptional23982f3no" (SomeClass.SomeMethod(?d = Some 8.0)) 14 + //check "csoptional23982f3no" (SomeClass.SomeMethod(?x = None)) 11 + //check "csoptional23982f3no" (SomeClass.SomeMethod(?y = None)) 11 + //check "csoptional23982f3no" (SomeClass.SomeMethod(?d = None)) 11 + + //check "csoptional23982f42" (SomeClass.MethodTakingNullableOptionalsWithDefaults(x = 6)) 14 + //check "csoptional23982f44" (SomeClass.MethodTakingNullableOptionalsWithDefaults(d = 8.0)) 14 + //check "csoptional23982f52" (SomeClass.MethodTakingNullableOptionals(x = 6)) 4 + //check "csoptional23982f54" (SomeClass.MethodTakingNullableOptionals(d = 8.0)) 6 module NestedStructPatternMatchingAcrossAssemblyBoundaries = open Lib.NestedStructUnionsTests diff --git a/vsintegration/src/FSharp.ProjectSystem.PropertyPages/Resources/xlf/Microsoft.VisualStudio.Editors.Designer.cs.xlf b/vsintegration/src/FSharp.ProjectSystem.PropertyPages/Resources/xlf/Microsoft.VisualStudio.Editors.Designer.cs.xlf index a678a4bcfeb..860555f3440 100644 --- a/vsintegration/src/FSharp.ProjectSystem.PropertyPages/Resources/xlf/Microsoft.VisualStudio.Editors.Designer.cs.xlf +++ b/vsintegration/src/FSharp.ProjectSystem.PropertyPages/Resources/xlf/Microsoft.VisualStudio.Editors.Designer.cs.xlf @@ -1828,8 +1828,9 @@ CONSIDER: get this from CodeDom {0} x {1} - {0} x {1} + {0} x {1} Format string for showing a graphic's size + # {0} = width (as an integer) # {1} = height (as an integer) #Example, for a bitmap of width=123, height = 456, the English version of this string would be "123x456" diff --git a/vsintegration/src/FSharp.ProjectSystem.PropertyPages/Resources/xlf/Microsoft.VisualStudio.Editors.Designer.de.xlf b/vsintegration/src/FSharp.ProjectSystem.PropertyPages/Resources/xlf/Microsoft.VisualStudio.Editors.Designer.de.xlf index 662133483e3..65b4328fdc2 100644 --- a/vsintegration/src/FSharp.ProjectSystem.PropertyPages/Resources/xlf/Microsoft.VisualStudio.Editors.Designer.de.xlf +++ b/vsintegration/src/FSharp.ProjectSystem.PropertyPages/Resources/xlf/Microsoft.VisualStudio.Editors.Designer.de.xlf @@ -1828,8 +1828,9 @@ CONSIDER: get this from CodeDom {0} x {1} - {0} x {1} + {0} x {1} Format string for showing a graphic's size + # {0} = width (as an integer) # {1} = height (as an integer) #Example, for a bitmap of width=123, height = 456, the English version of this string would be "123x456" diff --git a/vsintegration/src/FSharp.ProjectSystem.PropertyPages/Resources/xlf/Microsoft.VisualStudio.Editors.Designer.es.xlf b/vsintegration/src/FSharp.ProjectSystem.PropertyPages/Resources/xlf/Microsoft.VisualStudio.Editors.Designer.es.xlf index 41dbc88f0bd..1153755c3dd 100644 --- a/vsintegration/src/FSharp.ProjectSystem.PropertyPages/Resources/xlf/Microsoft.VisualStudio.Editors.Designer.es.xlf +++ b/vsintegration/src/FSharp.ProjectSystem.PropertyPages/Resources/xlf/Microsoft.VisualStudio.Editors.Designer.es.xlf @@ -1828,8 +1828,9 @@ CONSIDER: get this from CodeDom {0} x {1} - {0} x {1} + {0} x {1} Format string for showing a graphic's size + # {0} = width (as an integer) # {1} = height (as an integer) #Example, for a bitmap of width=123, height = 456, the English version of this string would be "123x456" diff --git a/vsintegration/src/FSharp.ProjectSystem.PropertyPages/Resources/xlf/Microsoft.VisualStudio.Editors.Designer.fr.xlf b/vsintegration/src/FSharp.ProjectSystem.PropertyPages/Resources/xlf/Microsoft.VisualStudio.Editors.Designer.fr.xlf index 0f1e16e95f2..cd60e9f07e9 100644 --- a/vsintegration/src/FSharp.ProjectSystem.PropertyPages/Resources/xlf/Microsoft.VisualStudio.Editors.Designer.fr.xlf +++ b/vsintegration/src/FSharp.ProjectSystem.PropertyPages/Resources/xlf/Microsoft.VisualStudio.Editors.Designer.fr.xlf @@ -1828,8 +1828,9 @@ CONSIDER: get this from CodeDom {0} x {1} - {0} x {1} + {0} x {1} Format string for showing a graphic's size + # {0} = width (as an integer) # {1} = height (as an integer) #Example, for a bitmap of width=123, height = 456, the English version of this string would be "123x456" diff --git a/vsintegration/src/FSharp.ProjectSystem.PropertyPages/Resources/xlf/Microsoft.VisualStudio.Editors.Designer.it.xlf b/vsintegration/src/FSharp.ProjectSystem.PropertyPages/Resources/xlf/Microsoft.VisualStudio.Editors.Designer.it.xlf index 8902030751c..dd58cb9a119 100644 --- a/vsintegration/src/FSharp.ProjectSystem.PropertyPages/Resources/xlf/Microsoft.VisualStudio.Editors.Designer.it.xlf +++ b/vsintegration/src/FSharp.ProjectSystem.PropertyPages/Resources/xlf/Microsoft.VisualStudio.Editors.Designer.it.xlf @@ -1828,8 +1828,9 @@ CONSIDER: get this from CodeDom {0} x {1} - {0} x {1} + {0} x {1} Format string for showing a graphic's size + # {0} = width (as an integer) # {1} = height (as an integer) #Example, for a bitmap of width=123, height = 456, the English version of this string would be "123x456" diff --git a/vsintegration/src/FSharp.ProjectSystem.PropertyPages/Resources/xlf/Microsoft.VisualStudio.Editors.Designer.ja.xlf b/vsintegration/src/FSharp.ProjectSystem.PropertyPages/Resources/xlf/Microsoft.VisualStudio.Editors.Designer.ja.xlf index a39e49dfa0d..bdb896a5c83 100644 --- a/vsintegration/src/FSharp.ProjectSystem.PropertyPages/Resources/xlf/Microsoft.VisualStudio.Editors.Designer.ja.xlf +++ b/vsintegration/src/FSharp.ProjectSystem.PropertyPages/Resources/xlf/Microsoft.VisualStudio.Editors.Designer.ja.xlf @@ -1828,8 +1828,9 @@ CONSIDER: get this from CodeDom {0} x {1} - {0} x {1} + {0} x {1} Format string for showing a graphic's size + # {0} = width (as an integer) # {1} = height (as an integer) #Example, for a bitmap of width=123, height = 456, the English version of this string would be "123x456" diff --git a/vsintegration/src/FSharp.ProjectSystem.PropertyPages/Resources/xlf/Microsoft.VisualStudio.Editors.Designer.ko.xlf b/vsintegration/src/FSharp.ProjectSystem.PropertyPages/Resources/xlf/Microsoft.VisualStudio.Editors.Designer.ko.xlf index e7191ac3c4a..6f540b54250 100644 --- a/vsintegration/src/FSharp.ProjectSystem.PropertyPages/Resources/xlf/Microsoft.VisualStudio.Editors.Designer.ko.xlf +++ b/vsintegration/src/FSharp.ProjectSystem.PropertyPages/Resources/xlf/Microsoft.VisualStudio.Editors.Designer.ko.xlf @@ -1828,8 +1828,9 @@ CONSIDER: get this from CodeDom {0} x {1} - {0} x {1} + {0} x {1} Format string for showing a graphic's size + # {0} = width (as an integer) # {1} = height (as an integer) #Example, for a bitmap of width=123, height = 456, the English version of this string would be "123x456" diff --git a/vsintegration/src/FSharp.ProjectSystem.PropertyPages/Resources/xlf/Microsoft.VisualStudio.Editors.Designer.pl.xlf b/vsintegration/src/FSharp.ProjectSystem.PropertyPages/Resources/xlf/Microsoft.VisualStudio.Editors.Designer.pl.xlf index d0675bd2fcb..73bef853b9f 100644 --- a/vsintegration/src/FSharp.ProjectSystem.PropertyPages/Resources/xlf/Microsoft.VisualStudio.Editors.Designer.pl.xlf +++ b/vsintegration/src/FSharp.ProjectSystem.PropertyPages/Resources/xlf/Microsoft.VisualStudio.Editors.Designer.pl.xlf @@ -1828,8 +1828,9 @@ CONSIDER: get this from CodeDom {0} x {1} - {0} x {1} + {0} x {1} Format string for showing a graphic's size + # {0} = width (as an integer) # {1} = height (as an integer) #Example, for a bitmap of width=123, height = 456, the English version of this string would be "123x456" diff --git a/vsintegration/src/FSharp.ProjectSystem.PropertyPages/Resources/xlf/Microsoft.VisualStudio.Editors.Designer.pt-BR.xlf b/vsintegration/src/FSharp.ProjectSystem.PropertyPages/Resources/xlf/Microsoft.VisualStudio.Editors.Designer.pt-BR.xlf index acfade88845..3e8a1693485 100644 --- a/vsintegration/src/FSharp.ProjectSystem.PropertyPages/Resources/xlf/Microsoft.VisualStudio.Editors.Designer.pt-BR.xlf +++ b/vsintegration/src/FSharp.ProjectSystem.PropertyPages/Resources/xlf/Microsoft.VisualStudio.Editors.Designer.pt-BR.xlf @@ -1828,8 +1828,9 @@ CONSIDER: get this from CodeDom {0} x {1} - {0} x {1} + {0} x {1} Format string for showing a graphic's size + # {0} = width (as an integer) # {1} = height (as an integer) #Example, for a bitmap of width=123, height = 456, the English version of this string would be "123x456" diff --git a/vsintegration/src/FSharp.ProjectSystem.PropertyPages/Resources/xlf/Microsoft.VisualStudio.Editors.Designer.ru.xlf b/vsintegration/src/FSharp.ProjectSystem.PropertyPages/Resources/xlf/Microsoft.VisualStudio.Editors.Designer.ru.xlf index 355d363084e..2b5303d91de 100644 --- a/vsintegration/src/FSharp.ProjectSystem.PropertyPages/Resources/xlf/Microsoft.VisualStudio.Editors.Designer.ru.xlf +++ b/vsintegration/src/FSharp.ProjectSystem.PropertyPages/Resources/xlf/Microsoft.VisualStudio.Editors.Designer.ru.xlf @@ -1828,8 +1828,9 @@ CONSIDER: get this from CodeDom {0} x {1} - {0} x {1} + {0} x {1} Format string for showing a graphic's size + # {0} = width (as an integer) # {1} = height (as an integer) #Example, for a bitmap of width=123, height = 456, the English version of this string would be "123x456" diff --git a/vsintegration/src/FSharp.ProjectSystem.PropertyPages/Resources/xlf/Microsoft.VisualStudio.Editors.Designer.tr.xlf b/vsintegration/src/FSharp.ProjectSystem.PropertyPages/Resources/xlf/Microsoft.VisualStudio.Editors.Designer.tr.xlf index 86ac32f4b37..73a72b806a2 100644 --- a/vsintegration/src/FSharp.ProjectSystem.PropertyPages/Resources/xlf/Microsoft.VisualStudio.Editors.Designer.tr.xlf +++ b/vsintegration/src/FSharp.ProjectSystem.PropertyPages/Resources/xlf/Microsoft.VisualStudio.Editors.Designer.tr.xlf @@ -1828,8 +1828,9 @@ CONSIDER: get this from CodeDom {0} x {1} - {0} x {1} + {0} x {1} Format string for showing a graphic's size + # {0} = width (as an integer) # {1} = height (as an integer) #Example, for a bitmap of width=123, height = 456, the English version of this string would be "123x456" diff --git a/vsintegration/src/FSharp.ProjectSystem.PropertyPages/Resources/xlf/Microsoft.VisualStudio.Editors.Designer.zh-Hans.xlf b/vsintegration/src/FSharp.ProjectSystem.PropertyPages/Resources/xlf/Microsoft.VisualStudio.Editors.Designer.zh-Hans.xlf index 0537632d5fc..474f99a3dcd 100644 --- a/vsintegration/src/FSharp.ProjectSystem.PropertyPages/Resources/xlf/Microsoft.VisualStudio.Editors.Designer.zh-Hans.xlf +++ b/vsintegration/src/FSharp.ProjectSystem.PropertyPages/Resources/xlf/Microsoft.VisualStudio.Editors.Designer.zh-Hans.xlf @@ -1828,8 +1828,9 @@ CONSIDER: get this from CodeDom {0} x {1} - {0} x {1} + {0} x {1} Format string for showing a graphic's size + # {0} = width (as an integer) # {1} = height (as an integer) #Example, for a bitmap of width=123, height = 456, the English version of this string would be "123x456" diff --git a/vsintegration/src/FSharp.ProjectSystem.PropertyPages/Resources/xlf/Microsoft.VisualStudio.Editors.Designer.zh-Hant.xlf b/vsintegration/src/FSharp.ProjectSystem.PropertyPages/Resources/xlf/Microsoft.VisualStudio.Editors.Designer.zh-Hant.xlf index 17c64ffefb9..16b7339b2a4 100644 --- a/vsintegration/src/FSharp.ProjectSystem.PropertyPages/Resources/xlf/Microsoft.VisualStudio.Editors.Designer.zh-Hant.xlf +++ b/vsintegration/src/FSharp.ProjectSystem.PropertyPages/Resources/xlf/Microsoft.VisualStudio.Editors.Designer.zh-Hant.xlf @@ -1828,8 +1828,9 @@ CONSIDER: get this from CodeDom {0} x {1} - {0} x {1} + {0} x {1} Format string for showing a graphic's size + # {0} = width (as an integer) # {1} = height (as an integer) #Example, for a bitmap of width=123, height = 456, the English version of this string would be "123x456" From e72ded1638bf17f7310c2b0080dc38edceedea1f Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Sat, 27 Jul 2019 11:26:05 -0700 Subject: [PATCH 2/7] Update dependencies from https://github.com/dotnet/arcade build 20190726.18 (#7285) - Microsoft.DotNet.Arcade.Sdk - 1.0.0-beta.19376.18 --- eng/Version.Details.xml | 4 +- eng/common/post-build/darc-gather-drop.ps1 | 17 ++-- eng/common/post-build/nuget-validation.ps1 | 5 +- eng/common/post-build/post-build-utils.ps1 | 90 +++++++++++++++++++ eng/common/post-build/promote-build.ps1 | 37 ++++---- eng/common/post-build/setup-maestro-vars.ps1 | 26 ++++++ .../post-build/sourcelink-validation.ps1 | 31 ++++--- eng/common/post-build/symbols-validation.ps1 | 29 +++--- .../post-build/trigger-subscriptions.ps1 | 48 ++++------ .../channels/internal-servicing.yml | 5 +- .../channels/public-dev-release.yml | 5 +- .../post-build/channels/public-release.yml | 5 +- .../channels/public-validation-release.yml | 9 +- .../templates/post-build/common-variables.yml | 34 +++++-- .../templates/post-build/darc-gather-drop.yml | 5 +- .../templates/post-build/post-build.yml | 5 +- .../templates/post-build/promote-build.yml | 5 +- .../post-build/setup-maestro-vars.yml | 21 +---- .../post-build/trigger-subscription.yml | 4 +- global.json | 2 +- 20 files changed, 246 insertions(+), 141 deletions(-) create mode 100644 eng/common/post-build/post-build-utils.ps1 create mode 100644 eng/common/post-build/setup-maestro-vars.ps1 diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 7a0a634b410..0893278ac13 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -3,9 +3,9 @@ - + https://github.com/dotnet/arcade - ef1c110152df0d500fffb87878a86f88d1ca5295 + 316481e57ee5e6acbbf2401eb6778a1d3d48d25b diff --git a/eng/common/post-build/darc-gather-drop.ps1 b/eng/common/post-build/darc-gather-drop.ps1 index 9cc2f1a0091..93a0bd83285 100644 --- a/eng/common/post-build/darc-gather-drop.ps1 +++ b/eng/common/post-build/darc-gather-drop.ps1 @@ -1,13 +1,12 @@ param( - [Parameter(Mandatory=$true)][string] $BarBuildId, # ID of the build which assets should be downloaded - [Parameter(Mandatory=$true)][string] $MaestroAccessToken, # Token used to access Maestro API - [Parameter(Mandatory=$true)][string] $DropLocation # Where the assets should be downloaded to + [Parameter(Mandatory=$true)][int] $BarBuildId, # ID of the build which assets should be downloaded + [Parameter(Mandatory=$true)][string] $DropLocation, # Where the assets should be downloaded to + [Parameter(Mandatory=$true)][string] $MaestroApiAccessToken, # Token used to access Maestro API + [Parameter(Mandatory=$false)][string] $MaestroApiEndPoint = "https://maestro-prod.westus2.cloudapp.azure.com", # Maestro API URL + [Parameter(Mandatory=$false)][string] $MaestroApiVersion = "2019-01-16" # Version of Maestro API to use ) -$ErrorActionPreference = "Stop" -Set-StrictMode -Version 2.0 - -. $PSScriptRoot\..\tools.ps1 +. $PSScriptRoot\post-build-utils.ps1 try { Write-Host "Installing DARC ..." @@ -24,8 +23,8 @@ try { --continue-on-error ` --id $BarBuildId ` --output-dir $DropLocation ` - --bar-uri https://maestro-prod.westus2.cloudapp.azure.com/ ` - --password $MaestroAccessToken ` + --bar-uri $MaestroApiEndpoint ` + --password $MaestroApiAccessToken ` --latest-location } catch { diff --git a/eng/common/post-build/nuget-validation.ps1 b/eng/common/post-build/nuget-validation.ps1 index 1bdced1e307..78ed0d540f5 100644 --- a/eng/common/post-build/nuget-validation.ps1 +++ b/eng/common/post-build/nuget-validation.ps1 @@ -6,10 +6,7 @@ param( [Parameter(Mandatory=$true)][string] $ToolDestinationPath # Where the validation tool should be downloaded to ) -$ErrorActionPreference = "Stop" -Set-StrictMode -Version 2.0 - -. $PSScriptRoot\..\tools.ps1 +. $PSScriptRoot\post-build-utils.ps1 try { $url = "https://raw.githubusercontent.com/NuGet/NuGetGallery/jver-verify/src/VerifyMicrosoftPackage/verify.ps1" diff --git a/eng/common/post-build/post-build-utils.ps1 b/eng/common/post-build/post-build-utils.ps1 new file mode 100644 index 00000000000..551ae113f89 --- /dev/null +++ b/eng/common/post-build/post-build-utils.ps1 @@ -0,0 +1,90 @@ +# Most of the functions in this file require the variables `MaestroApiEndPoint`, +# `MaestroApiVersion` and `MaestroApiAccessToken` to be globally available. + +$ErrorActionPreference = "Stop" +Set-StrictMode -Version 2.0 + +# `tools.ps1` checks $ci to perform some actions. Since the post-build +# scripts don't necessarily execute in the same agent that run the +# build.ps1/sh script this variable isn't automatically set. +$ci = $true +. $PSScriptRoot\..\tools.ps1 + +function Create-MaestroApiRequestHeaders([string]$ContentType = "application/json") { + Validate-MaestroVars + + $headers = New-Object 'System.Collections.Generic.Dictionary[[String],[String]]' + $headers.Add('Accept', $ContentType) + $headers.Add('Authorization',"Bearer $MaestroApiAccessToken") + return $headers +} + +function Get-MaestroChannel([int]$ChannelId) { + Validate-MaestroVars + + $apiHeaders = Create-MaestroApiRequestHeaders + $apiEndpoint = "$MaestroApiEndPoint/api/channels/${ChannelId}?api-version=$MaestroApiVersion" + + $result = try { Invoke-WebRequest -Method Get -Uri $apiEndpoint -Headers $apiHeaders | ConvertFrom-Json } catch { Write-Host "Error: $_" } + return $result +} + +function Get-MaestroBuild([int]$BuildId) { + Validate-MaestroVars + + $apiHeaders = Create-MaestroApiRequestHeaders -AuthToken $MaestroApiAccessToken + $apiEndpoint = "$MaestroApiEndPoint/api/builds/${BuildId}?api-version=$MaestroApiVersion" + + $result = try { return Invoke-WebRequest -Method Get -Uri $apiEndpoint -Headers $apiHeaders | ConvertFrom-Json } catch { Write-Host "Error: $_" } + return $result +} + +function Get-MaestroSubscriptions([string]$SourceRepository, [int]$ChannelId) { + Validate-MaestroVars + + $SourceRepository = [System.Web.HttpUtility]::UrlEncode($SourceRepository) + $apiHeaders = Create-MaestroApiRequestHeaders -AuthToken $MaestroApiAccessToken + $apiEndpoint = "$MaestroApiEndPoint/api/subscriptions?sourceRepository=$SourceRepository&channelId=$ChannelId&api-version=$MaestroApiVersion" + + $result = try { Invoke-WebRequest -Method Get -Uri $apiEndpoint -Headers $apiHeaders | ConvertFrom-Json } catch { Write-Host "Error: $_" } + return $result +} + +function Trigger-Subscription([string]$SubscriptionId) { + Validate-MaestroVars + + $apiHeaders = Create-MaestroApiRequestHeaders -AuthToken $MaestroApiAccessToken + $apiEndpoint = "$MaestroApiEndPoint/api/subscriptions/$SubscriptionId/trigger?api-version=$MaestroApiVersion" + Invoke-WebRequest -Uri $apiEndpoint -Headers $apiHeaders -Method Post | Out-Null +} + +function Assign-BuildToChannel([int]$BuildId, [int]$ChannelId) { + Validate-MaestroVars + + $apiHeaders = Create-MaestroApiRequestHeaders -AuthToken $MaestroApiAccessToken + $apiEndpoint = "$MaestroApiEndPoint/api/channels/${ChannelId}/builds/${BuildId}?api-version=$MaestroApiVersion" + Invoke-WebRequest -Method Post -Uri $apiEndpoint -Headers $apiHeaders | Out-Null +} + +function Validate-MaestroVars { + try { + Get-Variable MaestroApiEndPoint -Scope Global | Out-Null + Get-Variable MaestroApiVersion -Scope Global | Out-Null + Get-Variable MaestroApiAccessToken -Scope Global | Out-Null + + if (!($MaestroApiEndPoint -Match "^http[s]?://maestro-(int|prod).westus2.cloudapp.azure.com$")) { + Write-PipelineTaskError "MaestroApiEndPoint is not a valid Maestro URL. '$MaestroApiEndPoint'" + ExitWithExitCode 1 + } + + if (!($MaestroApiVersion -Match "^[0-9]{4}-[0-9]{2}-[0-9]{2}$")) { + Write-PipelineTaskError "MaestroApiVersion does not match a version string in the format yyyy-MM-DD. '$MaestroApiVersion'" + ExitWithExitCode 1 + } + } + catch { + Write-PipelineTaskError "Error: Variables `MaestroApiEndPoint`, `MaestroApiVersion` and `MaestroApiAccessToken` are required while using this script." + Write-Host $_ + ExitWithExitCode 1 + } +} diff --git a/eng/common/post-build/promote-build.ps1 b/eng/common/post-build/promote-build.ps1 index 84a608fa569..e5ae85f2517 100644 --- a/eng/common/post-build/promote-build.ps1 +++ b/eng/common/post-build/promote-build.ps1 @@ -1,30 +1,25 @@ param( [Parameter(Mandatory=$true)][int] $BuildId, [Parameter(Mandatory=$true)][int] $ChannelId, - [Parameter(Mandatory=$true)][string] $BarToken, - [string] $MaestroEndpoint = "https://maestro-prod.westus2.cloudapp.azure.com", - [string] $ApiVersion = "2019-01-16" + [Parameter(Mandatory=$true)][string] $MaestroApiAccessToken, + [Parameter(Mandatory=$false)][string] $MaestroApiEndPoint = "https://maestro-prod.westus2.cloudapp.azure.com", + [Parameter(Mandatory=$false)][string] $MaestroApiVersion = "2019-01-16" ) -$ErrorActionPreference = "Stop" -Set-StrictMode -Version 2.0 - -. $PSScriptRoot\..\tools.ps1 - -function Get-Headers([string]$accept, [string]$barToken) { - $headers = New-Object 'System.Collections.Generic.Dictionary[[String],[String]]' - $headers.Add('Accept',$accept) - $headers.Add('Authorization',"Bearer $barToken") - return $headers -} +. $PSScriptRoot\post-build-utils.ps1 try { - $maestroHeaders = Get-Headers 'application/json' $BarToken + # Check that the channel we are going to promote the build to exist + $channelInfo = Get-MaestroChannel -ChannelId $ChannelId - # Get info about which channels the build has already been promoted to - $getBuildApiEndpoint = "$MaestroEndpoint/api/builds/${BuildId}?api-version=$ApiVersion" - $buildInfo = Invoke-WebRequest -Method Get -Uri $getBuildApiEndpoint -Headers $maestroHeaders | ConvertFrom-Json + if (!$channelInfo) { + Write-Host "Channel with BAR ID $ChannelId was not found in BAR!" + ExitWithExitCode 1 + } + # Get info about which channels the build has already been promoted to + $buildInfo = Get-MaestroBuild -BuildId $BuildId + if (!$buildInfo) { Write-Host "Build with BAR ID $BuildId was not found in BAR!" ExitWithExitCode 1 @@ -40,10 +35,10 @@ try { } } - Write-Host "Build not present in channel $ChannelId. Promoting build ... " + Write-Host "Promoting build '$BuildId' to channel '$ChannelId'." + + Assign-BuildToChannel -BuildId $BuildId -ChannelId $ChannelId - $promoteBuildApiEndpoint = "$maestroEndpoint/api/channels/${ChannelId}/builds/${BuildId}?api-version=$ApiVersion" - Invoke-WebRequest -Method Post -Uri $promoteBuildApiEndpoint -Headers $maestroHeaders Write-Host "done." } catch { diff --git a/eng/common/post-build/setup-maestro-vars.ps1 b/eng/common/post-build/setup-maestro-vars.ps1 new file mode 100644 index 00000000000..d7f64dc63cb --- /dev/null +++ b/eng/common/post-build/setup-maestro-vars.ps1 @@ -0,0 +1,26 @@ +param( + [Parameter(Mandatory=$true)][string] $ReleaseConfigsPath # Full path to ReleaseConfigs.txt asset +) + +. $PSScriptRoot\post-build-utils.ps1 + +try { + $Content = Get-Content $ReleaseConfigsPath + + $BarId = $Content | Select -Index 0 + + $Channels = "" + $Content | Select -Index 1 | ForEach-Object { $Channels += "$_ ," } + + $IsStableBuild = $Content | Select -Index 2 + + Write-PipelineSetVariable -Name 'BARBuildId' -Value $BarId + Write-PipelineSetVariable -Name 'InitialChannels' -Value "$Channels" + Write-PipelineSetVariable -Name 'IsStableBuild' -Value $IsStableBuild +} +catch { + Write-Host $_ + Write-Host $_.Exception + Write-Host $_.ScriptStackTrace + ExitWithExitCode 1 +} diff --git a/eng/common/post-build/sourcelink-validation.ps1 b/eng/common/post-build/sourcelink-validation.ps1 index 8abd684e9e5..41e01ae6e67 100644 --- a/eng/common/post-build/sourcelink-validation.ps1 +++ b/eng/common/post-build/sourcelink-validation.ps1 @@ -6,10 +6,7 @@ param( [Parameter(Mandatory=$true)][string] $SourcelinkCliVersion # Version of SourceLink CLI to use ) -$ErrorActionPreference = "Stop" -Set-StrictMode -Version 2.0 - -. $PSScriptRoot\..\tools.ps1 +. $PSScriptRoot\post-build-utils.ps1 # Cache/HashMap (File -> Exist flag) used to consult whether a file exist # in the repository at a specific commit point. This is populated by inserting @@ -200,21 +197,27 @@ function ValidateSourceLinkLinks { } } -function CheckExitCode ([string]$stage) { - $exitCode = $LASTEXITCODE - if ($exitCode -ne 0) { - Write-PipelineTaskError "Something failed while '$stage'. Check for errors above. Exiting now..." - ExitWithExitCode $exitCode +function InstallSourcelinkCli { + $sourcelinkCliPackageName = "sourcelink" + + $dotnetRoot = InitializeDotNetCli -install:$true + $dotnet = "$dotnetRoot\dotnet.exe" + $toolList = & "$dotnet" tool list --global + + if (($toolList -like "*$sourcelinkCliPackageName*") -and ($toolList -like "*$sourcelinkCliVersion*")) { + Write-Host "SourceLink CLI version $sourcelinkCliVersion is already installed." + } + else { + Write-Host "Installing SourceLink CLI version $sourcelinkCliVersion..." + Write-Host "You may need to restart your command window if this is the first dotnet tool you have installed." + & "$dotnet" tool install $sourcelinkCliPackageName --version $sourcelinkCliVersion --verbosity "minimal" --global } } try { - Write-Host "Installing SourceLink CLI..." - Get-Location - . $PSScriptRoot\sourcelink-cli-init.ps1 -sourcelinkCliVersion $SourcelinkCliVersion - CheckExitCode "Running sourcelink-cli-init" + InstallSourcelinkCli - Measure-Command { ValidateSourceLinkLinks } + ValidateSourceLinkLinks } catch { Write-Host $_ diff --git a/eng/common/post-build/symbols-validation.ps1 b/eng/common/post-build/symbols-validation.ps1 index 69456854e04..d5ec51b150f 100644 --- a/eng/common/post-build/symbols-validation.ps1 +++ b/eng/common/post-build/symbols-validation.ps1 @@ -4,10 +4,7 @@ param( [Parameter(Mandatory=$true)][string] $DotnetSymbolVersion # Version of dotnet symbol to use ) -$ErrorActionPreference = "Stop" -Set-StrictMode -Version 2.0 - -. $PSScriptRoot\..\tools.ps1 +. $PSScriptRoot\post-build-utils.ps1 Add-Type -AssemblyName System.IO.Compression.FileSystem @@ -162,19 +159,25 @@ function CheckSymbolsAvailable { } } -function CheckExitCode ([string]$stage) { - $exitCode = $LASTEXITCODE - if ($exitCode -ne 0) { - Write-PipelineTaskError "Something failed while '$stage'. Check for errors above. Exiting now..." - ExitWithExitCode $exitCode +function Installdotnetsymbol { + $dotnetsymbolPackageName = "dotnet-symbol" + + $dotnetRoot = InitializeDotNetCli -install:$true + $dotnet = "$dotnetRoot\dotnet.exe" + $toolList = & "$dotnet" tool list --global + + if (($toolList -like "*$dotnetsymbolPackageName*") -and ($toolList -like "*$dotnetsymbolVersion*")) { + Write-Host "dotnet-symbol version $dotnetsymbolVersion is already installed." + } + else { + Write-Host "Installing dotnet-symbol version $dotnetsymbolVersion..." + Write-Host "You may need to restart your command window if this is the first dotnet tool you have installed." + & "$dotnet" tool install $dotnetsymbolPackageName --version $dotnetsymbolVersion --verbosity "minimal" --global } } try { - Write-Host "Installing dotnet symbol ..." - Get-Location - . $PSScriptRoot\dotnetsymbol-init.ps1 -dotnetsymbolVersion $DotnetSymbolVersion - CheckExitCode "Running dotnetsymbol-init" + Installdotnetsymbol CheckSymbolsAvailable } diff --git a/eng/common/post-build/trigger-subscriptions.ps1 b/eng/common/post-build/trigger-subscriptions.ps1 index 1a91dab0371..926d5b45513 100644 --- a/eng/common/post-build/trigger-subscriptions.ps1 +++ b/eng/common/post-build/trigger-subscriptions.ps1 @@ -1,33 +1,20 @@ -param( +param( [Parameter(Mandatory=$true)][string] $SourceRepo, [Parameter(Mandatory=$true)][int] $ChannelId, - [string] $MaestroEndpoint = "https://maestro-prod.westus2.cloudapp.azure.com", - [string] $BarToken, - [string] $ApiVersion = "2019-01-16" + [Parameter(Mandatory=$true)][string] $MaestroApiAccessToken, + [Parameter(Mandatory=$false)][string] $MaestroApiEndPoint = "https://maestro-prod.westus2.cloudapp.azure.com", + [Parameter(Mandatory=$false)][string] $MaestroApiVersion = "2019-01-16" ) -$ErrorActionPreference = "Stop" -Set-StrictMode -Version 2.0 - -. $PSScriptRoot\..\tools.ps1 - -function Get-Headers([string]$accept, [string]$barToken) { - $headers = New-Object 'System.Collections.Generic.Dictionary[[String],[String]]' - $headers.Add('Accept',$accept) - $headers.Add('Authorization',"Bearer $barToken") - return $headers -} +. $PSScriptRoot\post-build-utils.ps1 # Get all the $SourceRepo subscriptions $normalizedSourceRepo = $SourceRepo.Replace('dnceng@', '') -$getSubscriptionsApiEndpoint = "$maestroEndpoint/api/subscriptions?sourceRepository=$normalizedSourceRepo&api-version=$apiVersion" -$headers = Get-Headers 'application/json' $barToken - -$subscriptions = Invoke-WebRequest -Uri $getSubscriptionsApiEndpoint -Headers $headers | ConvertFrom-Json +$subscriptions = Get-MaestroSubscriptions -SourceRepository $normalizedSourceRepo -ChannelId $ChannelId if (!$subscriptions) { Write-Host "No subscriptions found for source repo '$normalizedSourceRepo' in channel '$ChannelId'" - return + ExitWithExitCode 0 } $subscriptionsToTrigger = New-Object System.Collections.Generic.List[string] @@ -36,21 +23,18 @@ $failedTriggeredSubscription = $false # Get all enabled subscriptions that need dependency flow on 'everyBuild' foreach ($subscription in $subscriptions) { if ($subscription.enabled -and $subscription.policy.updateFrequency -like 'everyBuild' -and $subscription.channel.id -eq $ChannelId) { - Write-Host "$subscription.id" + Write-Host "Should trigger this subscription: $subscription.id" [void]$subscriptionsToTrigger.Add($subscription.id) } } foreach ($subscriptionToTrigger in $subscriptionsToTrigger) { try { - $triggerSubscriptionApiEndpoint = "$maestroEndpoint/api/subscriptions/$subscriptionToTrigger/trigger?api-version=$apiVersion" - $headers = Get-Headers 'application/json' $BarToken - - Write-Host "Triggering subscription '$subscriptionToTrigger'..." + Write-Host "Triggering subscription '$subscriptionToTrigger'." - Invoke-WebRequest -Uri $triggerSubscriptionApiEndpoint -Headers $headers -Method Post + Trigger-Subscription -SubscriptionId $subscriptionToTrigger - Write-Host "Subscription '$subscriptionToTrigger' triggered!" + Write-Host "done." } catch { @@ -61,9 +45,13 @@ foreach ($subscriptionToTrigger in $subscriptionsToTrigger) { } } -if ($failedTriggeredSubscription) { +if ($subscriptionsToTrigger.Count -eq 0) { + Write-Host "No subscription matched source repo '$normalizedSourceRepo' and channel ID '$ChannelId'." +} +elseif ($failedTriggeredSubscription) { Write-Host "At least one subscription failed to be triggered..." ExitWithExitCode 1 } - -Write-Host "All subscriptions were triggered successfully!" +else { + Write-Host "All subscriptions were triggered successfully!" +} diff --git a/eng/common/templates/post-build/channels/internal-servicing.yml b/eng/common/templates/post-build/channels/internal-servicing.yml index 5c07b66926f..12fd2b4653d 100644 --- a/eng/common/templates/post-build/channels/internal-servicing.yml +++ b/eng/common/templates/post-build/channels/internal-servicing.yml @@ -41,7 +41,6 @@ stages: dependsOn: setupMaestroVars variables: - group: DotNet-Blob-Feed - - group: Publish-Build-Assets - group: AzureDevOps-Artifact-Feeds-Pats - name: BARBuildId value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.BARBuildId'] ] @@ -87,8 +86,8 @@ stages: /p:StaticInternalFeed=$(dotnetfeed-internal-nonstable-feed-url) /p:NugetPath=$(Agent.BuildDirectory)\Nuget\NuGet.exe /p:BARBuildId=$(BARBuildId) - /p:MaestroApiEndpoint='https://maestro-prod.westus2.cloudapp.azure.com' - /p:BuildAssetRegistryToken='$(MaestroAccessToken)' + /p:MaestroApiEndpoint='$(MaestroApiEndPoint)' + /p:BuildAssetRegistryToken='$(MaestroApiAccessToken)' /p:ManifestsBasePath='$(Build.ArtifactStagingDirectory)/AssetManifests/' /p:BlobBasePath='$(Build.ArtifactStagingDirectory)\BlobArtifacts' /p:PackageBasePath='$(Build.ArtifactStagingDirectory)\PackageArtifacts' diff --git a/eng/common/templates/post-build/channels/public-dev-release.yml b/eng/common/templates/post-build/channels/public-dev-release.yml index 4eaa6e4ff0f..b0f085b1420 100644 --- a/eng/common/templates/post-build/channels/public-dev-release.yml +++ b/eng/common/templates/post-build/channels/public-dev-release.yml @@ -41,7 +41,6 @@ stages: dependsOn: setupMaestroVars variables: - group: DotNet-Blob-Feed - - group: Publish-Build-Assets - group: AzureDevOps-Artifact-Feeds-Pats - name: BARBuildId value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.BARBuildId'] ] @@ -87,8 +86,8 @@ stages: /p:TargetFeedPAT='$(dn-bot-dnceng-unviersal-packages-rw)' /p:AzureStorageTargetFeedPAT='$(dotnetfeed-storage-access-key-1)' /p:BARBuildId=$(BARBuildId) - /p:MaestroApiEndpoint='https://maestro-prod.westus2.cloudapp.azure.com' - /p:BuildAssetRegistryToken='$(MaestroAccessToken)' + /p:MaestroApiEndpoint='$(MaestroApiEndPoint)' + /p:BuildAssetRegistryToken='$(MaestroApiAccessToken)' /p:ManifestsBasePath='$(Build.ArtifactStagingDirectory)/AssetManifests/' /p:BlobBasePath='$(Build.ArtifactStagingDirectory)/BlobArtifacts/' /p:PackageBasePath='$(Build.ArtifactStagingDirectory)/PackageArtifacts/' diff --git a/eng/common/templates/post-build/channels/public-release.yml b/eng/common/templates/post-build/channels/public-release.yml index a31d37139b7..4c63fb43f0c 100644 --- a/eng/common/templates/post-build/channels/public-release.yml +++ b/eng/common/templates/post-build/channels/public-release.yml @@ -41,7 +41,6 @@ stages: dependsOn: setupMaestroVars variables: - group: DotNet-Blob-Feed - - group: Publish-Build-Assets - group: AzureDevOps-Artifact-Feeds-Pats - name: BARBuildId value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.BARBuildId'] ] @@ -87,8 +86,8 @@ stages: /p:StaticInternalFeed=$(dotnetfeed-internal-nonstable-feed-url) /p:NugetPath=$(Agent.BuildDirectory)\Nuget\NuGet.exe /p:BARBuildId=$(BARBuildId) - /p:MaestroApiEndpoint='https://maestro-prod.westus2.cloudapp.azure.com' - /p:BuildAssetRegistryToken='$(MaestroAccessToken)' + /p:MaestroApiEndpoint='$(MaestroApiEndPoint)' + /p:BuildAssetRegistryToken='$(MaestroApiAccessToken)' /p:ManifestsBasePath='$(Build.ArtifactStagingDirectory)/AssetManifests/' /p:BlobBasePath='$(Build.ArtifactStagingDirectory)\BlobArtifacts' /p:PackageBasePath='$(Build.ArtifactStagingDirectory)\PackageArtifacts' diff --git a/eng/common/templates/post-build/channels/public-validation-release.yml b/eng/common/templates/post-build/channels/public-validation-release.yml index 8c4d8f6ef33..1089ac5fa6b 100644 --- a/eng/common/templates/post-build/channels/public-validation-release.yml +++ b/eng/common/templates/post-build/channels/public-validation-release.yml @@ -12,7 +12,6 @@ stages: dependsOn: setupMaestroVars variables: - group: DotNet-Blob-Feed - - group: Publish-Build-Assets - group: AzureDevOps-Artifact-Feeds-Pats - name: BARBuildId value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.BARBuildId'] ] @@ -48,7 +47,7 @@ stages: filePath: eng\common\sdk-task.ps1 arguments: -task PublishArtifactsInManifest -restore -msbuildEngine dotnet /p:ChannelId=$(PublicValidationRelease_30_Channel_Id) - /p:ArtifactsCategory=$(_DotNetArtifactsCategory) + /p:ArtifactsCategory=$(_DotNetValidationArtifactsCategory) /p:IsStableBuild=$(IsStableBuild) /p:IsInternalBuild=$(IsInternalBuild) /p:RepositoryName=$(Build.Repository.Name) @@ -58,13 +57,13 @@ stages: /p:TargetFeedPAT='$(dn-bot-dnceng-unviersal-packages-rw)' /p:AzureStorageTargetFeedPAT='$(dotnetfeed-storage-access-key-1)' /p:BARBuildId=$(BARBuildId) - /p:MaestroApiEndpoint='https://maestro-prod.westus2.cloudapp.azure.com' - /p:BuildAssetRegistryToken='$(MaestroAccessToken)' + /p:MaestroApiEndpoint='$(MaestroApiEndPoint)' + /p:BuildAssetRegistryToken='$(MaestroApiAccessToken)' /p:ManifestsBasePath='$(Build.ArtifactStagingDirectory)/AssetManifests/' /p:BlobBasePath='$(Build.ArtifactStagingDirectory)\BlobArtifacts' /p:PackageBasePath='$(Build.ArtifactStagingDirectory)\PackageArtifacts' /p:Configuration=Release - + - task: NuGetCommand@2 displayName: Publish Packages to AzDO Feed condition: contains(variables['TargetAzDOFeed'], 'pkgs.visualstudio.com') diff --git a/eng/common/templates/post-build/common-variables.yml b/eng/common/templates/post-build/common-variables.yml index 42df4ae77e3..bd0bc5e4daa 100644 --- a/eng/common/templates/post-build/common-variables.yml +++ b/eng/common/templates/post-build/common-variables.yml @@ -1,21 +1,39 @@ variables: + - group: Publish-Build-Assets + # .NET Core 3 Dev - PublicDevRelease_30_Channel_Id: 3 + - name: PublicDevRelease_30_Channel_Id + value: 3 # .NET Tools - Validation - PublicValidationRelease_30_Channel_Id: 9 + - name: PublicValidationRelease_30_Channel_Id + value: 9 # .NET Core 3.0 Internal Servicing - InternalServicing_30_Channel_Id: 184 + - name: InternalServicing_30_Channel_Id + value: 184 # .NET Core 3.0 Release - PublicRelease_30_Channel_Id: 19 + - name: PublicRelease_30_Channel_Id + value: 19 # Whether the build is internal or not - IsInternalBuild: ${{ and(ne(variables['System.TeamProject'], 'public'), contains(variables['Build.SourceBranch'], 'internal')) }} + - name: IsInternalBuild + value: ${{ and(ne(variables['System.TeamProject'], 'public'), contains(variables['Build.SourceBranch'], 'internal')) }} # Storage account name for proxy-backed feeds - ProxyBackedFeedsAccountName: dotnetfeed + - name: ProxyBackedFeedsAccountName + value: dotnetfeed + + # Default Maestro++ API Endpoint and API Version + - name: MaestroApiEndPoint + value: "https://maestro-prod.westus2.cloudapp.azure.com" + - name: MaestroApiAccessToken + value: $(MaestroAccessToken) + - name: MaestroApiVersion + value: "2019-01-16" - SourceLinkCLIVersion: 3.0.0 - SymbolToolVersion: 1.0.1 + - name: SourceLinkCLIVersion + value: 3.0.0 + - name: SymbolToolVersion + value: 1.0.1 diff --git a/eng/common/templates/post-build/darc-gather-drop.yml b/eng/common/templates/post-build/darc-gather-drop.yml index e0a9f0a6d26..f4e3bfcf5cd 100644 --- a/eng/common/templates/post-build/darc-gather-drop.yml +++ b/eng/common/templates/post-build/darc-gather-drop.yml @@ -7,7 +7,6 @@ jobs: dependsOn: setupMaestroVars condition: contains(dependencies.setupMaestroVars.outputs['setReleaseVars.InitialChannels'], ${{ parameters.ChannelId }}) variables: - - group: Publish-Build-Assets - name: BARBuildId value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.BARBuildId'] ] pool: @@ -19,4 +18,6 @@ jobs: filePath: $(Build.SourcesDirectory)/eng/common/post-build/darc-gather-drop.ps1 arguments: -BarBuildId $(BARBuildId) -DropLocation $(Agent.BuildDirectory)/Temp/Drop/ - -MaestroAccessToken $(MaestroAccessToken) + -MaestroApiAccessToken $(MaestroApiAccessToken) + -MaestroApiEndPoint $(MaestroApiEndPoint) + -MaestroApiVersion $(MaestroApiVersion) diff --git a/eng/common/templates/post-build/post-build.yml b/eng/common/templates/post-build/post-build.yml index daa799259c7..0872db4ed94 100644 --- a/eng/common/templates/post-build/post-build.yml +++ b/eng/common/templates/post-build/post-build.yml @@ -7,9 +7,12 @@ parameters: enable: false params: '' + # Which stages should finish execution before post-build stages start + dependsOn: [build] + stages: - stage: validate - dependsOn: build + dependsOn: ${{ parameters.dependsOn }} displayName: Validate jobs: - ${{ if eq(parameters.enableNugetValidation, 'true') }}: diff --git a/eng/common/templates/post-build/promote-build.yml b/eng/common/templates/post-build/promote-build.yml index af48b0b339e..9387c583b31 100644 --- a/eng/common/templates/post-build/promote-build.yml +++ b/eng/common/templates/post-build/promote-build.yml @@ -11,7 +11,6 @@ jobs: value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.BARBuildId'] ] - name: ChannelId value: ${{ parameters.ChannelId }} - - group: Publish-Build-Assets pool: vmImage: 'windows-2019' steps: @@ -21,4 +20,6 @@ jobs: filePath: $(Build.SourcesDirectory)/eng/common/post-build/promote-build.ps1 arguments: -BuildId $(BARBuildId) -ChannelId $(ChannelId) - -BarToken $(MaestroAccessToken) + -MaestroApiAccessToken $(MaestroApiAccessToken) + -MaestroApiEndPoint $(MaestroApiEndPoint) + -MaestroApiVersion $(MaestroApiVersion) diff --git a/eng/common/templates/post-build/setup-maestro-vars.yml b/eng/common/templates/post-build/setup-maestro-vars.yml index f6120dc1e1c..56242b068e1 100644 --- a/eng/common/templates/post-build/setup-maestro-vars.yml +++ b/eng/common/templates/post-build/setup-maestro-vars.yml @@ -14,22 +14,5 @@ jobs: name: setReleaseVars displayName: Set Release Configs Vars inputs: - targetType: inline - script: | - # This is needed to make Write-PipelineSetVariable works in this context - $ci = $true - - . "$(Build.SourcesDirectory)/eng/common/tools.ps1" - - $Content = Get-Content "$(Build.StagingDirectory)/ReleaseConfigs/ReleaseConfigs.txt" - - $BarId = $Content | Select -Index 0 - - $Channels = "" - $Content | Select -Index 1 | ForEach-Object { $Channels += "$_ ," } - - $IsStableBuild = $Content | Select -Index 2 - - Write-PipelineSetVariable -Name 'BARBuildId' -Value $BarId - Write-PipelineSetVariable -Name 'InitialChannels' -Value "$Channels" - Write-PipelineSetVariable -Name 'IsStableBuild' -Value $IsStableBuild + filePath: $(Build.SourcesDirectory)/eng/common/post-build/setup-maestro-vars.ps1 + arguments: -ReleaseConfigsPath '$(Build.StagingDirectory)/ReleaseConfigs/ReleaseConfigs.txt' diff --git a/eng/common/templates/post-build/trigger-subscription.yml b/eng/common/templates/post-build/trigger-subscription.yml index 3915cdcd1ad..da669030daf 100644 --- a/eng/common/templates/post-build/trigger-subscription.yml +++ b/eng/common/templates/post-build/trigger-subscription.yml @@ -8,4 +8,6 @@ steps: filePath: $(Build.SourcesDirectory)/eng/common/post-build/trigger-subscriptions.ps1 arguments: -SourceRepo $(Build.Repository.Uri) -ChannelId ${{ parameters.ChannelId }} - -BarToken $(MaestroAccessToken) + -MaestroApiAccessToken $(MaestroAccessToken) + -MaestroApiEndPoint $(MaestroApiEndPoint) + -MaestroApiVersion $(MaestroApiVersion) diff --git a/global.json b/global.json index 67df8eb1531..2e6618dad53 100644 --- a/global.json +++ b/global.json @@ -10,7 +10,7 @@ } }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "1.0.0-beta.19375.15", + "Microsoft.DotNet.Arcade.Sdk": "1.0.0-beta.19376.18", "Microsoft.DotNet.Helix.Sdk": "2.0.0-beta.19069.2" } } From bdb229c3da0edec3e2c03d604f35be2ac31029d5 Mon Sep 17 00:00:00 2001 From: Sergey Tihon Date: Sat, 27 Jul 2019 21:58:59 +0300 Subject: [PATCH 3/7] Moving ClassesTests over to NUnit (#7264) * Moving ClassesTests over to NUnit * Fixed assertion for ParseWithErrors test --- .../Compiler/ErrorMessages/ClassesTests.fs | 127 ++++++++++++++++++ tests/fsharp/FSharpSuite.Tests.fsproj | 1 + .../DoCannotHaveVisibilityDeclarations.fs | 11 -- ...MatchingMethodWithSameNameIsNotAbstract.fs | 14 -- .../MemberHasMultiplePossibleDispatchSlots.fs | 15 --- .../Source/Warnings/MethodIsNotStatic.fs | 9 -- .../NoMatchingAbstractMethodWithSameName.fs | 14 -- .../Source/Warnings/TupleInAbstractMethod.fs | 13 -- tests/fsharpqa/Source/Warnings/WrongArity.fs | 11 -- tests/fsharpqa/Source/Warnings/env.lst | 7 - 10 files changed, 128 insertions(+), 94 deletions(-) create mode 100644 tests/fsharp/Compiler/ErrorMessages/ClassesTests.fs delete mode 100644 tests/fsharpqa/Source/Warnings/DoCannotHaveVisibilityDeclarations.fs delete mode 100644 tests/fsharpqa/Source/Warnings/MatchingMethodWithSameNameIsNotAbstract.fs delete mode 100644 tests/fsharpqa/Source/Warnings/MemberHasMultiplePossibleDispatchSlots.fs delete mode 100644 tests/fsharpqa/Source/Warnings/MethodIsNotStatic.fs delete mode 100644 tests/fsharpqa/Source/Warnings/NoMatchingAbstractMethodWithSameName.fs delete mode 100644 tests/fsharpqa/Source/Warnings/TupleInAbstractMethod.fs delete mode 100644 tests/fsharpqa/Source/Warnings/WrongArity.fs diff --git a/tests/fsharp/Compiler/ErrorMessages/ClassesTests.fs b/tests/fsharp/Compiler/ErrorMessages/ClassesTests.fs new file mode 100644 index 00000000000..1ce10cb7080 --- /dev/null +++ b/tests/fsharp/Compiler/ErrorMessages/ClassesTests.fs @@ -0,0 +1,127 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. + +namespace FSharp.Compiler.UnitTests + +open NUnit.Framework +open FSharp.Compiler.SourceCodeServices + +[] +module ``Classes`` = + + [] + let ``Tuple In Abstract Method``() = + CompilerAssert.TypeCheckWithErrors + """ +type IInterface = + abstract Function : (int32 * int32) -> unit + +let x = + { new IInterface with + member this.Function (i, j) = () + } + """ + [| + FSharpErrorSeverity.Error, 768, (7, 16, 7, 36), "The member 'Function' does not accept the correct number of arguments. 1 argument(s) are expected, but 2 were given. The required signature is 'member IInterface.Function : (int32 * int32) -> unit'.\nA tuple type is required for one or more arguments. Consider wrapping the given arguments in additional parentheses or review the definition of the interface." + FSharpErrorSeverity.Error, 17, (7, 21, 7, 29), "The member 'Function : 'a * 'b -> unit' does not have the correct type to override the corresponding abstract method. The required signature is 'Function : (int32 * int32) -> unit'." + FSharpErrorSeverity.Error, 783, (6, 9, 6, 19), "At least one override did not correctly implement its corresponding abstract member" + |] + + [] + let ``Wrong Arity``() = + CompilerAssert.TypeCheckSingleError + """ +type MyType() = + static member MyMember(arg1, arg2:int ) = () + static member MyMember(arg1, arg2:byte) = () + + +MyType.MyMember("", 0, 0) + """ + FSharpErrorSeverity.Error + 503 + (7, 1, 7, 26) + "A member or object constructor 'MyMember' taking 3 arguments is not accessible from this code location. All accessible versions of method 'MyMember' take 2 arguments." + + [] + let ``Method Is Not Static``() = + CompilerAssert.TypeCheckSingleError + """ +type Class1() = + member this.X() = "F#" + +let x = Class1.X() + """ + FSharpErrorSeverity.Error + 3214 + (5, 9, 5, 17) + "Method or object constructor 'X' is not static" + + [] + let ``Matching Method With Same Name Is Not Abstract``() = + CompilerAssert.TypeCheckWithErrors + """ +type Foo(x : int) = + member v.MyX() = x + +let foo = + { new Foo(3) + with + member v.MyX() = 4 } + """ + [| + FSharpErrorSeverity.Error, 767, (8, 16, 8, 23), "The type Foo contains the member 'MyX' but it is not a virtual or abstract method that is available to override or implement." + FSharpErrorSeverity.Error, 17, (8, 18, 8, 21), "The member 'MyX : unit -> int' does not have the correct type to override any given virtual method" + FSharpErrorSeverity.Error, 783, (6, 11, 6, 14), "At least one override did not correctly implement its corresponding abstract member" + |] + + [] + let ``No Matching Abstract Method With Same Name``() = + CompilerAssert.TypeCheckWithErrors + """ +type IInterface = + abstract MyFunction : int32 * int32 -> unit + abstract SomeOtherFunction : int32 * int32 -> unit + +let x = + { new IInterface with + member this.Function (i, j) = () + } + """ + [| + FSharpErrorSeverity.Error, 767, (8, 14, 8, 34), "The member 'Function' does not correspond to any abstract or virtual method available to override or implement." + FSharpErrorSeverity.Error, 17, (8, 19, 8, 27), "The member 'Function : 'a * 'b -> unit' does not have the correct type to override any given virtual method" + FSharpErrorSeverity.Error, 366, (7, 3, 9, 4), "No implementation was given for those members: \r\n\t'abstract member IInterface.MyFunction : int32 * int32 -> unit'\r\n\t'abstract member IInterface.SomeOtherFunction : int32 * int32 -> unit'\r\nNote that all interface members must be implemented and listed under an appropriate 'interface' declaration, e.g. 'interface ... with member ...'." + FSharpErrorSeverity.Error, 783, (7, 9, 7, 19), "At least one override did not correctly implement its corresponding abstract member" + |] + + [] + let ``Member Has Multiple Possible Dispatch Slots``() = + CompilerAssert.TypeCheckWithErrors + """ +type IOverload = + abstract member Bar : int -> int + abstract member Bar : double -> int + +type Overload = + interface IOverload with + override __.Bar _ = 1 + """ + [| + FSharpErrorSeverity.Error, 366, (7, 15, 7, 24), "No implementation was given for those members: \r\n\t'abstract member IOverload.Bar : double -> int'\r\n\t'abstract member IOverload.Bar : int -> int'\r\nNote that all interface members must be implemented and listed under an appropriate 'interface' declaration, e.g. 'interface ... with member ...'." + FSharpErrorSeverity.Error, 3213, (8, 21, 8, 24), "The member 'Bar<'a0> : 'a0 -> int' matches multiple overloads of the same method.\nPlease restrict it to one of the following:\r\n Bar : double -> int\r\n Bar : int -> int." + |] + + [] + let ``Do Cannot Have Visibility Declarations``() = + CompilerAssert.ParseWithErrors + """ +type X() = + do () + private do () + static member Y() = 1 + """ + [| + FSharpErrorSeverity.Error, 531, (4, 5, 4, 12), "Accessibility modifiers should come immediately prior to the identifier naming a construct" + FSharpErrorSeverity.Error, 512, (4, 13, 4, 18), "Accessibility modifiers are not permitted on 'do' bindings, but 'Private' was given." + FSharpErrorSeverity.Error, 222, (2, 1, 3, 1), "Files in libraries or multiple-file applications must begin with a namespace or module declaration, e.g. 'namespace SomeNamespace.SubNamespace' or 'module SomeNamespace.SomeModule'. Only the last source file of an application may omit such a declaration." + |] diff --git a/tests/fsharp/FSharpSuite.Tests.fsproj b/tests/fsharp/FSharpSuite.Tests.fsproj index 9f3aeee1e43..651f0363ae6 100644 --- a/tests/fsharp/FSharpSuite.Tests.fsproj +++ b/tests/fsharp/FSharpSuite.Tests.fsproj @@ -33,6 +33,7 @@ + diff --git a/tests/fsharpqa/Source/Warnings/DoCannotHaveVisibilityDeclarations.fs b/tests/fsharpqa/Source/Warnings/DoCannotHaveVisibilityDeclarations.fs deleted file mode 100644 index b57356ee9a0..00000000000 --- a/tests/fsharpqa/Source/Warnings/DoCannotHaveVisibilityDeclarations.fs +++ /dev/null @@ -1,11 +0,0 @@ -// #Warnings -//Accessibility -//Accessibility modifiers are not permitted on 'do' bindings, but 'Private' was given. - -type X() = - do () - private do () - static member Y() = 1 - - -exit 0 \ No newline at end of file diff --git a/tests/fsharpqa/Source/Warnings/MatchingMethodWithSameNameIsNotAbstract.fs b/tests/fsharpqa/Source/Warnings/MatchingMethodWithSameNameIsNotAbstract.fs deleted file mode 100644 index 36275ff0e92..00000000000 --- a/tests/fsharpqa/Source/Warnings/MatchingMethodWithSameNameIsNotAbstract.fs +++ /dev/null @@ -1,14 +0,0 @@ -// #Warnings -//The type Foo contains the member 'MyX' but it is not a virtual or abstract method that is available to override or implement. -//ToString - -type Foo(x : int) = - member v.MyX() = x - -let foo = - { new Foo(3) - with - member v.MyX() = 4 } - - -exit 0 \ No newline at end of file diff --git a/tests/fsharpqa/Source/Warnings/MemberHasMultiplePossibleDispatchSlots.fs b/tests/fsharpqa/Source/Warnings/MemberHasMultiplePossibleDispatchSlots.fs deleted file mode 100644 index ae6738208b6..00000000000 --- a/tests/fsharpqa/Source/Warnings/MemberHasMultiplePossibleDispatchSlots.fs +++ /dev/null @@ -1,15 +0,0 @@ -// #Warnings -//The member 'Bar -//Please restrict it to one of the following: -//Bar : double -> int -//Bar : int -> int - -type IOverload = - abstract member Bar : int -> int - abstract member Bar : double -> int - -type Overload = - interface IOverload with - override __.Bar _ = 1 - -exit 0 \ No newline at end of file diff --git a/tests/fsharpqa/Source/Warnings/MethodIsNotStatic.fs b/tests/fsharpqa/Source/Warnings/MethodIsNotStatic.fs deleted file mode 100644 index 299a88abc3a..00000000000 --- a/tests/fsharpqa/Source/Warnings/MethodIsNotStatic.fs +++ /dev/null @@ -1,9 +0,0 @@ -// #Warnings -//Method or object constructor 'X' is not static - -type Class1() = - member this.X() = "F#" - -let x = Class1.X() - -exit 0 \ No newline at end of file diff --git a/tests/fsharpqa/Source/Warnings/NoMatchingAbstractMethodWithSameName.fs b/tests/fsharpqa/Source/Warnings/NoMatchingAbstractMethodWithSameName.fs deleted file mode 100644 index a59f863a774..00000000000 --- a/tests/fsharpqa/Source/Warnings/NoMatchingAbstractMethodWithSameName.fs +++ /dev/null @@ -1,14 +0,0 @@ -// #Warnings -//The member 'Function' does not correspond to any abstract or virtual method available to override or implement. -//MyFunction - -type IInterface = - abstract MyFunction : int32 * int32 -> unit - abstract SomeOtherFunction : int32 * int32 -> unit - -let x = - { new IInterface with - member this.Function (i, j) = () - } - -exit 0 \ No newline at end of file diff --git a/tests/fsharpqa/Source/Warnings/TupleInAbstractMethod.fs b/tests/fsharpqa/Source/Warnings/TupleInAbstractMethod.fs deleted file mode 100644 index 0ed439073e3..00000000000 --- a/tests/fsharpqa/Source/Warnings/TupleInAbstractMethod.fs +++ /dev/null @@ -1,13 +0,0 @@ -// #Warnings -//The member 'Function' does not accept the correct number of arguments. -//A tuple type is required for one or more arguments - -type IInterface = - abstract Function : (int32 * int32) -> unit - -let x = - { new IInterface with - member this.Function (i, j) = () - } - -exit 0 \ No newline at end of file diff --git a/tests/fsharpqa/Source/Warnings/WrongArity.fs b/tests/fsharpqa/Source/Warnings/WrongArity.fs deleted file mode 100644 index 459f9a5c7a4..00000000000 --- a/tests/fsharpqa/Source/Warnings/WrongArity.fs +++ /dev/null @@ -1,11 +0,0 @@ -// #Warnings -//A member or object constructor 'MyMember' taking 3 - -type MyType() = - static member MyMember(arg1, arg2:int ) = () - static member MyMember(arg1, arg2:byte) = () - - -MyType.MyMember("", 0, 0) - -exit 0 \ No newline at end of file diff --git a/tests/fsharpqa/Source/Warnings/env.lst b/tests/fsharpqa/Source/Warnings/env.lst index 18ef811a2a5..2daa6d31680 100644 --- a/tests/fsharpqa/Source/Warnings/env.lst +++ b/tests/fsharpqa/Source/Warnings/env.lst @@ -1,8 +1,5 @@ SOURCE=WrongNumericLiteral.fs # WrongNumericLiteral.fs - SOURCE=TupleInAbstractMethod.fs # TupleInAbstractMethod.fs SOURCE=FS0988AtEndOfFile.fs # FS0988AtEndOfFile.fs - SOURCE=WrongArity.fs # WrongArity.fs - SOURCE=MethodIsNotStatic.fs # MethodIsNotStatic.fs SOURCE=EqualsInsteadOfInInForLoop.fs # EqualsInsteadOfInInForLoop.fs SOURCE=DontWarnExternalFunctionAsUnused.fs SCFLAGS="--warnon:1182 --warnaserror+" # DontWarnExternalFunctionAsUnused.fs SOURCE=SuggestTypesInModule.fs # SuggestTypesInModule.fs @@ -25,14 +22,10 @@ SOURCE=DontSuggestWhenThingsAreOpen.fs SCFLAGS="--vserrors" # DontSuggestWhenThingsAreOpen.fs SOURCE=SuggestDoubleBacktickIdentifiers.fs SCFLAGS="--vserrors" # SuggestDoubleBacktickIdentifiers.fs SOURCE=SuggestDoubleBacktickUnions.fs SCFLAGS="--vserrors" # SuggestDoubleBacktickUnions.fs - SOURCE=MatchingMethodWithSameNameIsNotAbstract.fs # MatchingMethodWithSameNameIsNotAbstract.fs - SOURCE=NoMatchingAbstractMethodWithSameName.fs # NoMatchingAbstractMethodWithSameName.fs SOURCE=MissingExpressionAfterLet.fs # MissingExpressionAfterLet.fs SOURCE=SuggestFieldsInCtor.fs # SuggestFieldsInCtor.fs SOURCE=FieldSuggestion.fs # FieldSuggestion.fs SOURCE=SuggestToUseIndexer.fs # SuggestToUseIndexer.fs - SOURCE=MemberHasMultiplePossibleDispatchSlots.fs # MemberHasMultiplePossibleDispatchSlots.fs SOURCE=Repro1548.fs SCFLAGS="-r:Repro1548.dll" # Repro1548.fs - SOURCE=DoCannotHaveVisibilityDeclarations.fs SOURCE=ModuleAbbreviationsArePrivate.fs SOURCE=DontSuggestIntentionallyUnusedVariables.fs SCFLAGS="--vserrors" # DontSuggestIntentionallyUnusedVariables.fs From 8370ef62ebca160bfb677f6a8a367cd941b6227b Mon Sep 17 00:00:00 2001 From: Faisal Alfaddaghi Date: Sun, 28 Jul 2019 00:23:42 +0300 Subject: [PATCH 4/7] Move Basic Constants to NUnit (#7262) * Move BasicConstants.fs Tests To Nunit * fix typo * Another typo --- .../BasicGrammarElements/BasicConstants.fs | 177 ++++++++++++++++++ tests/fsharp/FSharpSuite.Tests.fsproj | 1 + .../Constants/BasicConstants.fs | 99 ---------- .../BasicGrammarElements/Constants/env.lst | 1 - 4 files changed, 178 insertions(+), 100 deletions(-) create mode 100644 tests/fsharp/Compiler/Conformance/BasicGrammarElements/BasicConstants.fs delete mode 100644 tests/fsharpqa/Source/Conformance/BasicGrammarElements/Constants/BasicConstants.fs diff --git a/tests/fsharp/Compiler/Conformance/BasicGrammarElements/BasicConstants.fs b/tests/fsharp/Compiler/Conformance/BasicGrammarElements/BasicConstants.fs new file mode 100644 index 00000000000..9bae4946568 --- /dev/null +++ b/tests/fsharp/Compiler/Conformance/BasicGrammarElements/BasicConstants.fs @@ -0,0 +1,177 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. + +namespace FSharp.Compiler.UnitTests + +open NUnit.Framework +open FSharp.Compiler.SourceCodeServices + +[] +module ``Basic Grammar Element Constants`` = + + [] + let `` Basic constants compile `` () = + CompilerAssert.Pass + """ +let sbyteConst = 1y +let int16Const = 1us +let int32Const = 1ul +let int64Const = 1UL + +let byteConst = 1uy +let uint16Const = 1us +let uint32Const = 1ul +let uint64Const = 1uL + +let ieee32Const1 = 1.0f +let ieee32Const2 = 1.0F +let ieee32Const3 = 0x0000000000000001lf + +let ieee64Const1 = 1.0 +let ieee64Const2 = 0x0000000000000001LF + +let bigintConst = 1I + +// let bignumConst = 1N - you need a reference to PowerPack.dll now + +let decimalConst1 = 1.0M +let decimalConst2 = 1.0m + +let charConst = '1' + +let stringConst = "1" + +let bytestringConst = "1"B + +let bytecharConst = '1'B + +let boolConst1 = true +let boolConst2 = false + +let unitConst = () + """ + + [] + let ``Long with underscores``() = + CompilerAssert.CompileExeAndRun + """ +let creditCardNumber = 1234_5678_9012_3456L +let socialSecurityNumber = 999_99_9999L + +if socialSecurityNumber <> 999999999L then failwith "Wrong parsing" +if creditCardNumber <> 1234567890123456L then failwith "Wrong parsing" +exit 0 + """ + + [] + let ``float 32 with underscores``() = + CompilerAssert.CompileExeAndRun + """ +let pi = 3.14_15F +if pi <> 3.1415F then failwith "Wrong parsing" +exit 0 + """ + + [] + let ``int with underscores hexBytes``() = + CompilerAssert.CompileExeAndRun + """ +let hexBytes = 0xFF_EC_DE_5E +if hexBytes <> 0xFFECDE5E then failwith "Wrong parsing" +exit 0 + """ + + + [] + let ``int with underscore hexWords``() = + CompilerAssert.CompileExeAndRun + """ +let hexWords = 0xCAFE_BABE +if hexWords <> 0xCAFEBABE then failwith "Wrong parsing" +exit 0 + """ + + [] + let ``Long with underscores maxLong``() = + CompilerAssert.CompileExeAndRun + """ +let maxLong = 0x7fff_ffff_ffff_ffffL +if maxLong <> 0x7fffffffffffffffL then failwith "Wrong parsing" +exit 0 + """ + + [] + let ``int with underscore nybbles``() = + CompilerAssert.CompileExeAndRun + """ +let nybbles = 0b0010_0101 +if nybbles <> 0b00100101 then failwith "Wrong parsing" +exit 0 + """ + + [] + let ``int with underscores bytes``() = + CompilerAssert.CompileExeAndRun + """ +let bytes = 0b11010010_01101001_10010100_10010010 +if bytes <> 0b11010010011010011001010010010010 then failwith "Wrong parsing" +exit 0 + """ + + [] + let ``int with single underscore literal``() = + CompilerAssert.CompileExeAndRun + """ +let x2 = 5_2 +if x2 <> 52 then failwith "Wrong parsing" +exit 0 + """ + + [] + let ``int with multiple underscores literal``() = + CompilerAssert.CompileExeAndRun + """ +let x4 = 5_______2 +if x4 <> 52 then failwith "Wrong parsing" +exit 0 + """ + + [] + let ``int with single underscore Hex literal``() = + CompilerAssert.CompileExeAndRun + """ +let x7 = 0x5_2 +if x7 <> 0x52 then + failwith "Wrong parsing" +exit 0 + """ + + [] + let ``int with single underscore after leading zero literal``() = + CompilerAssert.CompileExeAndRun + """ +let x9 = 0_52 +if x9 <> 052 then failwith "Wrong parsing" +exit 0 + """ + + [] + let ``int with single underscore after leteral with leading zero ``() = + CompilerAssert.CompileExeAndRun + """ +let x10 = 05_2 +if x10 <> 052 then failwith "Wrong parsing" +exit 0 + """ + + [] + let ``int with single underscore after octo leteral ``() = + CompilerAssert.CompileExeAndRun + """ +let x14 = 0o5_2 +if x14 <> 0o52 then failwith "Wrong parsing" +exit 0 + """ + + + + diff --git a/tests/fsharp/FSharpSuite.Tests.fsproj b/tests/fsharp/FSharpSuite.Tests.fsproj index 651f0363ae6..71fd78680a6 100644 --- a/tests/fsharp/FSharpSuite.Tests.fsproj +++ b/tests/fsharp/FSharpSuite.Tests.fsproj @@ -32,6 +32,7 @@ + diff --git a/tests/fsharpqa/Source/Conformance/BasicGrammarElements/Constants/BasicConstants.fs b/tests/fsharpqa/Source/Conformance/BasicGrammarElements/Constants/BasicConstants.fs deleted file mode 100644 index 78303d2713e..00000000000 --- a/tests/fsharpqa/Source/Conformance/BasicGrammarElements/Constants/BasicConstants.fs +++ /dev/null @@ -1,99 +0,0 @@ -// #Conformance #BasicGrammarElements #Constants -#light - -// Verify the ability to specify basic constants - -let sbyteConst = 1y -let int16Const = 1us -let int32Const = 1ul -let int64Const = 1UL - -let byteConst = 1uy -let uint16Const = 1us -let uint32Const = 1ul -let uint64Const = 1uL - -let ieee32Const1 = 1.0f -let ieee32Const2 = 1.0F -let ieee32Const3 = 0x0000000000000001lf - -let ieee64Const1 = 1.0 -let ieee64Const2 = 0x0000000000000001LF - -let bigintConst = 1I - -// let bignumConst = 1N - you need a reference to PowerPack.dll now - -let decimalConst1 = 1.0M -let decimalConst2 = 1.0m - -let charConst = '1' - -let stringConst = "1" - -let bytestringConst = "1"B - -let bytecharConst = '1'B - -let boolConst1 = true -let boolConst2 = false - -let unitConst = () - -let creditCardNumber = 1234_5678_9012_3456L -if creditCardNumber <> 1234567890123456L then - failwith "Wrong parsing" - -let socialSecurityNumber = 999_99_9999L -if socialSecurityNumber <> 999999999L then - failwith "Wrong parsing" - -let pi = 3.14_15F -if pi <> 3.1415F then - failwith "Wrong parsing" - -let hexBytes = 0xFF_EC_DE_5E -if hexBytes <> 0xFFECDE5E then - failwith "Wrong parsing" - -let hexWords = 0xCAFE_BABE -if hexWords <> 0xCAFEBABE then - failwith "Wrong parsing" - -let maxLong = 0x7fff_ffff_ffff_ffffL -if maxLong <> 0x7fffffffffffffffL then - failwith "Wrong parsing" - -let nybbles = 0b0010_0101 -if nybbles <> 0b00100101 then - failwith "Wrong parsing" - -let bytes = 0b11010010_01101001_10010100_10010010 -if bytes <> 0b11010010011010011001010010010010 then - failwith "Wrong parsing" - -let x2 = 5_2 -if x2 <> 52 then - failwith "Wrong parsing" - -let x4 = 5_______2 -if x4 <> 52 then - failwith "Wrong parsing" - -let x7 = 0x5_2 -if x7 <> 0x52 then - failwith "Wrong parsing" - -let x9 = 0_52 -if x9 <> 052 then - failwith "Wrong parsing" - -let x10 = 05_2 -if x10 <> 052 then - failwith "Wrong parsing" - -let x14 = 0o5_2 -if x14 <> 0o52 then - failwith "Wrong parsing" - -exit 0 diff --git a/tests/fsharpqa/Source/Conformance/BasicGrammarElements/Constants/env.lst b/tests/fsharpqa/Source/Conformance/BasicGrammarElements/Constants/env.lst index 500d42d77e1..97183b49781 100644 --- a/tests/fsharpqa/Source/Conformance/BasicGrammarElements/Constants/env.lst +++ b/tests/fsharpqa/Source/Conformance/BasicGrammarElements/Constants/env.lst @@ -1,4 +1,3 @@ - SOURCE=BasicConstants.fs # BasicConstants.fs NOMONO,NoMT SOURCE=E_BasicConstantsBigNum40.fsx SCFLAGS="--test:ErrorRanges" # E_BasicConstantsBigNum40.fsx From 3ce8eb1b2a4f8cfa29bb614ef8bb12e6a2fa67e0 Mon Sep 17 00:00:00 2001 From: Sergey Tihon Date: Mon, 29 Jul 2019 06:34:39 +0300 Subject: [PATCH 5/7] Moved Don't Suggest Tests over to NUnit (#7288) --- .../ErrorMessages/DontSuggestTests.fs | 48 +++++++++++++++++++ tests/fsharp/FSharpSuite.Tests.fsproj | 1 + .../DontSuggestCompletelyWrongStuff.fs | 7 --- ...DontSuggestIntentionallyUnusedVariables.fs | 8 ---- .../Warnings/DontSuggestWhenThingsAreOpen.fs | 13 ----- tests/fsharpqa/Source/Warnings/env.lst | 3 -- 6 files changed, 49 insertions(+), 31 deletions(-) create mode 100644 tests/fsharp/Compiler/ErrorMessages/DontSuggestTests.fs delete mode 100644 tests/fsharpqa/Source/Warnings/DontSuggestCompletelyWrongStuff.fs delete mode 100644 tests/fsharpqa/Source/Warnings/DontSuggestIntentionallyUnusedVariables.fs delete mode 100644 tests/fsharpqa/Source/Warnings/DontSuggestWhenThingsAreOpen.fs diff --git a/tests/fsharp/Compiler/ErrorMessages/DontSuggestTests.fs b/tests/fsharp/Compiler/ErrorMessages/DontSuggestTests.fs new file mode 100644 index 00000000000..0e5a4f19557 --- /dev/null +++ b/tests/fsharp/Compiler/ErrorMessages/DontSuggestTests.fs @@ -0,0 +1,48 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. + +namespace FSharp.Compiler.UnitTests + +open NUnit.Framework +open FSharp.Compiler.SourceCodeServices + +[] +module ``Don't Suggest`` = + + [] + let ``Dont Suggest Completely Wrong Stuff``() = + CompilerAssert.TypeCheckSingleError + """ +let _ = Path.GetFullPath "images" + """ + FSharpErrorSeverity.Error + 39 + (2, 9, 2, 13) + "The value, namespace, type or module 'Path' is not defined." + + [] + let ``Dont Suggest When Things Are Open``() = + CompilerAssert.ParseWithErrors + """ +module N = + let name = "hallo" + +type T = + static member myMember = 1 + +let x = N. + """ + [| + FSharpErrorSeverity.Error, 599, (8, 10, 8, 11), "Missing qualification after '.'" + FSharpErrorSeverity.Error, 222, (2, 1, 3, 1), "Files in libraries or multiple-file applications must begin with a namespace or module declaration. When using a module declaration at the start of a file the '=' sign is not allowed. If this is a top-level module, consider removing the = to resolve this error." + |] + + [] + let ``Dont Suggest Intentionally Unused Variables``() = + CompilerAssert.TypeCheckSingleError + """ +let hober xy _xyz = xyz + """ + FSharpErrorSeverity.Error + 39 + (2, 21, 2, 24) + "The value or constructor 'xyz' is not defined." diff --git a/tests/fsharp/FSharpSuite.Tests.fsproj b/tests/fsharp/FSharpSuite.Tests.fsproj index 71fd78680a6..21b9367ec3a 100644 --- a/tests/fsharp/FSharpSuite.Tests.fsproj +++ b/tests/fsharp/FSharpSuite.Tests.fsproj @@ -46,6 +46,7 @@ + diff --git a/tests/fsharpqa/Source/Warnings/DontSuggestCompletelyWrongStuff.fs b/tests/fsharpqa/Source/Warnings/DontSuggestCompletelyWrongStuff.fs deleted file mode 100644 index 68b6d6dcb7e..00000000000 --- a/tests/fsharpqa/Source/Warnings/DontSuggestCompletelyWrongStuff.fs +++ /dev/null @@ -1,7 +0,0 @@ -// #Warnings -//The value, namespace, type or module 'Path' is not defined. -//Maybe you want one of the following:\s+Math - -let _ = Path.GetFullPath "images" - -exit 0 \ No newline at end of file diff --git a/tests/fsharpqa/Source/Warnings/DontSuggestIntentionallyUnusedVariables.fs b/tests/fsharpqa/Source/Warnings/DontSuggestIntentionallyUnusedVariables.fs deleted file mode 100644 index 602d459d518..00000000000 --- a/tests/fsharpqa/Source/Warnings/DontSuggestIntentionallyUnusedVariables.fs +++ /dev/null @@ -1,8 +0,0 @@ -//The value or constructor 'xyz' is not defined. -//Maybe you want one of the following: -//\s+xy -//\s+_xyz - -let hober xy _xyz = xyz - -exit 0 diff --git a/tests/fsharpqa/Source/Warnings/DontSuggestWhenThingsAreOpen.fs b/tests/fsharpqa/Source/Warnings/DontSuggestWhenThingsAreOpen.fs deleted file mode 100644 index dad90178a5f..00000000000 --- a/tests/fsharpqa/Source/Warnings/DontSuggestWhenThingsAreOpen.fs +++ /dev/null @@ -1,13 +0,0 @@ -// #Warnings -//Missing qualification after '.' - -module N = - let name = "hallo" - -type T = - static member myMember = 1 - -let x = N. - - -exit 0 \ No newline at end of file diff --git a/tests/fsharpqa/Source/Warnings/env.lst b/tests/fsharpqa/Source/Warnings/env.lst index 2daa6d31680..275959c6957 100644 --- a/tests/fsharpqa/Source/Warnings/env.lst +++ b/tests/fsharpqa/Source/Warnings/env.lst @@ -16,10 +16,8 @@ SOURCE=SuggestUnionCases.fs SCFLAGS="--vserrors" # SuggestUnionCases.fs SOURCE=SuggestArrayModuleFunctions.fs SCFLAGS="--vserrors" # SuggestArrayModuleFunctions.fs SOURCE=SuggestTypesInNamespace.fs # SuggestTypesInNamespace.fs - SOURCE=DontSuggestCompletelyWrongStuff.fs SCFLAGS="--vserrors" # DontSuggestCompletelyWrongStuff.fs SOURCE=SuggestTypesInNamespaceVS.fs SCFLAGS="--vserrors" # SuggestTypesInNamespaceVS.fs SOURCE=SuggestAsyncModule.fs SCFLAGS="--vserrors" # SuggestAsyncModule.fs - SOURCE=DontSuggestWhenThingsAreOpen.fs SCFLAGS="--vserrors" # DontSuggestWhenThingsAreOpen.fs SOURCE=SuggestDoubleBacktickIdentifiers.fs SCFLAGS="--vserrors" # SuggestDoubleBacktickIdentifiers.fs SOURCE=SuggestDoubleBacktickUnions.fs SCFLAGS="--vserrors" # SuggestDoubleBacktickUnions.fs SOURCE=MissingExpressionAfterLet.fs # MissingExpressionAfterLet.fs @@ -28,4 +26,3 @@ SOURCE=SuggestToUseIndexer.fs # SuggestToUseIndexer.fs SOURCE=Repro1548.fs SCFLAGS="-r:Repro1548.dll" # Repro1548.fs SOURCE=ModuleAbbreviationsArePrivate.fs - SOURCE=DontSuggestIntentionallyUnusedVariables.fs SCFLAGS="--vserrors" # DontSuggestIntentionallyUnusedVariables.fs From 868b76a743fad667e0a398475a88a63522cfd787 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Mon, 29 Jul 2019 10:42:20 -0700 Subject: [PATCH 6/7] [master] Update dependencies from dotnet/arcade (#7287) * Update dependencies from https://github.com/dotnet/arcade build 20190727.2 - Microsoft.DotNet.Arcade.Sdk - 1.0.0-beta.19377.2 * Update dependencies from https://github.com/dotnet/arcade build 20190728.1 - Microsoft.DotNet.Arcade.Sdk - 1.0.0-beta.19378.1 --- eng/Version.Details.xml | 4 ++-- global.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 0893278ac13..8a78856321e 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -3,9 +3,9 @@ - + https://github.com/dotnet/arcade - 316481e57ee5e6acbbf2401eb6778a1d3d48d25b + a8e982d3bac01d8f4f91a4c57191147570079448 diff --git a/global.json b/global.json index 2e6618dad53..fe2ea05490f 100644 --- a/global.json +++ b/global.json @@ -10,7 +10,7 @@ } }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "1.0.0-beta.19376.18", + "Microsoft.DotNet.Arcade.Sdk": "1.0.0-beta.19378.1", "Microsoft.DotNet.Helix.Sdk": "2.0.0-beta.19069.2" } } From 9c1a0d12bcdf114a9b1844ef194ea1e18f03c36e Mon Sep 17 00:00:00 2001 From: "Kevin Ransom (msft)" Date: Mon, 29 Jul 2019 20:05:36 -0700 Subject: [PATCH 7/7] Fix langversion with multiple projects (#7293) --- src/fsharp/CompileOps.fsi | 1 + src/fsharp/LanguageFeatures.fs | 3 + src/fsharp/LanguageFeatures.fsi | 3 + src/fsharp/service/IncrementalBuild.fs | 13 +- .../Compiler/Language/OpenStaticClasses.fs | 173 ++++++++++++++++++ tests/fsharp/FSharpSuite.Tests.fsproj | 1 + .../fsharp/core/longnames/version46/test.bsl | 39 ---- tests/fsharp/core/longnames/version46/test.fs | 84 --------- .../fsharp/core/longnames/version47/test.fsx | 91 --------- tests/fsharp/tests.fs | 15 -- 10 files changed, 188 insertions(+), 235 deletions(-) create mode 100644 tests/fsharp/Compiler/Language/OpenStaticClasses.fs delete mode 100644 tests/fsharp/core/longnames/version46/test.bsl delete mode 100644 tests/fsharp/core/longnames/version46/test.fs delete mode 100644 tests/fsharp/core/longnames/version47/test.fsx diff --git a/src/fsharp/CompileOps.fsi b/src/fsharp/CompileOps.fsi index 68abd98ac81..0b5f9cb0839 100644 --- a/src/fsharp/CompileOps.fsi +++ b/src/fsharp/CompileOps.fsi @@ -552,6 +552,7 @@ type TcConfig = member copyFSharpCore: CopyFSharpCoreFlag member shadowCopyReferences: bool member useSdkRefs: bool + member langVersion: LanguageVersion static member Create: TcConfigBuilder * validate: bool -> TcConfig diff --git a/src/fsharp/LanguageFeatures.fs b/src/fsharp/LanguageFeatures.fs index 8894fb1fc17..c4c46e4b666 100644 --- a/src/fsharp/LanguageFeatures.fs +++ b/src/fsharp/LanguageFeatures.fs @@ -93,3 +93,6 @@ type LanguageVersion (specifiedVersion) = let label = if v = defaultVersion then " (Default)" else "" yield sprintf "%M%s" v label |] + + /// Get the specified LanguageVersion + member __.SpecifiedVerson = specified diff --git a/src/fsharp/LanguageFeatures.fsi b/src/fsharp/LanguageFeatures.fsi index bda44fe171e..d1d190d3f96 100644 --- a/src/fsharp/LanguageFeatures.fsi +++ b/src/fsharp/LanguageFeatures.fsi @@ -34,3 +34,6 @@ type LanguageVersion = /// Get the list of valid options member ValidOptions: string array + + /// Get the specified LanguageVersion + member SpecifiedVerson: decimal diff --git a/src/fsharp/service/IncrementalBuild.fs b/src/fsharp/service/IncrementalBuild.fs index 4099b59c803..96e81e32147 100755 --- a/src/fsharp/service/IncrementalBuild.fs +++ b/src/fsharp/service/IncrementalBuild.fs @@ -1052,7 +1052,7 @@ type TypeCheckAccumulator = /// Global service state -type FrameworkImportsCacheKey = (*resolvedpath*)string list * string * (*TargetFrameworkDirectories*)string list* (*fsharpBinaries*)string +type FrameworkImportsCacheKey = (*resolvedpath*)string list * string * (*TargetFrameworkDirectories*)string list * (*fsharpBinaries*)string * (*langVersion*)decimal /// Represents a cache of 'framework' references that can be shared betweeen multiple incremental builds type FrameworkImportsCache(keepStrongly) = @@ -1083,12 +1083,13 @@ type FrameworkImportsCache(keepStrongly) = // The data elements in this key are very important. There should be nothing else in the TcConfig that logically affects // the import of a set of framework DLLs into F# CCUs. That is, the F# CCUs that result from a set of DLLs (including // FSharp.Core.dll and mscorlib.dll) must be logically invariant of all the other compiler configuration parameters. - let key = (frameworkDLLsKey, - tcConfig.primaryAssembly.Name, - tcConfig.GetTargetFrameworkDirectories(), - tcConfig.fsharpBinariesDir) + let key = (frameworkDLLsKey, + tcConfig.primaryAssembly.Name, + tcConfig.GetTargetFrameworkDirectories(), + tcConfig.fsharpBinariesDir, + tcConfig.langVersion.SpecifiedVerson) - match frameworkTcImportsCache.TryGet (ctok, key) with + match frameworkTcImportsCache.TryGet (ctok, key) with | Some res -> return res | None -> let tcConfigP = TcConfigProvider.Constant tcConfig diff --git a/tests/fsharp/Compiler/Language/OpenStaticClasses.fs b/tests/fsharp/Compiler/Language/OpenStaticClasses.fs new file mode 100644 index 00000000000..bd036d3a109 --- /dev/null +++ b/tests/fsharp/Compiler/Language/OpenStaticClasses.fs @@ -0,0 +1,173 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. + +namespace FSharp.Compiler.UnitTests + +open FSharp.Compiler.SourceCodeServices +open NUnit.Framework + + +(* + Tests in this file evaluate whether the language supports accessing functions on static classes using open + The feature was added in FSharp4.7, the test cases ensure that the original errors are reproduced when the langversion:4.6 is specified +*) + +[] +module OpenStaticClassesTests = + + let baseModule = """ +module Core_OpenStaticClasses + +[] +type MyMath() = + static member Min(a: double, b: double) = System.Math.Min(a, b) + static member Min(a: int, b: int) = System.Math.Min(a, b) + +[] +type AutoOpenMyMath() = + static member AutoMin(a: double, b: double) = System.Math.Min(a, b) + static member AutoMin(a: int, b: int) = System.Math.Min(a, b) + +[] +type NotAllowedToOpen() = + static member QualifiedMin(a: double, b: double) = System.Math.Min(a, b) + static member QualifiedMin(a: int, b: int) = System.Math.Min(a, b) + +""" + + [] + let ``OpenStaticClassesTests - OpenSystemMathOnce - langversion:v4.6`` () = + CompilerAssert.TypeCheckWithErrorsAndOptions + [| "--langversion:4.6" |] + (baseModule + """ +module OpenSystemMathOnce = + + open System.Math + let x = Min(1.0, 2.0)""") + [| + (FSharpErrorSeverity.Error, 39, (22,28,22,32), "The namespace 'Math' is not defined."); + (FSharpErrorSeverity.Error, 39, (23,24,23,27), "The value or constructor 'Min' is not defined.") + |] + + [] + let ``OpenStaticClassesTests - OpenSystemMathOnce - langversion:v4.7`` () = + CompilerAssert.TypeCheckWithErrorsAndOptions + [| "--langversion:4.7" |] + (baseModule + """ +module OpenSystemMathOnce = + + open System.Math + let x = Min(1.0, 2.0)""") + [| |] + + [] + let ``OpenStaticClassesTests - OpenSystemMathTwice - langversion:v4.6`` () = + CompilerAssert.TypeCheckWithErrorsAndOptions + [| "--langversion:4.6" |] + (baseModule + """ +module OpenSystemMathTwice = + + open System.Math + let x = Min(1.0, 2.0) + + open System.Math + let x2 = Min(2.0, 1.0)""") + [| + (FSharpErrorSeverity.Error, 39, (22,17,22,21), "The namespace 'Math' is not defined."); + (FSharpErrorSeverity.Error, 39, (23,13,23,16), "The value or constructor 'Min' is not defined.") + (FSharpErrorSeverity.Error, 39, (25,17,25,21), "The namespace 'Math' is not defined."); + (FSharpErrorSeverity.Error, 39, (26,14,26,17), "The value or constructor 'Min' is not defined.") + |] + + [] + let ``OpenStaticClassesTests - OpenSystemMathTwice - langversion:v4.7`` () = + CompilerAssert.TypeCheckWithErrorsAndOptions + [| "--langversion:4.7" |] + (baseModule + """ +module OpenSystemMathOnce = + + open System.Math + let x = Min(1.0, 2.0)""") + [| |] + + [] + let ``OpenStaticClassesTests - OpenMyMathOnce - langversion:v4.6`` () = + CompilerAssert.TypeCheckWithErrorsAndOptions + [| "--langversion:4.6" |] + (baseModule + """ +module OpenMyMathOnce = + + open MyMath + let x = Min(1.0, 2.0) + let x2 = Min(1, 2)""") + [| + (FSharpErrorSeverity.Error, 39, (22,10,22,16), "The namespace or module 'MyMath' is not defined."); + (FSharpErrorSeverity.Error, 39, (23,13,23,16), "The value or constructor 'Min' is not defined.") + (FSharpErrorSeverity.Error, 39, (24,14,24,17), "The value or constructor 'Min' is not defined.") + |] + + [] + let ``OpenStaticClassesTests - OpenMyMathOnce - langversion:v4.7`` () = + CompilerAssert.TypeCheckWithErrorsAndOptions + [| "--langversion:4.7" |] + (baseModule + """ +module OpenMyMathOnce = + + open MyMath + let x = Min(1.0, 2.0) + let x2 = Min(1, 2)""") + [| |] + + [] + let ``OpenStaticClassesTests - DontOpenAutoMath - langversion:v4.6`` () = + CompilerAssert.TypeCheckWithErrorsAndOptions + [| "--langversion:4.6" |] + (baseModule + """ +module DontOpenAutoMath = + + let x = AutoMin(1.0, 2.0) + let x2 = AutoMin(1, 2)""") + [| + (FSharpErrorSeverity.Error, 39, (22,13,22,20), "The value or constructor 'AutoMin' is not defined."); + (FSharpErrorSeverity.Error, 39, (23,14,23,21), "The value or constructor 'AutoMin' is not defined.") + |] + + [] + let ``OpenStaticClassesTests - DontOpenAutoMath - langversion:v4.7`` () = + CompilerAssert.TypeCheckWithErrorsAndOptions + [| "--langversion:4.7" |] + (baseModule + """ +module DontOpenAutoMath = + + let x = AutoMin(1.0, 2.0) + let x2 = AutoMin(1, 2)""") + [| |] + + [] + let ``OpenStaticClassesTests - OpenAutoMath - langversion:v4.6`` () = + CompilerAssert.TypeCheckWithErrorsAndOptions + [| "--langversion:4.6" |] + (baseModule + """ +module OpenAutoMath = + open AutoOpenMyMath + //open NotAllowedToOpen + + let x = AutoMin(1.0, 2.0) + let x2 = AutoMin(1, 2)""") + [| + (FSharpErrorSeverity.Error, 39, (21,10,21,24), "The namespace or module 'AutoOpenMyMath' is not defined."); + (FSharpErrorSeverity.Error, 39, (24,13,24,20), "The value or constructor 'AutoMin' is not defined.") + (FSharpErrorSeverity.Error, 39, (25,14,25,21), "The value or constructor 'AutoMin' is not defined.") + |] + + [] + let ``OpenStaticClassesTests - OpenAutoMath - langversion:v4.7`` () = + CompilerAssert.TypeCheckWithErrorsAndOptions + [| "--langversion:4.7" |] + (baseModule + """ +module OpenAutoMath = + open AutoOpenMyMath + //open NotAllowedToOpen + + let x = AutoMin(1.0, 2.0) + let x2 = AutoMin(1, 2)""") + [| |] diff --git a/tests/fsharp/FSharpSuite.Tests.fsproj b/tests/fsharp/FSharpSuite.Tests.fsproj index 8883e8aabeb..438f7c58b14 100644 --- a/tests/fsharp/FSharpSuite.Tests.fsproj +++ b/tests/fsharp/FSharpSuite.Tests.fsproj @@ -47,6 +47,7 @@ + diff --git a/tests/fsharp/core/longnames/version46/test.bsl b/tests/fsharp/core/longnames/version46/test.bsl deleted file mode 100644 index 70f110197bb..00000000000 --- a/tests/fsharp/core/longnames/version46/test.bsl +++ /dev/null @@ -1,39 +0,0 @@ - -test.fs(34,17,34,21): typecheck error FS0039: The namespace 'Math' is not defined. - -test.fs(35,13,35,16): typecheck error FS0039: The value or constructor 'Min' is not defined. Maybe you want one of the following: - min - sin - -test.fs(41,17,41,21): typecheck error FS0039: The namespace 'Math' is not defined. - -test.fs(42,13,42,16): typecheck error FS0039: The value or constructor 'Min' is not defined. Maybe you want one of the following: - min - sin - -test.fs(44,17,44,21): typecheck error FS0039: The namespace 'Math' is not defined. - -test.fs(45,14,45,17): typecheck error FS0039: The value or constructor 'Min' is not defined. Maybe you want one of the following: - min - sin - -test.fs(51,10,51,16): typecheck error FS0039: The namespace or module 'MyMath' is not defined. Maybe you want one of the following: - Math - -test.fs(52,13,52,16): typecheck error FS0039: The value or constructor 'Min' is not defined. Maybe you want one of the following: - min - sin - -test.fs(53,14,53,17): typecheck error FS0039: The value or constructor 'Min' is not defined. Maybe you want one of the following: - min - sin - -test.fs(60,13,60,20): typecheck error FS0039: The value or constructor 'AutoMin' is not defined. - -test.fs(61,14,61,21): typecheck error FS0039: The value or constructor 'AutoMin' is not defined. - -test.fs(67,10,67,24): typecheck error FS0039: The namespace or module 'AutoOpenMyMath' is not defined. - -test.fs(70,13,70,20): typecheck error FS0039: The value or constructor 'AutoMin' is not defined. - -test.fs(71,14,71,21): typecheck error FS0039: The value or constructor 'AutoMin' is not defined. diff --git a/tests/fsharp/core/longnames/version46/test.fs b/tests/fsharp/core/longnames/version46/test.fs deleted file mode 100644 index 8c41fdc81f0..00000000000 --- a/tests/fsharp/core/longnames/version46/test.fs +++ /dev/null @@ -1,84 +0,0 @@ -module Core_longnames -let failures = ref [] - -let report_failure (s : string) = - stderr.Write" NO: " - stderr.WriteLine s - failures := !failures @ [s] - -let test (s : string) b = - stderr.Write(s) - if b then stderr.WriteLine " OK" - else report_failure (s) - -let check s b1 b2 = test s (b1 = b2) - -(* Some test expressions *) -[] -type MyMath() = - static member Min(a: double, b: double) = System.Math.Min(a, b) - static member Min(a: int, b: int) = System.Math.Min(a, b) - -[] -type AutoOpenMyMath() = - static member AutoMin(a: double, b: double) = System.Math.Min(a, b) - static member AutoMin(a: int, b: int) = System.Math.Min(a, b) - -[] -type NotAllowedToOpen() = - static member QualifiedMin(a: double, b: double) = System.Math.Min(a, b) - static member QualifiedMin(a: int, b: int) = System.Math.Min(a, b) - -module OpenSystemMathOnce = - - open System.Math - let x = Min(1.0, 2.0) - test "vwejhweoiu" (x = 1.0) - - -module OpenSystemMathTwice = - - open System.Math - let x = Min(1.0, 2.0) - - open System.Math - let x2 = Min(2.0, 1.0) - - test "vwejhweoiu2" (x2 = 1.0) - -module OpenMyMathOnce = - - open MyMath - let x = Min(1.0, 2.0) - let x2 = Min(1, 2) - - test "vwejhweoiu2" (x = 1.0) - test "vwejhweoiu3" (x2 = 1) - -module DontOpenAutoMath = - - let x = AutoMin(1.0, 2.0) - let x2 = AutoMin(1, 2) - - test "vwejhweoiu2" (x = 1.0) - test "vwejhweoiu3" (x2 = 1) - -module OpenAutoMath = - open AutoOpenMyMath - //open NotAllowedToOpen - - let x = AutoMin(1.0, 2.0) - let x2 = AutoMin(1, 2) - - test "vwejhweoiu2" (x = 1.0) - test "vwejhweoiu3" (x2 = 1) - -let RUN() = - match !failures with - | [] -> - stdout.WriteLine "Test Passed" - System.IO.File.WriteAllText("test.ok","ok") - exit 0 - | _ -> - stdout.WriteLine "Test Failed" - exit 1 diff --git a/tests/fsharp/core/longnames/version47/test.fsx b/tests/fsharp/core/longnames/version47/test.fsx deleted file mode 100644 index 03702cb996b..00000000000 --- a/tests/fsharp/core/longnames/version47/test.fsx +++ /dev/null @@ -1,91 +0,0 @@ -// #Conformance #ObjectConstructors -#if TESTS_AS_APP -module Core_longnames -#endif -let failures = ref [] - -let report_failure (s : string) = - stderr.Write" NO: " - stderr.WriteLine s - failures := !failures @ [s] - -let test (s : string) b = - stderr.Write(s) - if b then stderr.WriteLine " OK" - else report_failure (s) - -let check s b1 b2 = test s (b1 = b2) - -(* Some test expressions *) -[] -type MyMath() = - static member Min(a: double, b: double) = System.Math.Min(a, b) - static member Min(a: int, b: int) = System.Math.Min(a, b) - -[] -type AutoOpenMyMath() = - static member AutoMin(a: double, b: double) = System.Math.Min(a, b) - static member AutoMin(a: int, b: int) = System.Math.Min(a, b) - -[] -type NotAllowedToOpen() = - static member QualifiedMin(a: double, b: double) = System.Math.Min(a, b) - static member QualifiedMin(a: int, b: int) = System.Math.Min(a, b) - -module OpenSystemMathOnce = - - open System.Math - let x = Min(1.0, 2.0) - test "vwejhweoiu" (x = 1.0) - - -module OpenSystemMathTwice = - - open System.Math - let x = Min(1.0, 2.0) - - open System.Math - let x2 = Min(2.0, 1.0) - - test "vwejhweoiu2" (x2 = 1.0) - -module OpenMyMathOnce = - - open MyMath - let x = Min(1.0, 2.0) - let x2 = Min(1, 2) - - test "vwejhweoiu2" (x = 1.0) - test "vwejhweoiu3" (x2 = 1) - -module DontOpenAutoMath = - - let x = AutoMin(1.0, 2.0) - let x2 = AutoMin(1, 2) - - test "vwejhweoiu2" (x = 1.0) - test "vwejhweoiu3" (x2 = 1) - -module OpenAutoMath = - open AutoOpenMyMath - //open NotAllowedToOpen - - let x = AutoMin(1.0, 2.0) - let x2 = AutoMin(1, 2) - - test "vwejhweoiu2" (x = 1.0) - test "vwejhweoiu3" (x2 = 1) - -#if TESTS_AS_APP -let RUN() = !failures -#else -let aa = - match !failures with - | [] -> - stdout.WriteLine "Test Passed" - System.IO.File.WriteAllText("test.ok","ok") - exit 0 - | _ -> - stdout.WriteLine "Test Failed" - exit 1 -#endif diff --git a/tests/fsharp/tests.fs b/tests/fsharp/tests.fs index fab4a5fa84b..94c46a1dced 100644 --- a/tests/fsharp/tests.fs +++ b/tests/fsharp/tests.fs @@ -1302,21 +1302,6 @@ module CoreTests = [] let ``longnames-FSI_BASIC`` () = singleTestBuildAndRun "core/longnames" FSI_BASIC -#if !FSHARP_SUITE_DRIVES_CORECLR_TESTS - [] - let ``longnames-version46`` () = - let cfg = testConfig "core/longnames/version46" - // For some reason this warning is off by default in the test framework but in this case we are testing for it - let cfg = { cfg with fsc_flags = cfg.fsc_flags.Replace("--nowarn:20", "") } - singleVersionedNegTest cfg "4.6" "test" -#endif - - [] - let ``longnames-version47-FSC_BASIC`` () = singleTestBuildAndRunVersion "core/longnames/version47" FSC_BASIC "preview" - - [] - let ``longnames-version47-FSI_BASIC`` () = singleTestBuildAndRunVersion "core/longnames/version47" FSI_BASIC "preview" - [] let ``math-numbersVS2008-FSC_BASIC`` () = singleTestBuildAndRun "core/math/numbersVS2008" FSC_BASIC